[
  {
    "path": ".babelrc",
    "content": "{\n  \"presets\": [[\"env\", { \"loose\": true} ], \"stage-2\"],\n  \"plugins\": [\"transform-export-extensions\", \"transform-react-jsx\"],\n  \"env\": {\n    \"development\": {\n      \"sourceMaps\": \"inline\"\n    }\n  }\n}\n"
  },
  {
    "path": ".circleci/config.yml",
    "content": "# Javascript Node CircleCI 2.0 configuration file\n#\n# Check https://circleci.com/docs/2.0/language-javascript/ for more details\n#\nversion: 2\njobs:\n  build:\n    docker:\n      # specify the version you desire here\n      - image: circleci/node:10\n\n      # Specify service dependencies here if necessary\n      # CircleCI maintains a library of pre-built images\n      # documented at https://circleci.com/docs/2.0/circleci-images/\n      # - image: circleci/mongo:3.4.4\n\n    working_directory: ~/repo\n\n    steps:\n      - checkout\n\n      # Download and cache dependencies\n      - restore_cache:\n          keys:\n            - v1-dependencies-{{ checksum \"package.json\" }}\n            # fallback to using the latest cache if no exact match is found\n            - v1-dependencies-\n\n      - run: yarn\n\n      - run: yarn bootstrap\n\n      - save_cache:\n          paths:\n            - node_modules\n          key: v1-dependencies-{{ checksum \"package.json\" }}\n\n      # Build and run tests\n      - run: yarn test\n\n      - run: yarn build\n"
  },
  {
    "path": ".eslintrc",
    "content": "{\n  \"rules\": {\n    \"strict\": 0,\n    \"indent\": [2, 2],\n    \"quotes\": [2, \"single\"],\n    \"linebreak-style\": [2, \"unix\"],\n    \"semi\": [2, \"always\"],\n    \"no-unused-vars\": [2, { \"ignoreRestSiblings\": true }],\n    \"react/jsx-uses-react\": 1,\n    \"react/jsx-uses-vars\": 1\n  },\n  \"ecmaFeatures\": {\n    \"restParams\": true,\n    \"destructuring\": true,\n    \"modules\": true,\n    \"jsx\": true\n  },\n  \"env\": {\n    \"es6\": true,\n    \"browser\": true,\n    \"node\": true,\n    \"jest\": true\n  },\n  \"parser\": \"babel-eslint\",\n  \"extends\": \"eslint:recommended\",\n  \"plugins\": [\"jsx-a11y\", \"react\", \"import\", \"jasmine\", \"flowtype\"]\n}\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/Feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\n\n---\n\n## Ensure you're using the latest version\nCodeSandbox examples might not always be using the latest version of Pose.\n\n## Add the package name to bug title\nFor instance, if this is a bug in Popmotion, write \"Popmotion: Name of bug\"\n\n## Describe the bug\nA clear and concise description of what the bug is.\n\n## How to reproduce\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n## Expected behaviour\nA clear and concise description of what you expected to happen.\n\n## Link to CodePen example (or similar)\n\n## Device information\nIn which environment are you reproducing the bug?\n - Device: [e.g. iPhone6]\n - OS: [e.g. iOS]\n - Browser [e.g. chrome, safari]\n - Version [e.g. 22]\n\n## Additional context\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules\n.DS_Store\nlib\npackages/site/.next\npackages/site/pages/api\npackages/site/pages/learn\npackages/site/pages/blog\npackages/site/pages/pose/api\npackages/site/pages/pose/examples\npackages/site/pages/pose/learn\npackages/site/pages/popcorn/api\npackages/site/data/content.json\npackages/site/data/menus.json\npackages/site/next.config.js\npackages/projection/cypress/screenshots/*\nplayground/public\nstorybook-static\ncoverage\n.vscode\ntmp\ndist\n*.log\nvideos"
  },
  {
    "path": ".prettierignore",
    "content": "*.md"
  },
  {
    "path": ".storybook/config.js",
    "content": "import { configure } from '@storybook/react';\n\nfunction loadStories() {\n  require('../playground');\n}\n\nconfigure(loadStories, module);\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Code of conduct\n\n![Be excellent to each other](https://user-images.githubusercontent.com/7850794/33840491-f80357bc-de8c-11e7-82fb-408f4aaeb24c.png)\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# How to Contribute\n\nThis guide will run through the types of contributions you can make and how to set the Popmotion repo up, ready for local development.\n\n- [Types of Contribution](#types-of-contribution)\n  - [Bugs](#bugs)\n  - [Features](#features)\n- [Development](#development)\n- [Codebase Overview](#codebase-overview)\n  - [Package Hierarchy](#package-hierarchy)\n- [Get in Touch](#get-in-touch)\n\n## Types of Contribution\n\n### Bugs\n\nOpen issues can be found on our [GitHub issues](https://github.com/Popmotion/popmotion/issues) page.\n\nIf you begin working on a bug, post your intent on the issue itself. This will prevent more than one person tackling a bug at once.\n\nIf the bug you wish to work on doesn't currently have an issue, make one and label it \"Bug\".\n\n### Features\n\nBefore adding any features, open a Feature Proposal as a [new issue](https://github.com/Popmotion/popmotion/issues).\n\nThis will let us talk through your proposed API and/or implementation before you spend time on it.\n\n## Development\n\nFollow these steps to get your code PR-ready:\n\n1. [Fork the Popmotion repo](https://github.com/Popmotion/popmotion).\n2. Clone your fork locally.\n3. Run `yarn`, `yarn bootstrap`, and `yarn build` in the repo root ([install Yarn](https://yarnpkg.com/lang/en/docs/install/#mac-stable) if necessary).\n4. Add your code and supporting tests.\n5. If this is a feature that requires doc changes, make as necessary.\n6. Update `CHANGELOG.md`.\n7. Ensure your changes build by running `yarn build` in the appropriate package directory(s).\n\n## Codebase Overview\n\nOther than [Stylefire](https://github.com/popmotion/stylefire) and [Framesync](https://github.com/popmotion/framesync), Popmotion is a monorepo. All Popmotion and Pose packages are contained in the [`packages` directory](https://github.com/Popmotion/popmotion/tree/master/packages).\n\nAll code and tests must be written in Typescript.\n\n### Package Hierarchy\n\nThis flowchart illustrates the Popmotion package dependency tree.\n\n**Note:** Currently, this illustration depicts `popmotion` as **not** dependent on `stylefire`, which isn't currently true. In `popmotion@9.0.0`, I'm considering removing Stylefire as a Popmotion dependency.\n\n![Popmotion package hierarchy flowchart](https://user-images.githubusercontent.com/7850794/41407730-3d921f26-6fc8-11e8-9de6-f1756572f6fc.png)\n\n## Get in Touch\n\nIf you need help, you can reach out to the [official Popmotion Twitter](https://twitter.com/popmotionjs) account.\n"
  },
  {
    "path": "README.md",
    "content": "# <a href=\"https://popmotion.io\"><img src=\"https://user-images.githubusercontent.com/7850794/90245722-80926e80-de33-11ea-9c39-ea6c5b344217.png\" height=\"52\" width=\"243\" alt=\"Popmotion\" /></a>\n\n### The animator's toolbox\n\n[![npm version](https://img.shields.io/npm/v/popmotion.svg?style=flat-square)](https://www.npmjs.com/package/popmotion)\n[![npm downloads](https://img.shields.io/npm/dm/popmotion.svg?style=flat-square)](https://www.npmjs.com/package/popmotion)\n[![Twitter Follow](https://img.shields.io/twitter/follow/popmotionjs.svg?style=social&label=Follow)](http://twitter.com/popmotionjs)\n\nPopmotion is:\n- **Powerful**: It supports keyframe and spring animations for numbers, colors and complex strings.\n- **Low level**: It's designed to be composable and portable into any JavaScript environment, with an eye on worklets in the future.\n- **Stable**: It's written in TypeScript and enjoys over 95% test coverage.\n- **Tiny**: `animate` is just ~4.5kb, and every function is individually importable.\n\n<!-- Documentation -->\n\n## Quick start\n\n```bash\nnpm install popmotion\n```\n\n```javascript\nimport { animate } from \"popmotion\"\n\nanimate({\n  from: 0,\n  to: 100,\n  onUpdate: latest => console.log(latest)\n})\n```\n\n## Animation\n\n### animate\n\n`animate` performs a keyframes or spring animation.\n\n```javascript\nimport { animate } from \"popmotion\"\n\nanimate({\n  from: 0, \n  to: 100,\n  onUpdate: latest => console.log(latest)\n})\n```\n\nIt can animate numbers:\n\n```javascript\nanimate({ from: 0, to: 100 })\n```\n\nOr strings of the same type:\n\n```javascript\nanimate({ from: \"0px\", to: \"100px\" })\nanimate({ from: \"#fff\", to: \"#000\" })\n```\n\nThe strings can be pretty complex, for instance box shadows or SVG path definitions. The only limitation is that the numbers and colors contained within must be in the same order:\n\n```javascript\nanimate({\n  from: \"0px 0px 0px rgba(0, 0, 0, 0)\",\n  to: \"10px 10px 0px rgba(0, 0, 0, 0.2)\"\n})\n```\n\n<!--\nArrays of the above:\n\n```javascript\nanimate({\n  from: [0, \"#fff\"],\n  to: [100, \"#000\"]\n})\n```\n\nAnd objects of the above:\n\n```javascript\nanimate({\n  from: { x: 0, backgroundColor: \"#fff\" },\n  to: { x: 100, backgroundColor: \"#000\" }\n})\n```\n-->\n\nThe type of animation performed will be automatically detected from the provided options, or can be chosen manually by defining `type` as `\"keyframes\"`, `\"spring\"` or `\"decay\"`.\n\n#### Options\n\nThese options can be set for **all animations**:\n\n##### from\n\nAn initial value to start the animation from.\n\nDefaults to `0`\n\n```javascript\nanimate({\n  from: \"linear-gradient(#e66465, #9198e5)\",\n  to: \"linear-gradient(#9198e5, #e66465)\"\n})\n```\n\n##### elapsed\n\nSets an initial elapsed time, in milliseconds. Set to a negative value for a delay.\n\n```javascript\nanimate({\n  to: 100,\n  elapsed: -300\n})\n```\n\n##### repeat\n\nThe number of times to repeat the animation. Set to `Infinity` to repeat forever.\n\n```javascript\nanimate({\n  to: 100,\n  repeat: 2\n})\n```\n\n##### repeatDelay\n\nThe duration, in milliseconds, to wait before repeating the animation.\n\n```javascript\nanimate({\n  to: 100,\n  repeat: 2,\n  repeatDelay: 200\n})\n```\n\n##### repeatType\n\nEither `\"loop\"`, `\"mirror\"` or `\"reverse\"`. Defaults to `\"loop\"`.\n\n- `\"loop\"`: Repeats the animation from `0`.\n- `\"mirror\":` Swaps the `from`/`to` values alternately.\n- `\"reverse\":` Reverses the animation alternately.\n\n```javascript\nanimate({\n  to: 100,\n  repeat: 2,\n  repeatType: \"reverse\"\n})\n```\n\n##### driver\n\nBy default, the animation will be driven by a `requestAnimationFrame` loop. `driver` can specify a different source.\n\nA `Driver` is a function that accepts the animations `update` function. This is a function that can be called with a time delta from the previous frame. The `Driver` must return a function that will be called when the animation is stopped.\n\n```javascript\nconst xrDriver = session => update => {\n  let latestRequestId = 0\n  let prevTimestamp = performance.now()\n  \n  const step = timestamp => {\n    const delta = timestamp - prevTimestamp\n    prevTimestamp = timestamp\n\n    update(delta)\n\n    latestRequestId = session.requestAnimationFrame(step)\n  }\n\n  let latestRequestId = session.requestAnimationFrame(step)\n\n  return () => session.cancelRequestAnimationFrame(latestRequestId)\n}\n\nanimate({\n  to: 100,\n  driver: xrDriver(xrSession)\n})\n```\n\n##### type\n\n`animate` will automatically detect the type of animation to use based on the options provided. But a specific type can be chosen manually by defining `type` as `\"keyframes\"`, `\"spring\"` or `\"decay\"`.\n\n```jsx\nanimate({\n  to: 100,\n  type: \"spring\"\n})\n```\n\n#### Lifecycle events\n\nThe following lifecycle events are available for **all animations**:\n\n##### onUpdate\n\nThis is called every frame the animation fires with the latest computed value.\n\n```javascript\nanimate({\n  to: 100,\n  onUpdate: latest => console.log(latest)\n})\n```\n\n##### onPlay\n\nThis is called when the animation starts. Currently this automatically when `animate` is called.\n\n```javascript\nanimate({\n  to: 100,\n  onPlay: () => {}\n})\n```\n\n##### onComplete\n\nThis is called when the animation successfully completes.\n\n```javascript\nanimate({\n  to: 100,\n  onComplete:() => {}\n})\n```\n\n##### onRepeat\n\nThis is called when an animation repeats.\n\n```javascript\nanimate({\n  to: 100,\n  repeat: 2,\n  onRepeat: () => {}\n})\n```\n\n##### onStop\n\nThis is called when the animation is stopped by the `stop` control.\n\n```javascript\nconst animation = animate({\n  to: 100,\n  onStop: () => {}\n})\n\nanimation.stop()\n```\n\n#### Keyframes options\n\nA keyframes animation is the default animation type and it can be defined either with a `from` and `to` option:\n\n```javascript\nanimate({ from: 0, to: 100 })\n```\n\nOr as a series of keyframes provided to the `to` option:\n\n```javascript\nanimate({ to: [0, 100, 200] })\n```\n\n##### to\n\nA single value to animate to, or an array of values to animate through.\n\n```javascript\nanimate({\n  to: [\"#0ff\", \"#f00\", \"#0f0\"]\n})\n```\n\nIf `to` is an array, any defined `from` will be ignored.\n\n##### duration\n\nThis defines the duration of the animation, in milliseconds.\n\n```javascript\nanimate({\n  to: 100,\n  duration: 300\n})\n```\n\n##### ease\n\nThis is an easing function, or array of functions, to use when easing between each keyframe.\n\n```javascript\nimport { animate, linear, easeInOut } from \"popmotion\"\n\nanimate({\n  to: 100,\n  ease: linear\n})\n\nanimate({\n  to: [\"#fff\", \"#000\", \"#f00\"],\n  ease: [linear, easeInOut]\n})\n```\n\nIf set as any array, the length of this array must be one shorter than the number of values being animated between.\n\n##### offset\n\nThis is an array of values between `0` and `1` that defines at which point throughout the animation each keyframe should be reached.\n\nThis array should be the same length as the number of defined keyframes.\n\n```javascript\nanimate({\n  to: [\"#fff\", \"#000\", \"#f00\"],\n  offset: [0, 0.2, 1]\n})\n```\n\n#### Spring options\n\nSprings are great for creating natural-feeling interfaces and dynamic interruptable animations.\n\nA spring animation will be used if any of the `stiffness`, `damping` or `mass` options are detected.\n\n**Note:** A spring simulation is inherently numerical so if it's given a color, array or object, it runs the animation from `0` to `100` and interpolates that to the given values. This strategy is likely to be tweaked before the official release so animations made this way may change in feel.\n\n##### to\n\nA single value to animate to.\n\n```javascript\nanimate({\n  to: 100,\n  type: \"spring\"\n})\n```\n\nIf `to` is an array, any defined `from` will be ignored.\n\n##### stiffness\n\nThis defines the stiffness of the spring. A higher stiffness will result in a snappier animation.\n\nDefaults to `100`\n\n```javascript\nanimate({\n  to: 100,\n  stiffness: 1000\n})\n```\n\n##### damping\n\nThis is the opposing force to `stiffness`. As you reduce this value, relative to `stiffness`, the spring will become bouncier and the animation will last longer. Likewise, higher relative values will have less bounciness and result in shorter animations.\n\nDefaults to `10`\n\n```javascript\nanimate({\n  to: 100,\n  damping: 50\n})\n```\n\n##### mass\n\nThis is the mass of the animating object. Heavier objects will take longer to speed up and slow down.\n\nDefaults to `1`.\n\n```javascript\nanimate({\n  to: 100,\n  mass: 2\n})\n```\n\n##### velocity\n\nThe initial velocity, in units per second, of the animation.\n\n```javascript\nanimate({\n  to: 100,\n  velocity: 1000\n})\n```\n\n##### duration\n\nThe duration of the spring, in milliseconds.\n\nWill be overridden by `stiffness`, `mass` or `damping`.\n\n```javascript\nanimate({\n  to: 100,\n  duration: 1000\n})\n```\n\n##### bounce\n\nThe bounciness of the spring, as a value between `0` and `1`, where `0` is no bounce.\n\nWill be overridden by `stiffness`, `mass` or `damping`.\n\n```javascript\nanimate({\n  to: 100,\n  bounce: 0.2\n})\n```\n\n##### restDelta\n\nThe distance from the animation target at which the animation can be considered complete. When both `restDelta` and `restSpeed` are met, the animation completes.\n\n```javascript\nanimate({\n  to: 100,\n  restDelta: 0.5\n})\n```\n\n##### restSpeed\n\nThe absolute velocity, in units per second, below which the animation can be considered complete. When both `restDelta` and `restSpeed` are met, the animation completes. Defaults to `10`.\n\n```javascript\nanimate({\n  to: 100,\n  restSpeed: 5\n})\n```\n\n#### Playback controls\n\n`animate` returns `PlaybackControls`, which can be used to control the playback of the animation.\n\nCurrently this only includes a `stop` method, but may expand with more.\n\n##### stop\n\nStops the animation.\n\n```javascript\nconst playback = animate({ from: 0, to: 100 })\nplayback.stop()\n```\n\n### inertia\n\nThe `inertia` animation is used to gradually decelerate a number. Think smartphone scroll momentum.\n\n#### Options\n\nIn addition to `animate`'s `from`, `onUpdate` and `onComplete` options, `inertia` also supports the following:\n\n##### velocity\n\nThe initial velocity, in units per second, of the animation.\n\n```javascript\ninertia({\n  from: 0,\n  velocity: 100\n})\n```\n\n##### power\n\nA constant with which to calculate a target value. Higher power = further target.\n\nDefaults to `0.8`.\n\n```javascript\ninertia({\n  from: 0,\n  power: 0.3\n})\n```\n\n##### timeConstant\n\nAdjusting the time constant will change the duration of the deceleration, thereby affecting its feel.\n\nDefaults to `350`.\n\n```javascript\ninertia({\n  from: 0,\n  velocity: 100,\n  timeConstant: 400\n})\n```\n\n##### modifyTarget\n\nA function that receives the calculated target and returns a new one. Useful for snapping the target to a grid.\n\n```javascript\nconst roundToNearest = target => v => Math.ceil(v / target) * target\n\ninertia({\n  from: 0,\n  velocity: 100,\n  modifyTarget: roundToNearest(100)\n})\n```\n\n##### min\n\nThe minimum value at which the animation will switch from gradual deceleration and use a spring animation to snap to this point.\n\n```javascript\ninertia({\n  from: 50,\n  velocity: -100,\n  min: 0\n})\n```\n\n##### max\n\nThe maximum value at which the animation will switch from gradual deceleration and use a spring animation to snap to this point.\n\n```javascript\ninertia({\n  from: 50,\n  velocity: 100,\n  max: 100\n})\n```\n\n##### bounceStiffness\n\nThis defines the stiffness of the spring when the animation hits either `min` or `max`. A higher stiffness will result in a snappier animation.\n\nDefaults to `500`\n\n```javascript\ninertia({\n  from: 0,\n  velocity: 100,\n  max: 50,\n  bounceStiffness: 1000\n})\n```\n\n##### bounceDamping\n\nThis is the opposing force to `bounceStiffness`. As you reduce this value, relative to `bounceStiffness`, the spring will become bouncier and the animation will last longer. Likewise, higher relative values will have less bounciness and result in shorter animations.\n\nDefaults to `10`\n\n```javascript\ninertia({\n  from: 0,\n  velocity: 100,\n  max: 50,\n  bounceDamping: 300\n})\n```\n\n##### restDelta\n\nThe distance from the animation target at which the animation can be considered complete.\n\n```javascript\ninertia({\n  from: 0,\n  velocity: 100,\n  restDelta: 0.5\n})\n```\n\n### Iterators\n\nPowering `animate` and `inertia` are the `keyframes`, `spring`, and `decay` [iterators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#The_iterator_protocol).\n\n```javascript\nimport { keyframes, spring, decay } from \"popmotion\";\n```\n\nIterators give you the ability to run an animation with a high degree of control. For example, [Framer](https://framer.com) uses the `spring` iterator to draw its animation editor visualiser by running it synchronously.\n\nEach can be initialised with the matching options above (`decay` with a subset of `inertia`'s options, excluding the `bounce-` options):\n\n```javascript\nconst animation = spring({\n  from: 0,\n  to: 100,\n  stiffness: 200\n})\n```\n\nWith the returned iterator, you can resolve the animation at a specific timestamp with its `next` method.\n\n```javascript\n// Resolve the animation at 200ms\nconst { value, done } = animation.next(200)\n```\n\n## Easing\n\nPopmotion includes a number of in-built easing functions, as well as factory functions to make entirely new ones.\n\n### Functions\n\nEach easing function can be imported like so:\n\n```javascript\nimport { linear } from \"popmotion\"\n```\n\nEach function accepts a progress value between `0` and `1`, and returns a new one:\n\n```javascript\nconst progress = 0.5\nconst easedProgress = easeInOut(progress)\n```\n\n - `linear`\n - `easeIn`\n - `easeInOut`\n - `easeOut`\n - `circIn`\n - `circInOut`\n - `circOut`\n - `backIn`\n - `backInOut`\n - `backOut`\n - `anticipate`\n - `bounceIn`\n - `bounceInOut`\n - `bounceOut`\n\n### Factories\n\n#### cubicBezier\n\n```javascript\nimport { cubicBezier } from \"popmotion\"\n\nconst easing = cubicBezier(0, .42, 0, 1)\n```\n\nNew cubic bezier definitions can be created in the [Framer](https://framer.com) animation editor and copy/pasted directly into this function.\n\n#### steps\n\n`steps` returns an easing function that will convert the animation into a discrete series of steps.\n\n```javascript\nimport { steps } from \"popmotion\"\n\nconst easing = steps(5)\n```\n\nIt optionally accepts a second parameter, either `\"start\"` or `\"end\"` (default)that decides whether the steps are aligned with the start or end of the animation.\n\n```javascript\nsteps(5, \"start\")\n```\n\n#### mirrorEasing\n\nMirrors an existing easing function. \n\n#### reverseEasing\n\nReverses an existing easing function. For instance, providing it `easeIn` would return an `easeOut`.\n\n```javascript\nimport { reverseEasing, linear } from \"popmotion\"\n\nconst reversed = reverseEasing(linear)\nreversed(1) // 0\nreversed(0.5) // 0.5\nreversed(0) // 1\n```\n\n#### createExpoIn\n\nCreates an easing function based on the exponent of the provided `power`. The higher the `power`, the stronger the easing.\n\n```javascript\nimport { createExpoIn } from \"popmotion\"\n\nconst expoIn = createExpoIn(4)\n```\n\nThe returned easing function is an ease in, which means it starts slow and finished fast. `mirrorEasing` and `reverseEasing` can be used to create ease in out, and ease out variations:\n\n```javascript\nconst expoIn = createExpoIn(4)\nconst expoOut = mirrorEasing(easeIn)\nconst expoInOut = reverseEasing(easeIn)\n```\n\n#### createBackIn\n\nCreates an easing function with an overshoot. It accepts a `power` value, the higher the `power` the stronger the overshoot.\n\n```javascript\nimport { createBackIn } from \"popmotion\"\n\nconst backIn = createBackIn(4)\n```\n\nThe returned easing function is an ease in, which means the overshoot happens at the start of the animation. `mirrorEasing` and `reverseEasing` can be used to create ease in out, and ease out variations:\n\n```javascript\nconst backIn = createBackIn(4)\nconst backOut = mirrorEasing(easeIn)\nconst backInOut = reverseEasing(easeIn)\n```\n\n#### createAnticipate\n\nCreates an easing that pulls back a little before animating out with an overshoot. The stronger the `power` the bigger the overshoot.\n\n```javascript\nimport { createAnticipate } from \"popmotion\"\n\nconst anticipate = createAnticipate(4)\n```\n\n## Utils\n\n#### angle\n\nReturns an angle between two points, in degrees.\n\n```javascript\nimport { angle } from \"popmotion\"\n\nangle(\n  { x: 0, y: 0 },\n  { x: 45, y: 100 }\n)\n```\n\n#### attract\n\n\n```javascript\nimport { attract } from \"popmotion\"\n\nattract(5, 10, 12)\n```\n\n#### attractExpo\n\n```javascript\nimport { attractExpo } from \"popmotion\"\n\nattractExpo(5, 10, 12)\n```\n\n#### clamp\n\nClamp a value to within the given range.\n\n```javascript\nimport { clamp } from \"popmotion\"\n\nconst min = 50\nconst max = 100\nclamp(min, max, 150) // 100\n```\n\n#### degreesToRadians\n\nConverts degrees to radians.\n\n```javascript\nimport { degreesToRadians } from \"popmotion\"\n\ndegreesToRadians(45) // 0.785...\n```\n\n#### distance\n\nReturns the distance between two numbers, two 2D points, or two 3D points.\n\n```javascript\nimport { distance } from \"popmotion\"\n\ndistance(10, 50)\ndistance({ x: 0, y: 0 }, { x: 45, y: 100 })\ndistance({ x: 0, y: 0, z: 100 }, { x: 45, y: 100, z: 0 })\n```\n\n#### interpolate\n\nCreates a function that will interpolate from an linear series of numbers, to a non-linear series of numbers, strings of the same numerical format, colours, or arrays/objects of those.\n\n```javascript\nimport { interpolate } from \"popmotion\"\n\nconst mapXToOpacity = interpolate(\n  [-100, 0, 100],\n  [0, 1, 0]\n)\nmapXToOpacity(-50) // 0.5\n\nconst mapProgressToValues = interpolate(\n  [0, 1],\n  [\n    { x: 0, color: \"#fff\" },\n    { x: 100, color: \"#000\" }\n  ]\n)\nmapProgressToValues(0.5) // { x: 50, color: \"#888\" }\n\nconst rescale = interpolate(\n  [0, 1],\n  [100, 200],\n  { clamp: false }\n)\nrescale(2) // 300\n```\n\n#### Options\n\n`interpolate` accepts an optional third argument, an object of options.\n\n- `clamp`: Clamps values to within given range. Defaults to `true`.\n- `ease`: An `Easing` function, or array of easing functions, to ease the interpolation of each segment.\n- `mixer`: A function that, when provided a `from` and `to` value, will return a new function that accepts a progress value between `0` and `1` to mix between those two values. For integration with libraries like Flubber.\n\n#### isPoint\n\nReturns `true` if the provided argument is a 2D point.\n\n```javascript\nimport { isPoint } from \"popmotion\"\n\nisPoint({ x: 0 }) // false\nisPoint({ x: 0, y: 0 }) // true\n```\n\n#### isPoint3D\n\nReturns `true` if the provided argument is a 3D point.\n\n```javascript\nimport { isPoint3D } from \"popmotion\"\n\nisPoint3D({ x: 0 }) // false\nisPoint3D({ x: 0, y: 0 }) // false\nisPoint3D({ x: 0, y: 0, z: 0 }) // true\n```\n\n#### mix\n\nWill mix between two values, given `progress` as a third argument.\n\n```javascript\nimport { mix } from \"popmotion\"\n\nmix(0, 100, 0.5) // 50\nmix(0, 100, 2) // 200\n```\n\n#### mixColor\n\nReturns a function that, when provided a `progress` value, will mix between two colors. Accepts hex, rgba and hsla colors.\n\n```javascript\nimport { mixColor } from \"popmotion\"\n\nmixColor(\"#000\", \"#fff\")(0.5) // \"rgba(125, 125, 125, 1)\"\n```\n\n#### mixComplex\n\nReturns a function that, when provided a `progress` value, will mix between two strings with the same order of numbers and colors.\n\n```javascript\nimport { mixComplex } from \"popmotion\"\n\nmixComplex(\"100px #fff\", \"0px #000\")(0.5) // \"50px rgba(125, 125, 125, 1)\"\n```\n\n#### pointFromVector\n\nGiven a point, angle in degrees, and distance, will return a new point.\n\n```javascript\nimport { pointFromVector } from \"popmotion\"\n\nconst point = { x: 0, y: 0 }\nconst angle = 45\nconst distance = 100\n\npointFromVector(point, angle, distance)\n```\n\n#### progress\n\nGiven a min and a max range, and a value, will return the `progress` of the value within the range as normalised to a `0`-`1` range.\n\n```javascript\nimport { progress } from \"popmotion\"\n\nconst min = 100\nconst max = 200\nprogress(min, max, 150) // 0.5\n```\n\n#### radiansToDegrees\n\nConverts radians to degrees.\n\n```javascript\nimport { radiansToDegrees } from \"popmotion\"\n\nradiansToDegrees(0.785) // 45\n```\n\n#### snap\n\nCreates a function that will snap numbers to the nearest in a provided array or to a regular interval.\n\n```javascript\nimport { snap } from \"popmotion\"\n\n// Snap to regular intervals\nconst snapTo = snap(45);\n\nsnapTo(1); // 0\nsnapTo(40); // 45\nsnapTo(50); // 45\nsnapTo(80); // 90\n\n// Snap to values in an array\nconst snapTo = snap([-100, -50, 100, 200]);\n\nsnapTo(-200); // -100\nsnapTo(-76); // -100\nsnapTo(-74); // -50\n```\n\n#### toDecimal\n\nRounds a number to a specific decimal place.\n\n```javascript\nimport { toDecimal } from \"popmotion\"\n\ntoDecimal(3.3333); // 3.33\ntoDecimal(6.6666, 1); // 6.67\n```\n\n#### velocityPerFrame\n\n```javascript\nimport { velocityPerFrame } from \"popmotion\"\n\nvelocityPerFrame(50, 16.7); // 0.835\n```\n\n#### velocityPerSecond\n\n```javascript\nimport { velocityPerSecond } from \"popmotion\"\n\nvelocityPerSecond(1, 16.7); // 59.880...\n```\n\n#### wrap\n\n```javascript\nimport { wrap } from \"popmotion\"\n\nwrap(0, 1, 0.5); // 0.5\nwrap(0, 1, 1.5); // 0.5\n```\n\n"
  },
  {
    "path": "lerna.json",
    "content": "{\n  \"lerna\": \"3.0.6\",\n  \"version\": \"independent\",\n  \"packages\": [\"packages/*\"],\n  \"npmClient\": \"yarn\",\n  \"useWorkspaces\": true\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"private\": true,\n  \"name\": \"popmotion-packages\",\n  \"author\": \"Matt Perry\",\n  \"homepage\": \"https://popmotion.io\",\n  \"scripts\": {\n    \"bootstrap\": \"lerna bootstrap\",\n    \"build\": \"cd packages/style-value-types && yarn build && cd ../framesync && yarn build && cd ../popmotion\",\n    \"playground\": \"start-storybook -s ./storybook-static -p 6006\",\n    \"build-playground\": \"build-storybook\",\n    \"clean\": \"lerna clean --yes && rm -rf node_modules\",\n    \"clear\": \"yarn clean && rm yarn.lock\",\n    \"test\": \"lerna run test\"\n  },\n  \"devDependencies\": {\n    \"@rollup/plugin-node-resolve\": \"^7.0.0\",\n    \"@rollup/plugin-replace\": \"^2.3.0\",\n    \"@storybook/react\": \"^3.2.13\",\n    \"babel-cli\": \"^6.26.0\",\n    \"babel-core\": \"^6.26.3\",\n    \"babel-eslint\": \"^5.0.4\",\n    \"babel-loader\": \"^6.0.1\",\n    \"babel-plugin-annotate-pure-calls\": \"^0.2.2\",\n    \"babel-plugin-root-import\": \"^5.1.0\",\n    \"babel-plugin-transform-export-extensions\": \"^6.4.0\",\n    \"babel-plugin-transform-react-constant-elements\": \"^6.9.1\",\n    \"babel-plugin-transform-react-jsx\": \"^6.24.1\",\n    \"babel-plugin-transform-react-remove-prop-types\": \"^0.2.6\",\n    \"babel-plugin-transform-runtime\": \"^6.23.0\",\n    \"babel-preset-env\": \"^1.6.1\",\n    \"babel-preset-react\": \"^6.16.0\",\n    \"babel-preset-stage-0\": \"^6.24.1\",\n    \"babel-preset-stage-2\": \"^6.17.0\",\n    \"babel-register\": \"^6.3.13\",\n    \"eslint\": \"^3.19.0\",\n    \"eslint-plugin-flowtype\": \"^2.30.0\",\n    \"eslint-plugin-import\": \"^2.2.0\",\n    \"eslint-plugin-jasmine\": \"2.2.0\",\n    \"eslint-plugin-jsx-a11y\": \"^4.0.0\",\n    \"eslint-plugin-react\": \"^6.10.0\",\n    \"estraverse-fb\": \"^1.3.1\",\n    \"husky\": \"^1.1.2\",\n    \"jest\": \"^24.0.0\",\n    \"jest-cli\": \"^24.0.0\",\n    \"jest-diff\": \"^24.0.0\",\n    \"lerna\": \"^3.0.6\",\n    \"lint-staged\": \"^7.3.0\",\n    \"prettier\": \"^2.1.0\",\n    \"react\": \"^16.8.6\",\n    \"react-dom\": \"^16.8.6\",\n    \"rollup\": \"^2.40.0\",\n    \"rollup-plugin-terser\": \"^7.0.2\",\n    \"rollup-plugin-typescript2\": \"^0.30.0\",\n    \"string-replace-loader\": \"^1.3.0\",\n    \"styled-components\": \"^4.1.1\",\n    \"ts-jest\": \"^22.4.6\",\n    \"tslint\": \"^5.11.0\",\n    \"tslint-config-prettier\": \"^1.15.0\",\n    \"tslint-react\": \"^4.1.0\",\n    \"typescript\": \"^4.7\",\n    \"webpack\": \"^3.0.0\"\n  },\n  \"workspaces\": {\n    \"packages\": [\n      \"packages/*\"\n    ],\n    \"nohoist\": [\n      \"gatsby\"\n    ]\n  },\n  \"resolutions\": {\n    \"jest\": \"24.2.0-alpha.0\",\n    \"babel-jest\": \"^22.4.3\",\n    \"tslib\": \"2.4.0\"\n  },\n  \"prettier\": {\n    \"parser\": \"typescript\",\n    \"singleQuote\": true\n  },\n  \"husky\": {\n    \"hooks\": {\n      \"pre-commit\": \"lint-staged\"\n    }\n  },\n  \"lint-staged\": {\n    \"*.{ts,tsx}\": [\n      \"prettier --write\",\n      \"git add\"\n    ]\n  },\n  \"version\": \"10.1.0\"\n}\n"
  },
  {
    "path": "packages/blend-tweens/blend-tweens.js",
    "content": "import tween from './tween';\nimport { linear } from '../inc/easing';\nimport { getProgressFromValue, getValueFromProgress } from '../inc/calc';\nimport { flow, clamp, bezier } from '../inc/transformers';\n\nconst clampProgress = clamp(0, 1);\n\nfunction calcValueAtTime(from, to, duration, elapsed, ease) {\n  const progressAtTime = ease(clampProgress(getProgressFromValue(0, duration, elapsed)));\n  return getValueFromProgress(from, to, progressAtTime);\n}\n\nexport default ({ from, to, onUpdate, accuracy = 60, ...props }) => {\n  // Get tween properties\n  const a = from;\n  const b = to;\n  const aCurrent = a.get();\n  const aDuration = a.getProp('duration');\n  const bDuration = b.getProp('duration');\n  const aEase = a.getProp('ease');\n  const bEase = b.getProp('ease');\n  const aFrom = a.getProp('from');\n  const bFrom = b.getProp('from');\n  const aTo = a.getProp('to');\n  const bTo = b.getProp('to');\n\n  // Analyse tweens\n  const overlapDuration = Math.min(aDuration - a.getElapsed(), bDuration);\n  const bValueAtTweenOverlapComplete = calcValueAtTime(bFrom, bTo, bDuration, overlapDuration, bEase);\n  const bStartsHigherThanA = (bFrom > aCurrent);\n  const bEndsHigherThanA = (bValueAtTweenOverlapComplete > aTo);\n\n  // Blend points are defined as [t = time, v = valueAtTime]\n  // P1\n  // The start of the tween blend\n  const P1 = aCurrent;\n  const blendPoints = [P1];\n\n  // Find P2\n  // The possible intersection point between the two tweens\n  const tweensIntersect = (bStartsHigherThanA !== bEndsHigherThanA);\n  if (tweensIntersect) {\n    let timestep = overlapDuration / accuracy;\n\n    for (let i = 0; i < accuracy; i++) {\n      const runningTime = i * timestep;\n\n      const aValueAtTime = calcValueAtTime(aFrom, aTo, aDuration, a.elapsed + runningTime, aEase);\n      const bValueAtTime = calcValueAtTime(bFrom, bTo, bDuration, b.elapsed + runningTime, bEase);\n\n      const hasIntersected = (\n        (bStartsHigherThanA && aValueAtTime > bValueAtTime) ||\n        (!bStartsHigherThanA && aValueAtTime < bValueAtTime)\n      );\n\n      if (hasIntersected) {\n        const P2 = bValueAtTime;\n        blendPoints.push(P2);\n        break;\n      }\n    }\n  }\n\n  // P3\n  // The points the two tweens stop overlapping\n  const P3 = bValueAtTweenOverlapComplete;\n  blendPoints.push(P3);\n\n  // Push the end state of b tween as final control point\n  const P4 = bTo;\n  blendPoints.push(P4);\n\n  return tween({\n    ...props,\n    duration: bDuration,\n    ease: linear,\n    onUpdate: flow(\n      bezier(blendPoints),\n      onUpdate\n    )\n  });\n};\n"
  },
  {
    "path": "packages/blend-tweens/cross-fade.js",
    "content": "import Action from './';\nimport tween from './tween';\nimport { linear } from '../inc/easing';\nimport { getValueFromProgress } from '../inc/calc';\n\nclass CrossFade extends Action {\n  static defaultProps = {\n    ease: linear\n  }\n\n  onStart() {\n    const { duration, ease, fader } = this.props;\n\n    this.fader = fader || tween({\n      to: 1,\n      duration,\n      ease\n    }).start();\n  }\n\n  update() {\n    const { from, to } = this.props;\n    const balance = this.fader.get();\n    const latestFromValue = from.get();\n    const latestToValue = to.get();\n    return getValueFromProgress(latestFromValue, latestToValue, balance);\n  }\n}\n\nexport default (props) => new CrossFade(props);\n"
  },
  {
    "path": "packages/framesync/CHANGELOG.md",
    "content": "# Changelog\n\nFramesync adheres to [Semantic Versioning](http://semver.org/).\n\n## [6.1.2] 2022-08-15\n\n### Update\n\n-   `tslib` and `typescript`.\n\n## [6.1.1] 2022-08-10\n\n### Update\n\n-   Adding `types` to `exports` field.\n\n## [6.1.0] 2021-11-24\n\n### Update\n\n-   Updating `tslib`.\n\n## [6.0.1] 2021-10-22\n\n### Fixed\n\n-   Fixing bug where `flushSync` being called from an existing process would boot keep-alive processes off the thread.\n\n## [6.0.0] 2021-09-23\n\n### Fixed\n\n-   Fixing `exports` and `module` in `package.json`. This will break (unsupported) direct file imports.\n\n## [5.3.0] 2021-03-30\n\n### Added\n\n-   Adding `flushSync` API for manual flushing of job queues.\n\n## [5.2.3] 2021-03-19\n\n### Fixed\n\n-   Fixing `main` entry point.\n\n## [5.2.2] 2021-03-19\n\n### Fixed\n\n-   Fixing `main` entry point.\n\n## [5.2.1] 2021-03-19\n\n### Added\n\n-   Adding `exports` to `package.json`.\n\n### Updated\n\n-   `tslib` to latest.\n\n## [5.2.0] 2021-03-01\n\n### Fixed\n\n-   Unbundling ES code to facilitate code-splitting in Webpack.\n\n## [5.1.0] 2021-02-22\n\n### Fixed\n\n-   Adding polyfill for `performance.now` for better compatibility with Node environments.\n\n## [5.0.0] 2021-01-01\n\n### Changed\n\n-   Using `performance.now` to measure polyfilled elapsed time.\n\n## [4.1.0] 2020-8-24\n\n### Added\n\n-   `preRender` step.\n\n## [4.0.2] 2019-02-05\n\n### Fixed\n\n-   Fixing rescheduling keepAlive method.\n\n## [4.0.1] 2018-09-24\n\n### Changed\n\n-   Updated README.\n\n## [4.0.0] 2018-09-24\n\n### Changed\n\n-   New API.\n    -   `onFrameUpdate(callback, immediate)` -> `sync.update(callback, keepAlive, immediate)`\n    -   `cancelOnFrameUpdate(callback)` -> `cancelSync.update(callback)`\n\n### Added\n\n-   `keepAlive` parameter.\n\n## [3.1.9] 2018-05-16\n\n### Fixed\n\n-   Fixing Rollup config.\n\n## [3.1.8] 2018-05-13\n\n### Added\n\n-   Rollup support for outputting ES modules and UMD bundles.\n\n## [3.1.7] 2018-01-04\n\n### Fixed\n\n-   Fixing illegal invocation errors.\n\n## [3.1.6] 2018-01-04\n\n### Changed\n\n-   Using previous frame duration as default duration (for instance between active cycles).\n\n## [3.1.5] 2018-01-04\n\n### Changed\n\n-   Cleaning polyfill.\n\n## [3.1.4] 2018-01-04\n\n### Changed\n\n-   Max permitted time elapsed is now 40ms to permit 30fps max.\n-   When `startRenderLoop` is fired, and the loop is not active, we set a new `currentTime`.\n\n## [3.1.3] 2017-11-08\n\n### Fixed\n\n-   Actually pointing to new declaration file.\n\n## [3.1.2] 2017-11-08\n\n### Fixed\n\n-   Pointing to new declaration file.\n\n## [3.1.1] 2017-11-08\n\n### Fixed\n\n-   Automatically exporting declaration file.\n\n## [3.1.0] 2017-11-08\n\n### Added\n\n-   Added optional `true` flag to `schedule`. This will schedule a job to run at the end of the current frame step.\n\n## [3.0.0] 2017-08-28\n\n-   `currentFrameTimestamp` becomes `currentFrameTime` for symmetry with `currentTime`.\n\n## [2.0.1] 2017-08-26\n\n### Added\n\n-   Changelog and Readme.\n\n## [2.0.0] 2017-08-26\n\n### Added\n\n-   First publish.\n"
  },
  {
    "path": "packages/framesync/LICENSE.md",
    "content": "MIT License\n\nCopyright © 2019 Framer BV\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/framesync/README.md",
    "content": "# Framesync\n\nA tiny frame scheduler for performantly batching reads, updates and renders.\n\nSegregating actions that read and write to the DOM will avoid [layout thrashing](https://developers.google.com/web/fundamentals/performance/rendering/avoid-large-complex-layouts-and-layout-thrashing).\n\nIt's also a way of ensuring order of execution across a frame. For instance, [Framer Motion](https://github.com/framer/motion) batches animations on the `update` step, and renders on the `render` step, allowing independent animation of `transform` properties.\n\n## Install\n\n```bash\nnpm install framesync\n```\n\n## Usage\n\nFramesync splits a frame into discrete `read`, `update`, `preRender`, `render` and `postRender` steps.\n\n### Scheduling functions\n\nFunctions can be scheduled to different parts of the render loop with `sync`.\n\n```javascript\nimport sync from 'framesync';\n```\n\nIt provides four functions, one for scheduling a function to run on each part of the frame:\n\n```javascript\nsync.update(() => {});\n```\n\n### Frame data\n\nEach function is provided data about the current frame:\n\n```javascript\nsync.update(({ delta, timestamp }) => {});\n```\n\n- `delta`: Time since last frame (in milliseconds)\n- `timestamp`: Timestamp of the current frame.\n\nThis object is recycled across frames, so values should be destructured if intended to be used asynchronously.\n\n### Keep alive\n\nWe can run a function as an ongoing process by passing `true` as the second parameter:\n\n```javascript\nlet count = 0;\n\nsync.update(() => count++, true);\n```\n\nThis will keep the process running until it's actively cancelled.\n\n### Run immediately\n\nThe third parameter, `immediate`, can be used to sync a function on the **current frame step**.\n\nBy default, Framesync will schedule functions to run the next time that frame step is fired:\n\n```javascript\nsync.update(({ timestamp }) => {\n  // The following function will run on the subsequent frame:\n  sync.update((frame) => frame.timestamp !== timestamp);\n});\n```\n\nBy setting `immediate` to `true`, we can add this at the end of the current step:\n\n```javascript\nsync.update(({ timestamp }) => {\n  // The following function will run on the **current** frame:\n  sync.update(\n    (frame) => frame.timestamp === timestamp,\n    false,\n    true\n  );\n});\n```\n\n### Cancelling\n\nSynced processes can be cancelled with the `cancelSync` function:\n\n```javascript\nimport sync, { cancelSync } from 'framesync';\n\nlet count = 0;\n\nconst process = sync.render(() => {\n  count++;\n  if (count >= 10) cancelSync.render(process);\n}, true);\n```\n"
  },
  {
    "path": "packages/framesync/package.json",
    "content": "{\n    \"name\": \"framesync\",\n    \"license\": \"MIT\",\n    \"version\": \"6.1.2\",\n    \"description\": \"A frame-synced render loop for JavaScript\",\n    \"author\": \"Matt Perry\",\n    \"homepage\": \"https://popmotion.io\",\n    \"main\": \"dist/framesync.cjs.js\",\n    \"types\": \"lib/index.d.ts\",\n    \"module\": \"dist/es/index.mjs\",\n    \"jsnext:main\": \"dist/es/index.mjs\",\n    \"unpkg\": \"./dist/framesync.min.js\",\n    \"exports\": {\n        \".\": {\n            \"types\": \"./lib/index.d.ts\",\n            \"import\": \"./dist/es/index.mjs\",\n            \"require\": \"./dist/framesync.cjs.js\",\n            \"default\": \"./dist/framesync.cjs.js\"\n        },\n        \"./package.json\": \"./package.json\"\n    },\n    \"scripts\": {\n        \"build\": \"tsc -p . && rollup -c && yarn measure\",\n        \"watch\": \"rollup -c -w\",\n        \"lint\": \"tslint -c tslint.json 'src/**/*.{ts}'\",\n        \"test\": \"jest\",\n        \"measure\": \"gzip -c dist/framesync.min.js | wc -c\",\n        \"prepublishOnly\": \"npm run test && npm run build\"\n    },\n    \"files\": [\n        \"lib\",\n        \"dist\"\n    ],\n    \"repository\": {\n        \"type\": \"git\",\n        \"url\": \"git+https://github.com/Popmotion/popmotion.git\"\n    },\n    \"keywords\": [\n        \"animation\",\n        \"raf\"\n    ],\n    \"bugs\": {\n        \"url\": \"https://github.com/Popmotion/popmotion/issues\"\n    },\n    \"jest\": {\n        \"moduleFileExtensions\": [\n            \"ts\",\n            \"js\"\n        ],\n        \"transform\": {\n            \"\\\\.(ts)$\": \"../../../node_modules/ts-jest/preprocessor.js\"\n        },\n        \"testRegex\": \"/_tests/.*\\\\.(ts|js)$\",\n        \"rootDir\": \"src\"\n    },\n    \"prettier\": {\n        \"printWidth\": 80,\n        \"tabWidth\": 4,\n        \"semi\": false,\n        \"trailingComma\": \"es5\"\n    },\n    \"dependencies\": {\n        \"tslib\": \"2.4.0\"\n    }\n}\n"
  },
  {
    "path": "packages/framesync/rollup.config.js",
    "content": "import generateConfig from '../../rollup-generate-config';\nimport pkg from './package.json';\n\nexport default generateConfig(pkg);\n"
  },
  {
    "path": "packages/framesync/src/_tests/test.ts",
    "content": "import sync, { cancelSync, flushSync } from \"../\"\nimport { onNextFrame } from \"../on-next-frame\"\n\ndescribe(\"onNextFrame\", () => {\n    it(\"fires callback on following frame\", () => {\n        return new Promise((resolve) => onNextFrame(resolve))\n    })\n})\n\ndescribe(\"sync\", () => {\n    it(\"fires callbacks in the correct order\", () => {\n        return new Promise<void>((resolve, reject) => {\n            const order: number[] = []\n\n            sync.read(() => order.push(0))\n            sync.update(() => order.push(1))\n            sync.preRender(() => order.push(2))\n            sync.render(() => order.push(3))\n            sync.postRender(() => {\n                order.push(4)\n                if (\n                    order[0] === 0 &&\n                    order[1] === 1 &&\n                    order[2] === 2 &&\n                    order[3] === 3 &&\n                    order[4] === 4\n                ) {\n                    resolve()\n                } else {\n                    reject(order)\n                }\n            })\n        })\n    })\n\n    it(\"cancels callbacks\", () => {\n        return new Promise<void>((resolve, reject) => {\n            let hasFired = false\n\n            const process = sync.render(() => (hasFired = true))\n\n            sync.update(() => cancelSync.render(process))\n\n            sync.postRender(() => (hasFired ? reject(hasFired) : resolve()))\n        })\n    })\n\n    it(\"fires callback on current frame if scheduled with `true` within the same step\", () => {\n        return new Promise<number | string | void>((resolve, reject) => {\n            let v = 0\n\n            sync.update(({ timestamp: prevTimestamp }) => {\n                v++\n                sync.update(\n                    ({ timestamp }) => {\n                        v++\n                        if (timestamp !== prevTimestamp) {\n                            reject(`${timestamp} ${prevTimestamp}`)\n                        }\n                    },\n                    false,\n                    true\n                )\n            })\n\n            sync.render(() => (v === 2 ? resolve() : reject(v)))\n        })\n    })\n\n    it(\"fires callback on next frame if scheduled with `true` outside the same step\", () => {\n        return new Promise((resolve: Function, reject: Function) => {\n            let v = 0\n\n            sync.update(() => v++)\n            sync.update(() => v++, false, true)\n            sync.render(() => (v === 2 ? resolve() : reject()))\n        })\n    })\n\n    it(\"uses default elapsed time if first fire\", () => {\n        return new Promise((resolve: Function, reject: Function) => {\n            sync.update(({ delta: defaultElapsed }) => {\n                setTimeout(\n                    () =>\n                        sync.update(({ delta }) =>\n                            delta === defaultElapsed\n                                ? resolve()\n                                : reject(defaultElapsed, delta)\n                        ),\n                    50\n                )\n            })\n        })\n    })\n\n    it(\"correctly cancels\", () => {\n        return new Promise<void>((resolve, reject) => {\n            const callback = () => reject()\n\n            sync.read(() => cancelSync.update(callback))\n            sync.update(callback)\n            sync.render(() => resolve())\n        })\n    })\n\n    it(\"correctly keeps alive\", () => {\n        return new Promise<void>((resolve) => {\n            let v = 0\n            sync.update(() => v++, true)\n            sync.render(() => v === 2 && resolve(), true)\n        })\n    })\n\n    it(\"correctly cancels a keepAlive process\", () => {\n        return new Promise<number[] | void>((resolve, reject) => {\n            let updateCount = 0\n            let renderCount = 0\n\n            const update = sync.update(() => {\n                updateCount++\n\n                if (updateCount === 4) cancelSync.update(update)\n            }, true)\n\n            sync.render(() => {\n                renderCount++\n\n                if (renderCount === 6) {\n                    if (renderCount !== updateCount) {\n                        resolve()\n                    } else {\n                        reject([renderCount, updateCount])\n                    }\n                }\n            }, true)\n        })\n    })\n\n    it(\"correctly keeps alive after a flush\", async () => {\n        const promise = new Promise<boolean>((resolve) => {\n            let v = 0\n\n            sync.update(() => {\n                if (v === 2) flushSync.update()\n            }, true)\n\n            sync.update(() => {\n                v++\n                if (v > 6) resolve(true)\n            }, true)\n        })\n        flushSync.update()\n        return expect(promise).resolves.toBe(true)\n    })\n})\n"
  },
  {
    "path": "packages/framesync/src/create-render-step.ts",
    "content": "import { Step, Process } from \"./types\"\n\nexport function createRenderStep(runNextFrame: () => void): Step {\n    /**\n     * We create and reuse two arrays, one to queue jobs for the current frame\n     * and one for the next. We reuse to avoid triggering GC after x frames.\n     */\n    let toRun: Process[] = []\n    let toRunNextFrame: Process[] = []\n\n    /**\n     *\n     */\n    let numToRun = 0\n\n    /**\n     * Track whether we're currently processing jobs in this step. This way\n     * we can decide whether to schedule new jobs for this frame or next.\n     */\n    let isProcessing = false\n\n    let flushNextFrame = false\n\n    /**\n     * A set of processes which were marked keepAlive when scheduled.\n     */\n    const toKeepAlive = new WeakSet<Process>()\n\n    const step: Step = {\n        /**\n         * Schedule a process to run on the next frame.\n         */\n        schedule: (callback, keepAlive = false, immediate = false) => {\n            const addToCurrentFrame = immediate && isProcessing\n            const buffer = addToCurrentFrame ? toRun : toRunNextFrame\n\n            if (keepAlive) toKeepAlive.add(callback)\n\n            // If the buffer doesn't already contain this callback, add it\n            if (buffer.indexOf(callback) === -1) {\n                buffer.push(callback)\n\n                // If we're adding it to the currently running buffer, update its measured size\n                if (addToCurrentFrame && isProcessing) numToRun = toRun.length\n            }\n\n            return callback\n        },\n\n        /**\n         * Cancel the provided callback from running on the next frame.\n         */\n        cancel: (callback) => {\n            const index = toRunNextFrame.indexOf(callback)\n            if (index !== -1) toRunNextFrame.splice(index, 1)\n\n            toKeepAlive.delete(callback)\n        },\n\n        /**\n         * Execute all schedule callbacks.\n         */\n        process: (frameData) => {\n            /**\n             * If we're already processing we've probably been triggered by a flushSync\n             * inside an existing process. Instead of executing, mark flushNextFrame\n             * as true and ensure we flush the following frame at the end of this one.\n             */\n            if (isProcessing) {\n                flushNextFrame = true\n                return\n            }\n\n            isProcessing = true\n\n            // Swap this frame and the next to avoid GC\n            ;[toRun, toRunNextFrame] = [toRunNextFrame, toRun]\n\n            // Clear the next frame list\n            toRunNextFrame.length = 0\n\n            // Execute this frame\n            numToRun = toRun.length\n\n            if (numToRun) {\n                for (let i = 0; i < numToRun; i++) {\n                    const callback = toRun[i]\n\n                    callback(frameData)\n\n                    if (toKeepAlive.has(callback)) {\n                        step.schedule(callback)\n                        runNextFrame()\n                    }\n                }\n            }\n\n            isProcessing = false\n\n            if (flushNextFrame) {\n                flushNextFrame = false\n                step.process(frameData)\n            }\n        },\n    }\n\n    return step\n}\n"
  },
  {
    "path": "packages/framesync/src/index.ts",
    "content": "import { onNextFrame, defaultTimestep } from \"./on-next-frame\"\nimport { createRenderStep } from \"./create-render-step\"\nimport {\n    Process,\n    StepId,\n    FrameData,\n    CancelSync,\n    FlushSync,\n    Sync,\n    Steps,\n} from \"./types\"\n\nconst maxElapsed = 40\nlet useDefaultElapsed = true\nlet runNextFrame = false\nlet isProcessing = false\n\nconst frame = {\n    delta: 0,\n    timestamp: 0,\n}\n\nconst stepsOrder: StepId[] = [\n    \"read\",\n    \"update\",\n    \"preRender\",\n    \"render\",\n    \"postRender\",\n]\n\nconst steps = stepsOrder.reduce((acc, key) => {\n    acc[key] = createRenderStep(() => (runNextFrame = true))\n    return acc\n}, {} as Steps)\n\nconst sync = stepsOrder.reduce((acc, key) => {\n    const step = steps[key]\n    acc[key] = (process: Process, keepAlive = false, immediate = false) => {\n        if (!runNextFrame) startLoop()\n        return step.schedule(process, keepAlive, immediate)\n    }\n    return acc\n}, {} as Sync)\n\nconst cancelSync = stepsOrder.reduce((acc, key) => {\n    acc[key] = steps[key].cancel\n    return acc\n}, {} as CancelSync)\n\nconst flushSync = stepsOrder.reduce((acc, key) => {\n    acc[key] = () => steps[key].process(frame)\n    return acc\n}, {} as FlushSync)\n\nconst processStep = (stepId: StepId) => steps[stepId].process(frame)\n\nconst processFrame = (timestamp: number) => {\n    runNextFrame = false\n\n    frame.delta = useDefaultElapsed\n        ? defaultTimestep\n        : Math.max(Math.min(timestamp - frame.timestamp, maxElapsed), 1)\n\n    frame.timestamp = timestamp\n\n    isProcessing = true\n    stepsOrder.forEach(processStep)\n    isProcessing = false\n\n    if (runNextFrame) {\n        useDefaultElapsed = false\n        onNextFrame(processFrame)\n    }\n}\n\nconst startLoop = () => {\n    runNextFrame = true\n    useDefaultElapsed = true\n\n    if (!isProcessing) onNextFrame(processFrame)\n}\n\nconst getFrameData = () => frame\n\nexport default sync\nexport { cancelSync, flushSync, getFrameData, FrameData, Process }\n"
  },
  {
    "path": "packages/framesync/src/on-next-frame.ts",
    "content": "/*\n  Detect and load appropriate clock setting for the execution environment\n */\nexport const defaultTimestep = (1 / 60) * 1000\n\nconst getCurrentTime =\n    typeof performance !== \"undefined\"\n        ? () => performance.now()\n        : () => Date.now()\n\nexport const onNextFrame =\n    typeof window !== \"undefined\"\n        ? (callback: FrameRequestCallback) =>\n              window.requestAnimationFrame(callback)\n        : (callback: FrameRequestCallback) =>\n              setTimeout(() => callback(getCurrentTime()), defaultTimestep)\n"
  },
  {
    "path": "packages/framesync/src/types.ts",
    "content": "export type FrameData = {\n    delta: number\n    timestamp: number\n}\n\nexport type Process = (data: FrameData) => void\n\nexport type Schedule = (\n    process: Process,\n    keepAlive?: boolean,\n    immediate?: boolean\n) => Process\n\nexport interface Step {\n    schedule: Schedule\n    cancel: (process: Process) => void\n    process: (frame: FrameData) => void\n}\n\nexport type StepId =\n    | \"read\"\n    | \"update\"\n    | \"postUpdate\"\n    | \"preRender\"\n    | \"render\"\n    | \"postRender\"\n\nexport type Sync = {\n    [key in StepId]: Schedule\n}\n\nexport type Steps = {\n    [key in StepId]: Step\n}\n\nexport type CancelSync = {\n    [key in StepId]: (process: Process) => void\n}\n\nexport type FlushSync = {\n    [key in StepId]: () => void\n}\n"
  },
  {
    "path": "packages/framesync/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"declarationDir\": \"lib\",\n    \"rootDir\": \"src\",\n    \"outDir\": \"lib\"\n  },\n  \"include\": [\"src/**/*\"]\n}"
  },
  {
    "path": "packages/popcorn/docs/api/utilities/angle.md",
    "content": "---\ntitle: angle\ndescription: Returns the angle between two 2D points.\ncategory: functions\n---\n\n# `angle`\n\n`angle` returns the angle between two 2D points, in degrees.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { angle } from '@popmotion/popcorn';\n```\n\n## Usage\n\n```javascript\nangle(\n  { x: 0, y: 0 },\n  { x: 0, y: 20 }\n) // 90\n```\n\n## Types\n\n```typescript\ntype Point2D = {\n  x: number;\n  y: number;\n}\n\nangle(a: Point2D, b: Point2D): number\n```\n"
  },
  {
    "path": "packages/popcorn/docs/api/utilities/apply-offset.md",
    "content": "---\ntitle: applyOffset\ndescription: Creates a function that measures the offset of incoming values and applies it to an initial value.\ncategory: functions\n---\n\n# `applyOffset`\n\n`applyOffset` creates a function that measures the offset of any given value from the initial `from`, and applies it to `to`.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { applyOffset } from '@popmotion/popcorn';\n```\n\n## Usage\n\n`applyOffset` can be used both when you know the initial value you want to measure the offset from, and when you don't.\n\n### With an initial value\n\n```javascript\napplyOffset(100, 0)(101) // 1\n```\n\n### Without an initial value\n\nIf we don't provide an initial `from` value, the first value we call the returned function will be considered `from` and apply `to` with a delta of `0`.\n\n```javascript\nconst applyPointerMovementToX = applyOffset(x);\n\napplyPointerMovement(100); // x\napplyPointerMovement(120); // x + 20\n```\n\n## Types\n\n```typescript\napplyOffset(from: number, to: number): (v: number) => number;\napplyOffset(to: number): (v: number) => number;\n```\n"
  },
  {
    "path": "packages/popcorn/docs/api/utilities/clamp.md",
    "content": "---\ntitle: clamp\ndescription: Restricts a number to within the defined range.\ncategory: functions\n---\n\n# `clamp`\n\n`clamp` restricts a number to within the given range.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { clamp } from '@popmotion/popcorn';\n```\n\n## Usage\n\nClamp accepts a `min` and `max` value.\n\nIf a third value is provided, it returns a number that is clamped within that given range:\n\n```javascript\nclamp(100, 200, 99); // 100\nclamp(100, 200, 201); // 200\n```\n\nIf only a range is provided, it returns a function. When that function is provided a number, it returns a new number that is clamped within the defined range:\n\n```javascript\nconst restrictOpacity = clamp(0, 1);\nrestrictOpacity(-1); // 0\n```\n\n## Types\n\n```typescript\nclamp(min: number, max: number, v: number) => number;\nclamp(min: number, max: number) => (v: number) => number;\n```\n"
  },
  {
    "path": "packages/popcorn/docs/api/utilities/conditional.md",
    "content": "---\ntitle: conditional\ndescription: Creates a function that conditionally transforms provided values.\ncategory: functions\n---\n\n# `conditional`\n\n`conditional` is used to create a function that will conditionally transform incoming values.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { conditional } from '@popmotion/popcorn';\n```\n\n## Usage\n\n`conditional` is provided a `check` and `transform` function, and returns a new function.\n\nThis function, when provided a value, will provide it to `check`.\n\nIf `check` returns `true`, it will return the value as transformed by `transform`. If `false`, it will return the value.\n\n```javascript\nconst conditionallyDouble = conditional(\n  v => v > 5,\n  v => v * 2\n);\n\nconditionallyDouble(4); // 4\nconditionallyDouble(6); // 12\n```\n\n## Types\n\n```typescript\ntype Check = (v: any) => boolean;\ntype Apply = (v: any) => any;\n\nconditional(check: Check, transform: Apply) => (v: any) => any;\n```\n"
  },
  {
    "path": "packages/popcorn/docs/api/utilities/degreesToRadians.md",
    "content": "---\ntitle: degreesToRadians\ndescription: Converts degrees to radians.\ncategory: functions\n---\n\n# `degreesToRadians`\n\n`degreesToRadians` converts degrees to radians.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { degreesToRadians } from '@popmotion/popcorn';\n```\n\n## Usage\n\n```javascript\ndegreesToRadians(45) // 0.785...\n```\n\n## Types\n\n```typescript\ndegreesToRadians(degrees: number): number;\n```\n"
  },
  {
    "path": "packages/popcorn/docs/api/utilities/distance.md",
    "content": "---\ntitle: distance\ndescription: Calculate the distance between two n-dimensional points.\ncategory: functions\n---\n\n# `distance`\n\n`distance` calculates the distance between two n-dimensional points.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { distance } from '@popmotion/popcorn';\n```\n\n## Usage\n\n### 1D points\n\nProvide two numbers to measure the distance between them.\n\n```javascript\ndistance(-100, 100); // 200\n```\n\n### 2D and 3D points\n\nProvide two `Point` values, with `x`, `y` and optionally `z` numbers, to measure the distance between them.\n\n```javascript\ndistance(\n  { x: 0, y: 0, z: 0 },\n  { x: 0, y: 0, z: 10 }\n); // 10\n```\n\n## Types\n\n```typescript\ntype Point = {\n  x: number;\n  y: number;\n  z?: number;\n}\n\ndistance(a: number | Point, b: number | Point): number\n```\n"
  },
  {
    "path": "packages/popcorn/docs/api/utilities/interpolate.md",
    "content": "---\ntitle: interpolate\ndescription: Map from a series of numbers to a range of numbers, colors or strings.\ncategory: functions\n---\n\n# `interpolate`\n\nUsing an `input` range of sequential numbers, and an `output` range of numbers or colors, `interpolate` will create a function that maps a number from the `input` range to the `output`.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { interpolate } from '@popmotion/popcorn';\n```\n\n## Usage\n\n`interpolate` can map from an `input` array of sequential numbers like this:\n\n```javascript\n[0, 1, 2]\n```\n\nTo an array of **either** numbers, colors, or strings containing one or more numbers or colors.\n\nThe two arrays must be the **same length**.\n\n### Numbers\n\n```javascript\nconst mapper = interpolate(\n  [-100, -50, 50, 100],\n  [0, 1, 1, 0]\n);\n\nmapper(-200); // 0\nmapper(-75); // 0.5\nmapper(50); // 1\n```\n\n### Colors\n\n`interpolate` can map to hex, RGB(A) or HSL(A) colors.\n\n**Note:** Hex numbers will be output as RGBA.\n\n```javascript\nconst mapper = interpolate(\n  [0, 50, 100],\n  ['#fff', '#f00', '#000']\n);\n\nmapper(25); // rgba(255, 128, 128, 1)\nmapper(50); // rgba(255, 0, 0, 1)\nmapper(75); // rgba(128, 0, 0, 1)\n```\n\n### Strings\n\n`interpolate` can maps to complex value types that include multiple numbers or colors.\n\nEvery string in the `output` range must be of the exact same format.\n\n```javascript\nconst mapper = interpolate(\n  [0, 1, 2],\n  [\n    '20px, rgba(0, 0, 0, 0)',\n    '10px, rgba(255, 255, 255, 1)',\n    '40px, rgba(100, 100, 100, 0.5)'\n  ]\n);\n\nmapper(0.5); // '15px, rgba(128, 128, 128, 0.5)'\n```\n\n## Options\n\n`interpolate` takes an optional third argument, options. This is an object that may contain the following configurations:\n\n### Clamp\n\nClamp values to within the provided ranges.\n\nDefault: `true`.\n\n```javascript\ninterpolate([0, 1], [0, 100])(2) // 100\ninterpolate([0, 1], [0, 100], { clamp: false })(2) // 200\n```\n\n### Ease\n\nDefault: `linear`\n\nAn easing function, or list of easing functions, to apply to every transition.\n\nIf defined as an array, it must be the `input.length - 1`, as it applies to the transitions **between** the defined values.\n\n```javascript\ninterpolate(\n  [0, 100, 200],\n  ['#fff', '#500', '#000'],\n  { ease: [linear, easeOut] }\n)\n```\n\n## Types\n\n```typescript\ninterpolate(\n  input: number[],\n  output: string[] | number[],\n  options: InterpolateOptions\n): string | number;\n\ntype InterpolateOptions = {\n  clamp?: boolean = true,\n  ease?: Easing | Easing[]\n};\n\ntype Easing = v => v;\n```\n"
  },
  {
    "path": "packages/popcorn/docs/api/utilities/is-point-3d.md",
    "content": "---\ntitle: isPoint3D\ndescription: Test a value for x, y and z properties.\ncategory: functions\n---\n\n# `isPoint3D`\n\nReturns `true` if the provided value has an `x`, `y` and `z` properties.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { isPoint3D } from '@popmotion/popcorn';\n```\n\n## Usage\n\n```javascript\nisPoint3D(0); // false\nisPoint3D({ x: 0, y: 0 }); // false\nisPoint3D({ x: 0, y: 0, z: 0 }); // true\n```\n\n## Types\n\n```typescript\nisPoint3D(v: any): boolean;\n```\n"
  },
  {
    "path": "packages/popcorn/docs/api/utilities/is-point.md",
    "content": "---\ntitle: isPoint\ndescription: Test a value for an `x` and `y` property.\ncategory: functions\n---\n\n# `isPoint`\n\nReturns `true` if the provided value has an `x` and `y` property.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { isPoint } from '@popmotion/popcorn';\n```\n\n## Usage\n\n```javascript\nisPoint(0); // false\nisPoint({ x: 0, y: 0 }); // true\n```\n\n## Types\n\n```typescript\nisPoint(v: any): boolean;\n```\n"
  },
  {
    "path": "packages/popcorn/docs/api/utilities/mix-array.md",
    "content": "---\ntitle: mixArray\ndescription: Creates a function that can interpolate between two arrays of matching value types.\ncategory: functions\n---\n\n# `mixArray`\n\n`mixArray` creates a function that can interpolate between two arrays of matching value types.\n\nValues can be any number, color, or a string containing multiple numbers or colors.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { mixArray } from '@popmotion/popcorn';\n```\n\n## Usage\n\n`mixArray` accepts two arrays, a `from` and `to` array.\n\nThe values in each can be:\n\n- Number\n- Hex color\n- RGB(A) color\n- HSL(A) color\n- String containing one or more of the above types\n\nIt returns a function that can be used to interpolate between the two arrays using a value between `0-1`.\n\n```javascript\nconst mixer = mixArray(\n  [0, '60px', '#fff'],\n  [100, '-60px', '#000']\n)\n\nmixer(0.5) // [50, '0px', 'rgba(128, 128, 128, 1)']\n```\n\n**Note:** Colors, if defined as hex values, will be returned as rgba.\n\n## Types\n\n```typescript\ntype Mixable = Array<Number | String>;\n\nmixArray(from: Mixable, to: Mixable): Mixable\n```\n"
  },
  {
    "path": "packages/popcorn/docs/api/utilities/mix-color.md",
    "content": "---\ntitle: mixColor\ndescription: Creates a function that can interpolate between two hex, rgba or hsla colors.\ncategory: functions\n---\n\n# `mixColor`\n\n`mixColor` creates a function that can interpolate between two hex, rgba or hsla colors.\n\nHex and RGBA colors are mixed using linear color space blending which avoids brightness dips. [Learn more](https://www.youtube.com/watch?v=LKnqECcg6Gw).\n\n<TOC />\n\n## Import\n\n```javascript\nimport { mixColor } from '@popmotion/popcorn';\n```\n\n## Usage\n\n`mixColor` accepts two colors, either hex/RGB(A), or HSL(A).\n\nIt returns a function that can be used to interpolate between the two colors using a value between `0-1`.\n\n```javascript\nconst mixer = mixColor('#f00', '#0f0');\n\nmixer(0.5) // 'rgba(128, 128, 0, 1)'\n```\n\n**Note:** Colors, if defined as hex values, will be returned as rgba.\n\n## Types\n\n```typescript\nmixColor(from: string, to: string) => (v: number) => string\n```\n"
  },
  {
    "path": "packages/popcorn/docs/api/utilities/mix-complex.md",
    "content": "---\ntitle: mixComplex\ndescription: Creates a function that can mix between two strings that contain one or more numbers and/or colors.\ncategory: functions\n---\n\n# `mixComplex`\n\nCreates a function that can mix between two strings that contain one or more numbers and/or colors.\n\nHex and RGBA colors are mixed using linear color space blending which avoids brightness dips. [Learn more](https://www.youtube.com/watch?v=LKnqECcg6Gw).\n\n<TOC />\n\n## Import\n\n```javascript\nimport { mixComplex } from '@popmotion/popcorn';\n```\n\n## Usage\n\n`mixComplex` can be used to animate any string in which numbers or colors are detected.\n\nAs simple as single unit types:\n\n```javascript\nconst mixer = mixComplex('10px', '20px');\n\nmixer(0.5); // '15px'\n```\n\nOr strings containing multiple numbers and colors:\n\n```javascript\nconst mixer = mixComplex(\n  '0px 0px auto rgba(0, 0, 0, 0)',\n  '5px 5px auto rgba(0, 0, 0, 0.5)'\n);\n\nmixer(0.5); // '2.5px 2.5px auto rgba(0, 0, 0, 0.25)'\n```\n\n**Note:** The non-numerical portions of the string must be the same in both `from` and `to` values.\n\n## Types\n\n```typescript\nmixColor(from: string, to: string) => (v: number) => string\n```\n"
  },
  {
    "path": "packages/popcorn/docs/api/utilities/mix.md",
    "content": "---\ntitle: mix\ndescription: Mixes between two numbers\ncategory: functions\n---\n\n# `mix`\n\n`mix` can interpolate between two numbers.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { mix } from '@popmotion/popcorn';\n```\n\n## Usage\n\n```javascript\nmix(0, 100, 0.5); // 50\nmix(0, 100, 1); // 100\nmix(0, 100, 2); // 200\n```\n\n## Types\n\n```typescript\nmix(from: number, to: number, progress: number): number\n```\n"
  },
  {
    "path": "packages/popcorn/docs/api/utilities/pipe.md",
    "content": "---\ntitle: pipe\ndescription: Left-to-right function composition.\ncategory: functions\n---\n\n# `pipe`\n\n`pipe` composes a new function out of a series of provided functions.\n\nWhen this new function is provided a value, it will run this value through the provided functions in left-to-right order.\n\nThis provides a way of composing logic from simpler, reusable functions.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { pipe } from '@popmotion/popcorn';\n```\n\n## Usage\n\n```javascript\nconst double = v => v * 2;\nconst add = toAdd => v => v + toAdd;\nconst negative = v => -v;\n\nconst func = pipe(double, add(1), negative);\n\nfunc(2); // -5\n```\n\n## Types\n\n```typescript\npipe(...funcs: Function): Function\n```\n"
  },
  {
    "path": "packages/popcorn/docs/api/utilities/point-from-vector.md",
    "content": "---\ntitle: pointFromVector\ndescription: Calculates a point, given a point and vector (angle and distance)\ncategory: functions\n---\n\n# `pointFromVector`\n\n`pointFromVector` takes a point, an angle (in degrees), and a distance, and returns a new point.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { pointFromVector } from '@popmotion/popcorn';\n```\n\n## Usage\n\n```javascript\npointFromVector({ x: 0, y: 0 }, 45, 100);\n// { x: 70.710..., y: 70.710... }\n```\n\n## Types\n\n```typescript\ntype Point = {\n  x :number;\n  y: number;\n};\n\npointFromVector(origin: Point, angle: number, distance: number): Point\n```\n"
  },
  {
    "path": "packages/popcorn/docs/api/utilities/progress.md",
    "content": "---\ntitle: progress\ndescription: Calculates the progress of a value between in a given range.\ncategory: functions\n---\n\n# `progress`\n\n`progress` returns the progress of a value in a given range.\n\nProgress is represented as a number between `0` and `1`, but is unclamped.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { progress } from '@popmotion/popcorn';\n```\n\n## Usage\n\n```javascript\nprogress(100, -100, 50); // 0.25\nprogress(100, -100, -300); // 2\n```\n\n## Types\n\n```typescript\nprogress(from: number, to: number, value: number): number\n```\n"
  },
  {
    "path": "packages/popcorn/docs/api/utilities/radians-to-degrees.md",
    "content": "---\ntitle: radiansToDegrees\ndescription: Converts radians to degrees.\ncategory: functions\n---\n\n# `radiansToDegrees`\n\n`radiansToDegrees` converts radian units to degrees.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { radiansToDegrees } from '@popmotion/popcorn';\n```\n\n## Usage\n\n```javascript\nradiansToDegrees(0.7); // 40.107...\n```\n\n## Types\n\n```typescript\nradiansToDegrees(radians: number): number\n```\n"
  },
  {
    "path": "packages/popcorn/docs/api/utilities/smooth-frame.md",
    "content": "---\ntitle: smoothFrame\ndescription: Smooth the motion from one value to a new value over a single frame.\ncategory: functions\n---\n\n# `smoothFrame`\n\n`smoothFrame` can be used to smooth motion across a single frame, independent of framerate.\n\nThis can be used, for example, to implement input smoothing.\n\n**Note:** To smooth motion using a [Framesync](/api/framesync)-based process or library like [Popmotion Pure](/pure), the [smooth](/popcorn/api/smooth) utility offers a simpler API.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { smoothFrame } from '@popmotion/popcorn';\n```\n\n## Usage\n\n`smoothFrame` accepts `prevValue`, `nextValue`, `frameDuration` and `strength` arguments.\n\nIt will return a value that smooths the difference between `prevValue` and `nextValue` according to the `frameDuration` and `strength` properties.\n\n```javascript\nsmoothFrame(0, 100, 16.7, 50); // 33.4\n```\n\nHigher `strength` values impose stronger smoothing, with values the same as or less than the `frameDuration` imposing no smoothing.\n\n## Types\n\n```typescript\nsmoothFrame(\n  prev: number,\n  next: number,\n  frameDuration: number,\n  strength: number\n): number\n```\n"
  },
  {
    "path": "packages/popcorn/docs/api/utilities/smooth.md",
    "content": "---\ntitle: smooth\ndescription: Creates a function that will smooth values across frames when used with Framesync or Popmotion Pure.\ncategory: functions\n---\n\n# `smooth`\n\n`smooth` creates a function that can smooth a value across frames when paired with a [Framesync](/api/framesync) process or [Popmotion Pure](/pure) animation.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { smooth } from '@popmotion/popcorn';\n```\n\n## Usage\n\n### With Framesync\n\n```javascript\nimport { smooth } from '@popmotion/popcorn';\nimport sync from 'framesync';\n\nlet counter = 0;\nconst smoother = smooth(100);\n\nsync.update(() => {\n  counter = counter + 10;\n  counter = smoother(counter);\n}, true);\n```\n\n### With Popmotion Pure\n\nAs Popmotion Pure runs on Framesync, we can use it to smooth animations.\n\nFor instance, here's an example of input smoothing:\n\n```javascript\nimport { smooth } from '@popmotion/popcorn';\nimport { pointer } from 'popmotion';\n\npointer({ x: 100 })\n  .pipe(\n    ({ x }) => x,\n    smooth(50)\n  )\n  .start(v => console.log(v))\n```\n\n## Types\n\n```typescript\nsmoothFrame(strength: number) => (v: number) => number\n```\n"
  },
  {
    "path": "packages/popcorn/docs/api/utilities/snap.md",
    "content": "---\ntitle: snap\ndescription: Creates a function that will snap provided values to regular intervals, or to numbers provided as an array.\ncategory: functions\n---\n\n# `snap`\n\n`snap` creates a function that will snap numbers to the nearest in a provided array or to a regular interval. \n\n<TOC />\n\n## Import\n\n```javascript\nimport { snap } from '@popmotion/popcorn';\n```\n\n## Usage\n\n### Snap to regular interval\n\n```javascript\nconst snapTo = snap(45);\n\nsnapTo(1); // 0\nsnapTo(40); // 45\nsnapTo(50); // 45\nsnapTo(80); // 90\n```\n\n### Snap to values in an array\n\n```javascript\nconst snapTo = snap([-100, -50, 100, 200]);\n\nsnapTo(-200); // -100\nsnapTo(-76); // -100\nsnapTo(-74); // -50\n```\n\n## Types\n\n```typescript\nsnap(interval: number) => (v: number) => number;\nsnap(intervals: number[]) => (v: number) => number;\n```\n"
  },
  {
    "path": "packages/popcorn/docs/api/utilities/to-decimal.md",
    "content": "---\ntitle: toDecimal\ndescription: Rounds a number to a specified decimal place.\ncategory: functions\n---\n\n# `toDecimal`\n\n`toDecimal` will round a number to the specified decimal place.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { toDecimal } from '@popmotion/popcorn';\n```\n\n## Usage\n\n```javascript\ntoDecimal(3.3333); // 3.33\ntoDecimal(6.6666, 1); // 6.67\n```\n\n## Types\n\n```typescript\ntoDecimal(value: number, precision: number = 2): number\n```\n"
  },
  {
    "path": "packages/popcorn/docs/api/utilities/velocity-per-frame.md",
    "content": "---\ntitle: velocityPerFrame\ndescription: Converts velocity per second into velocity per frame.\ncategory: functions\n---\n\n# `velocityPerFrame`\n\n`velocityPerFrame` converts velocity per second into velocity per frame. It is framerate-independent.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { velocityPerFrame } from '@popmotion/popcorn';\n```\n\n## Usage\n\nIf a number is changing at a velocity of `50` per second, we can find its velocity per frame by passing `50` along with the duration of the previous frame (in milliseconds):\n\n```javascript\nvelocityPerFrame(50, 16.7); // 0.835\n```\n\n## Types\n\n```typescript\nsnap(velocityPerSecond: number, frameDuration: number): number;\n```\n"
  },
  {
    "path": "packages/popcorn/docs/api/utilities/velocity-per-second.md",
    "content": "---\ntitle: velocityPerSecond\ndescription: Converts velocity per frame into velocity per second.\ncategory: functions\n---\n\n# `velocityPerSecond`\n\n`velocityPerSecond` converts velocity per frame into velocity per second. It is framerate-independent.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { velocityPerSecond } from '@popmotion/popcorn';\n```\n\n## Usage\n\nIf a number changed, for instanced, by an increase of `1` in the previous frame, we can calculate its velocity per second by passing `velocityPerSecond` `1` along with the duration of the previous frame (in milliseconds):\n\n```javascript\nvelocityPerSecond(1, 16.7); // 59.880...\n```\n\n## Types\n\n```typescript\nvelocityPerSecond(velocityPerFrame: number, frameDuration: number): number;\n```\n"
  },
  {
    "path": "packages/popcorn/docs/api/utilities/wrap.md",
    "content": "---\ntitle: wrap\ndescription: Wraps a number when it breaches the defined range.\ncategory: functions\n---\n\n# `wrap`\n\nWraps a number when it breaches the defined range.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { wrap } from '@popmotion/popcorn';\n```\n\n## Usage\n\n`wrap` accepts a range, defined as a `min` and `max`.\n\nWhen a third number is provided:\n\n- If it lies within the range, it is returned.\n- If it lies outside the range, it is wrapped back around:\n\n```javascript\nwrap(0, 1, 0.5); // 0.5\nwrap(0, 1, 1.5); // 0.5\n```\n\n## Types\n\n```typescript\nwrap(min: number, max: number, v: number): number;\nwrap(min: number, max: number) => (v: number) => number;\n```\n"
  },
  {
    "path": "packages/popmotion/.gitignore",
    "content": "/*.js\n/*.js.map\n*.d.ts\n/coverage\n"
  },
  {
    "path": "packages/popmotion/.npmignore",
    "content": "*.md\n*.map\ndocs\nwebpack.config.js\ntmp\ncoverage\nsrc"
  },
  {
    "path": "packages/popmotion/CHANGELOG.md",
    "content": "# Changelog\n\nPopmotion adheres to [Semantic Versioning](http://semver.org/).\n\n## [11.0.5] 2022-08-15\n\n### Update\n\n-   `tslib` and `typescript`.\n\n## [11.0.4] 2022-08-10\n\n### Update\n\n-   Adding `types` to `exports` field.\n\n## [11.0.3] 2021-12-03\n\n### Update\n\n-   Dynamic `restDelta` for smoother springs at low values.\n\n## [11.0.2] 2021-12-02\n\n### Update\n\n-   Locking dependencies.\n\n## [11.0.1] 2021-12-02\n\n### Update\n\n-   Locking dependencies.\n\n## [11.0.0] 2021-11-03\n\n### Changed\n\n-   `mixColor` always outputs RGB, even when mixing HSLA.\n\n### Added\n\n-   Animate HSLA with linear color mix.\n-   Animate between HSLA, RGBA and Hex with `mixColor`.\n\n## [10.0.2] 2021-10-22\n\n### Fixed\n\n-   Updating `framesync`.\n\n## [10.0.0] 2021-09-23\n\n### Fixed\n\n-   Fixing `exports` and `module` in `package.json`. This will break (unsupported) direct file imports.\n\n### [9.4.1] 2021-09-21\n\n### Changed\n\n-   Change `mixComplex` \"too complex\" error to warning, and allowing instant interpolation when `p > 0`.\n\n### [9.4.0] 2021-06-18\n\n### Added\n\n-   `onStop` to `inertia`.\n\n### [9.3.6] 2021-05-11\n\n### Fix\n\n-   Correctly end spring animation if provided `bounce` without `duration`.\n\n### [9.3.5] 2021-03-30\n\n### Update\n\n-   Updating `framesync`.\n\n### [9.3.4] 2021-03-19\n\n### Fixed\n\n-   Updating `style-value-types`.\n\n### [9.3.3] 2021-03-19\n\n### Fixed\n\n-   Fixing `main` entry point.\n\n### [9.3.2] 2021-03-19\n\n### Added\n\n-   Adding `exports` to `package.json`.\n\n### Updated\n\n-   `tslib` to latest.\n\n### [9.3.1] 2021-03-02\n\n### Fixed\n\n-   Scheduling of first animation frame was previously set to `immediate`, leading to double animations for animations stopped/started within the same frame.\n\n### [9.3.0] 2021-03-01\n\n### Fixed\n\n-   Unbundling ES code to facilitate code-splitting in Webpack.\n\n## [9.2.1] 2020-02-22\n\n### Update\n\n-   Upgrading to `style-value-types@4.0.3`.\n\n## [9.2.0] 2020-02-22\n\n### Update\n\n-   Upgrading to `framesync@5.1.0` for better Node compatibility.\n\n## [9.1.0] 2020-01-08\n\n### Update\n\n-   Support for hex alpha in `mixColor`.\n\n## [9.0.2] 2020-12-18\n\n### Update\n\n-   Dependency updates.\n\n## [9.0.1] 2020-12-01\n\n### Fixed\n\n-   If `offsets` is a different length to `values`, rather than throw an error we now just generate default offsets.\n\n## [9.0.0] 2020-10-24\n\n-   Full API revamp, see documentation.\n\n## [8.7.5] 2020-09-03\n\n### Fixed\n\n-   Refreshing published bundle.\n\n## [8.7.2] 2020-04-28\n\n### Fixed\n\n-   Decay and inertia correctly start motion at from prop when using modifyTarget\n-   Decay and inertia no longer round target calculation\n-   Inertia calls modifyTarget even with zero-velocity\n\n### Changed\n\n-   Inertia implementation refinements\n\n## [8.7.1] 2019-11-14\n\n### Upgrade\n\n-   Upgraded to Typescript 3.7.\n\n## [8.7.0] 2019-06-25\n\n### Added\n\n-   `repeatDelay` prop to `tween`.\n\n## [8.6.10] 2019-05-09\n\n### Fixed\n\n-   Fixing undefined action creator. (https://github.com/Popmotion/popmotion/issues/794)[#794]\n\n## [8.6.9] 2019-05-01\n\n### Update\n\n-   Dependencies.\n\n## [8.6.8] 2019-04-01\n\n### Update\n\n-   `@popmotion/popcorn@0.3.6`\n\n## [8.6.7] 2019-04-01\n\n### Fixed\n\n-   Making `inertia.complete` call conditional on there not being a subsequent animation. (https://github.com/Popmotion/popmotion/pull/763)[#763]\n\n## [8.6.6] 2019-04-01\n\n### Update\n\n-   `@popmotion/popcorn@0.3.5`\n\n## [8.6.5] 2019-04-01\n\n### Update\n\n-   Changing the behaviour of `inertia` to always spring back if the initial value is out of bounds. On multi-axis `inertia` animations it used to be possible that both values are out of bounds and only one was travelling towards its bound - this led to a situation where one animation used a spring and the other used decay.\n\n## [8.6.4] 2019-03-12\n\n### Upgrade\n\n-   Upgrading `style-value-types@3.1.0`.\n\n## [8.6.3] 2019-02-21\n\n### Fixed\n\n-   Correctly integrating remainder of `elapsed` in yoyo tweens to ensure multiple concurrent tweens stay in sync.\n\n## [8.6.2] 2019-01-28\n\n### Updated\n\n-   Tightened type definitions for TransitionMapFactory [#714](https://github.com/Popmotion/popmotion/pull/714)\n\n## [8.6.1] 2019-01-23\n\n### Added\n\n-   Adding `bounceStiffness`, `bounceDamping`, `restDelta`, `timeConstant` and `power` options to `inertia`.\n\n## [8.6.0] 2019-01-16\n\n### Added\n\n-   `inertia` animation.\n\n## [8.5.5] 2018-12-28\n\n### Update\n\n-   `stylefire@8.3.4`\n\n## [8.5.4] 2018-12-10\n\n### Fixed\n\n-   When a subscriber is added, only that subscriber is fired with the latest value.\n\n## [8.5.3] 2018-11-20\n\n### Fixed\n\n-   Ensuring `.stop()` is part of `ColdSubscription` definition.\n\n## [8.5.2] 2018-11-16\n\n### Upgrade\n\n-   Moving to `popcorn@0.2.0`\n\n## [8.5.0] 2018-11-01\n\n### Fixed\n\n-   Enforcing minor upgrade to Popcorn.\n\n## [8.4.2] 2018-11-01\n\n### Fixed\n\n-   Migrating functions to Popcorn.\n\n## [8.4.1] 2018-09-29\n\n### Fixed\n\n-   Calling `transform.steps()` should round properly to each step. [#528](https://github.com/Popmotion/popmotion/issues/528)\n\n## [8.4.0] 2018-09-21\n\n### Updated\n\n-   Moved to `framesync@4.0.0`\n\n## [8.3.8] 2018-08-30\n\n### Fixed\n\n-   Calling `tween.resume()` would speed the tween up by firing multiple timers. [#395](https://github.com/Popmotion/popmotion/issues/395)\n\n## [8.3.7] 2018-08-30\n\n### Fixed\n\n-   Updating latest style-value-types and stylefire\n\n## [8.3.6] 2018-08-21\n\n### Fixed\n\n-   Fixed `postinstall` script by removing Chalk.\n\n## [8.3.4] 2018-08-20\n\n### Fixed\n\n-   Forcing `multitouch` to use `passive: true`.\n\n## [8.3.2] 2018-06-27\n\n### Fixed\n\n-   Forced fix from `style-value-types@3.0.3`\n\n## [8.3.2] 2018-06-27\n\n### Fixed\n\n-   Updated color regex in `style-value-types`\n\n## [8.3.1] 2018-06-27\n\n### Fixed\n\n-   Fixing some TypeScript definition incompatibilities with newer versions of TS.\n\n## [8.3.0] 2018-06-20\n\n### Added\n\n-   Support for animating value types:\n    -   `px`\n    -   `deg`\n    -   `%`\n    -   `vw`\n    -   `vh`\n    -   Complex types including:\n        -   SVG paths\n        -   CSS gradients\n        -   CSS shadows\n\n## [8.2.5] 2018-06-13\n\n### Fixed\n\n-   Removing `import`s from output declaration files.\n\n## [8.2.4] 2018-06-08\n\n### Added\n\n-   Exporting popular types from index.ts.\n\n## [8.2.3] 2018-05-28\n\n### Fixed\n\n-   Renaming `popmotion.min.js` back to `popmotion.global.min.js`\n\n## [8.2.1] 2018-05-17\n\n### Fixed\n\n-   Removing `process.env.NODE_ENV` from bundled hey-listen\n\n## [8.2.0] 2018-05-17\n\n### Changed\n\n-   Added Rollup to build process. Now just 11.1kb.\n\n### Deprecated\n\n-   `css` and `svg` functions from `stylefire`. Use `styler` instead.\n\n## [8.1.23] 2018-05-10\n\n### Fixed\n\n-   If an action stops more than once, `parallel` doesn't increase the stop counter.\n\n## [8.1.22] 2018-03-23\n\n### Fixed\n\n-   Making `easing` type optional in `interpolate`.\n\n## [8.1.21] 2018-03-13\n\n### Updated\n\n-   Updating `stylefire`.\n\n## [8.1.20] 2018-03-13\n\n### Updated\n\n-   Updating `stylefire`.\n\n## [8.1.19] 2018-03-13\n\n### Updated\n\n-   Updating `stylefire`.\n\n## [8.1.18] 2018-03-13\n\n### Updated\n\n-   Changed `Update` type definition to `Function`.\n\n## [8.1.17] 2018-03-09\n\n### Updated\n\n-   Stylefire updated to `1.2.6`\n\n## [8.1.16] 2018-03-06\n\n### Fixed\n\n-   `value` now fires a velocity check at the end of the following frame to set velocity to `0` if it hasn't been updated.\n\n## [8.1.15] 2018-03-06\n\n### Updated\n\n-   Stylefire updated to `1.2.5`\n\n## [8.1.14] 2018-03-04\n\n### Updated\n\n-   Stylefire updated to `1.2.4`\n\n## [8.1.13] 2018-03-04\n\n### Updated\n\n-   Stylefire updated to `1.2.3`\n\n## [8.1.12] 2018-03-04\n\n### Update\n\n-   Running `parseFloat` on string values when returning velocity.\n-   Stylefire and Style Value Types upgrade\n\n## [8.1.11] 2018-02-19\n\n### Update\n\n-   `interpolate` roughly 200x faster when interpolating between just two numbers.\n\n## [8.1.10] 2018-02-04\n\n### Fixed\n\n-   Stylefire update.\n\n## [8.1.9] 2018-01-22\n\n### Fixed\n\n-   Fix removeEventListener in Chrome 46 [#248](https://github.com/Popmotion/popmotion/pull/248)\n\n## [8.1.8] 2018-01-15\n\n### Fixed\n\n-   Fixing TS errors for `stop`\n\n## [8.1.7] 2018-01-04\n\n### Changed\n\n-   Updating Framesync to improve performance at 30fps.\n\n## [8.1.6] 2018-01-03\n\n### Fixed\n\n-   Fix build.\n\n## [8.1.5] 2018-01-03\n\n### Fixed\n\n-   Upgrading Stylefire.\n-   Corrected types on `tween`.\n\n## [8.1.4] 2017-12-22\n\n### Added\n\n-   `generateStaticSpring` transformer.\n\n## [8.1.3] 2017-12-18\n\n### Added\n\n-   `conditional` transformer.\n\n## [8.1.2] 2017-12-12\n\n### Changed\n\n-   Removed `esnext` and `module` settings from package.json, added `src` to exclude.\n\n## [8.1.1] 2017-12-12\n\n### Changed\n\n-   Adding README.md to package.\n\n## [8.1.0] 2017-12-12\n\n### Release!\n\n## [8.0.37@beta] 2017-12-11\n\n### Changed\n\n-   `everyFrame` now outputs the `timeSinceStart` rather than the current framestamp (which can be taken from `framesync`).\n\n### Fixed\n\n-   Actions that use internal `everyFrame` actions now stop the timer when complete.\n\n## [8.0.35@beta] 2017-12-09\n\n### Added\n\n-   The API matching of `parallel` and `composite` can now accept arguments with the same shape. For instance:\n\n```javascript\ncomposite({\n    x: physics(),\n    y: physics(),\n}).setSpringStrength({ x: 100, y: 50 })\n```\n\n## [8.0.34@beta] 2017-12-05\n\n### Changed\n\n-   `keyframes` prop `ease` is now `easings`. `ease` applies easing to the overall tween.\n\n## [8.0.33@beta] 2017-12-04\n\n### Added\n\n-   `timeline` animation.\n\n### Changed\n\n-   `stagger` now outputs array.\n\n## [8.0.32@beta] 2017-11-28\n\n### Added\n\n-   New `schedule` compositor.\n\n### Changed\n\n-   `transformChildValues` is now `transformMap`, and finally docced.\n\n## [8.0.31@beta] 2017-11-27\n\n### Fixed\n\n-   Stopped new instances of actions mutating shared vars.\n\n## [8.0.30@beta] 2017-11-24\n\n### Fixed\n\n-   Published with wrong version of Stylefire.\n\n## [8.0.29@beta] 2017-11-24\n\n### Fixed\n\n-   Ensuring `everyFrame` stops when it's bloody well told to.\n\n## [8.0.28@beta] 2017-11-22\n\n### Changed\n\n-   Upgrading Stylefire\n\n## [8.0.27@beta] 2017-11-16\n\n### Fixed\n\n-   `delay` waits appropriate number of time before `complete`.\n\n## [8.0.26@beta] 2017-11-16\n\n### Fixed\n\n-   Fixing `scale` delta equation and firing `preventDefault` on multitouch events.\n\n## [8.0.25@beta] 2017-11-16\n\n### Fixed\n\n-   Providing `multitouch` `scale` and `rotate` props outputs the delta as applied to those values.\n\n## [8.0.24@beta] 2017-11-16\n\n### Added\n\n-   `keyframes` `ease` property can now be a single function.\n-   `multitouch` accepts initial `scale` and `rotate` properties.\n-   `filter` chainable to actions and reactions.\n\n### Changed\n\n-   `touch` becomes `multitouch`.\n-   `reaction` becomes `multicast`.\n-   `onFrame` becomes `everyFrame`.\n\n## [8.0.22@beta] 2017-11-16\n\n### Fixed\n\n-   Fixed `tween` flip.\n\n## [8.0.21@beta] 2017-11-16\n\n### Added\n\n-   `scale` and `rotate` properties to `touch`.\n-   `listen` action.\n\n## [8.0.20@beta] 2017-11-14\n\n### Fixed\n\n-   Fixed `isActive` bug with observable. Should look at removing this in favor of Reaction.\n\n## [8.0.19@beta] 2017-11-14\n\n## [8.0.18@beta] 2017-11-14\n\n### Changed\n\n-   Changed `spring` equation.\n\n## [8.0.17@beta] 2017-11-14\n\n### Changed\n\n-   Changed `spring` equation.\n\n## [8.0.16@beta] 2017-11-14\n\n### Fixed\n\n-   Reactivating a reaction when provided a new parent.\n\n## [8.0.15@beta] 2017-11-14\n\n### Fixed\n\n-   Re-reversing `spring` initial velocity.\n\n## [8.0.14@beta] 2017-11-14\n\n### Fixed\n\n-   Not reversing `spring` initial velocity.\n\n## [8.0.13@beta] 2017-11-14\n\n### Fixed\n\n-   `keyframes` composite undefined value fixed.\n\n## [8.0.12@beta] 2017-11-11\n\n### Added\n\n-   `value` handles objects and arrays.\n-   `reaction` and `value` automatically stop previous action if used to start a new one.\n\n### Fixed\n\n-   `composite` APIs now map return values to the provided object, rather than as a flat array.\n\n## [8.0.11@beta] 2017-11-10\n\n### Added\n\n-   Object, array and colour support to `keyframes`.\n\n### Changed\n\n-   `pointerDelta` has been removed, `pointer` now accepts an initial point.\n\n## [8.0.10@beta] 2017-11-09\n\n### Fixed\n\n-   Fixing broken entry point in `package.json`.\n\n## [8.0.9@beta] 2017-11-08\n\n### Added\n\n-   Color support to all vector actions.\n\n## [8.0.8@beta] 2017-11-08\n\n### Added\n\n-   `crossfade`, `delay`, `merge` and `stagger` compositors.\n\n## [8.0.7@beta] 2017-11-07\n\n### Added\n\n-   `chain` compositor.\n\n## [8.0.4@beta] 2017-10-30\n\n### Added\n\n-   New reactive API.\n-   `keyframes` animation.\n-   `decay` animation.\n-   `delta` transformer.\n\n### Removed\n\n-   `flow` alias for `pipe`\n-   Transformers: `add`/`subtract`/`divide`/`multiply`/`conditional`/`alpha`/`percent`/`degrees`/`px`/`rgbUnit`/`rgba`/`hex`/`color`/`hsla`\n-   Renderers: Moved to [Stylefire](https://github.com/Popmotion/stylefire)\n-   Render Loop: Moved to [Framesync](https://github.com/Popmotion/framesync)\n-   Color Tween: Moved to [Popmotion Color Tween](https://github.com/Popmotion/popmotion-color-tween)\n-   Value Types: Moved to [Style Value Types](https://github.com/Popmotion/style-value-types)\n\n### Changed\n\n-   `physics` prop `to` is now `to`\n-   `physics` prop `spring` is now `springStrength`\n-   `physics` prop `autoStopSpeed` is now `restSpeed`.\n-   `spring` prop `restDisplacement` is now `restDelta`.\n\n## [7.8.2] 2017-10-02\n\n### Changed\n\n-   Now publishing `dist` folder on npm for use on CodePen via unpkg.com\n\n### Changed\n\n-   `spring` transformer becomes `linearSpring` to avoid clashing with the `spring` action.\n\n## [7.8.1] 2017-08-29\n\n### Fixed\n\n-   Fixing mistake where Framesync's renamed `currentFrameTime` was exported instead of the previously-named `currentFrameTimestamp`.\n\n## [7.8.0] 2017-08-29\n\n-   Spinning off `framesync` to it's own module and deprecating render loop functions for removal in `8.0.0`.\n\n## [7.7.1] 2017-08-27\n\n### Fixed\n\n-   Bug in `touches` (via [Mars](https://twitter.com/marsi))\n\n## [7.7.0] 2017-08-24\n\n### Added\n\n-   `touches` action for multitouch support. (via [Mars](https://twitter.com/marsi))\n-   `parallel.getChildren` method now returns array of children actions.\n-   `parallel` can now accept an `onUpdate` function that is provided an array of latest child values.\n\n## [7.6.2] 2017-08-17\n\n### Fixed\n\n-   Composite Actions were firing `onUpdate` as soon as registered.\n\n## [7.6.1] 2017-08-17\n\n### Fixed\n\n-   Actions were firing `onUpdate` as soon as registered.\n\n## [7.6.0] 2017-08-07\n\n### Added\n\n-   New `spring` action based on an interpretation of Apple's `CASpringAnimation` by [@skevy](https://github.com/skevy)\n\n## [7.5.6] 2017-08-04\n\n### Fixed\n\n-   Prevent `Value.toUpdate` from being undefined.\n\n## [7.5.5] 2017-08-02\n\n### Fixed\n\n-   Only firing `onStop` on an action bound to a value if the action is active.\n\n## [7.5.4] 2017-07-31\n\n### Fixed\n\n-   A key is only added to Renderer's `changedValues` array if it doesn't already exist for that frame.\n\n## [7.5.3] 2017-07-18\n\n### Fixed\n\n-   Consistency issue with scheduling update on `value.set` - area to look at in the future.\n\n## [7.5.2] 2017-07-18\n\n### Fixed\n\n-   Bug with `css` translate map.\n\n## [7.5.1] 2017-07-17\n\n### Fixed\n\n-   Fixed a bug with `smooth`, preventing it from working if the initial given numbers were `0`, or if it was called twice in the same frame.\n\n## [7.5.0] 2017-07-17\n\n### Added\n\n-   Enforced order for css `transform` properties.\n\n## [7.4.0] 2017-07-16\n\n### Added\n\n-   Added `seek` to `tween`.\n\n## [7.3.1] 2017-07-13\n\n### Added\n\n-   Updated `snap` transform to take numbers for regular interval snapping.\n\n## [7.3.0] 2017-07-13\n\n### Added\n\n-   New `snap` transformer.\n\n## [7.2.9] 2017-07-12\n\n### Changed\n\n-   `trackOffset` now calls `get` instead of `getBeforeTransform`.\n\n## [7.2.8] 2017-07-12\n\n### Fixed\n\n-   `angle` calculation fixed.\n\n## [7.2.7] 2017-07-11\n\n### Fixed\n\n-   `steps` now returning actual value rather than stepped progress.\n\n## [7.2.6] 2017-07-05\n\n### Fixed\n\n-   `speedPerSecond` divide by `0` bug.\n\n## [7.2.5] 2017-07-05\n\n### Fixed\n\n-   `lastUpdated` set to `0` on action start to prevent `NaN` velocities.\n\n## [7.2.4] 2017-07-05\n\n### Fixed\n\n-   `prev = current` on action start, to prevent `NaN` velocities.\n\n## [7.2.3] 2017-07-04\n\n### Fixed\n\n-   `pointer` events are now `passive: true` if `preventDefault` is also set to `true` to fix bug introduced by Chrome 56.\n\n## [7.2.2] 2017-07-03\n\n### Changed\n\n-   `composite` action is now `passive: true` to enable composition of other passive actions.\n\n## [7.2.0] 2017-06-26\n\n### Added\n\n-   `value` can now be provided to an action's `onUpdate` for automatic action management.\n\n## [7.1.1] 2017-06-23\n\n-   Minor bugfix.\n\n## [7.1.0] 2017-06-23\n\n### Added\n\n-   `complex` `valueType`.\n\n## [7.0.3] 2017-06-23\n\n### Fixed\n\n-   Changed `pointer` to read mouse event `client` positioning instead of `page`, to make consistent with touch events.\n\n## [7.0.2] 2017-06-23\n\n-   Minor bugfix.\n\n## [7.0.1] 2017-06-23\n\n-   Minor bugfix.\n\n## [7.0.0] 2017-06-22\n\n### Features\n\n-   `trackOffset` action returns to simplify the process of tracking the offset of other actions.\n-   `esnext` package.json property supported.\n\n### Deprecated\n\n-   `flow` is now `pipe`, to avoid terminology clashes with [Flow](https://flow.org/). `flow` will continue to work until `7.1.0`.\n\n### Removed\n\n-   `blendTweens` is now an optional include.\n\n## [6.7.2] 2017-06-01\n\n### Fixed\n\n-   Removing dependencies from `package.json`\n\n## [6.7.1] 2017-06-01\n\n### Fixed\n\n-   `colorTween` now uses `transform` property to convert from progress to color, which fixes composition compatibility.\n\n## [6.7.0] 2017-06-01\n\n### Added\n\n-   `transform` property for actions. If set, any values passed to `onUpdate` or returned from `get` will be run through this function.\n-   `getBeforeTransform` method added for actions. Will return the current value, before transform is applied.\n\n## [6.3.5] 2017-03-03\n\n### Added\n\n-   `applyOffset` transformer.\n\n## [6.3.4] 2017-03-01\n\n### Fixed\n\n-   Undocumented range easing property in `interpolate` transformer was looking at the wrong index.\n\n## [6.3.3] 2017-18-01\n\n### Added\n\n-   `top`, `left`, `bottom` and `right` CSS renderer value types.\n\n## [6.3.2] 2017-11-01\n\n### Added\n\n-   `smooth` transformer\n\n## [6.3.1] 2017-11-01\n\n### Fixed\n\n-   `transformChildValues` transformer now keeps a local mutable state rather than mutating the provided state.\n\n## [6.3.0] 2017-11-01\n\n### Added\n\n-   Actions now have an `output` shorthand for setting the `onUpdate` property.\n\n## [6.2.1] 2017-09-01\n\n### Added\n\n-   Updated bezier tween blend algorithm.\n-   Exposed bezier resolver as a transformer.\n\n## [6.2.0] 2017-09-01\n\n### Added\n\n-   Bezier tween blending\n\n## [6.1.0] 2017-06-01\n\n-   Public release of new API\n\n## [6.0.0@alpha] 2017-01-01\n\n-   New API\n\n## [5.0.20] 2016-11-15\n\n### Fixed\n\n-   Accidentally transpiled a version of 6.0.\n\n## [5.0.19] 2016-11-15\n\n### Added\n\n-   `track` Can take `preventDefault` as optional second param. Defaults to `true`.\n\n## [5.0.18] 2016-08-08\n\n### Fixed\n\n-   Firing `onActivateLoop` even if task is already active to prevent `once` from running more than once.\n\n## [5.0.17] 2016-05-08\n\n### Fixed\n\n-   Actually fixing spring clamping this time.\n\n## [5.0.16] 2016-05-08\n\n### Fixed\n\n-   Spring physics action now automatically ending when target is reached.\n\n## [5.0.15] 2016-18-07\n\n### Fixed\n\n-   Missing compilation of `5.0.14`\n\n## [5.0.14] 2016-18-07\n\n### Fixed\n\n-   Preventing `current` being overwritten by value type default properties.\n-   `Tween`s now finish automatically when scrubbed, fixing timeline/stagger bug where tweens wouldn't end.\n\n## [5.0.13] 2016-06-07\n\n### Fixed\n\n-   `track.start` and `track.stop` now returning `this`, allowing chaining.\n-   `from` restored as `track` default value.\n\n## [5.0.12] 2016-06-01\n\n### Fixed\n\n-   @[jamieowen](https://github.com/jamieowen): `transform` now being prefixed correctly.\n-   [#156](https://github.com/Popmotion/popmotion/issues/156): Explicit tween `from` values now honoured by `flow.start`.\n\n### Changed\n\n-   Converted project from 4 space indent to 2.\n\n## [5.0.11] 2016-05-21\n\n### Changed\n\n-   Tween `blend` property set to `false` by default.\n\n### Fixed\n\n-   Mouse tracking in Firefox - `Object.watch` is truthy in Firefox.\n\n## [5.0.10] 2016-05-21\n\n### Fixed\n\n-   @[FreakTheMighty](https://github.com/FreakTheMighty): Setting bound pointer listener to ensure correct removal on `Pointer.stop`.\n\n## [5.0.9] 2016-05-21\n\n### Fixed\n\n-   @[jamieowen](https://github.com/jamieowen): Prefixed properties now being set correctly.\n\n## [5.0.8] 2016-05-15\n\n### Added\n\n-   Unit tests for `transformers.createMapper`.\n\n### Fixed\n\n-   Fixed mapped values calculated from `transformers.createMapper` mappers that are outside of the input range returning `undefined`.\n\n## [5.0.7] 2016-04-20\n\n### Changed\n\n-   Subsequent actions started on a flow are only given the flow's velocity if their velocity is 0.\n\n## [5.0.6] 2016-04-17\n\n### Changed\n\n-   Inherited actions now receive a `parentId` property with the `id` of their parent action.\n\n## [5.0.5] 2016-04-13\n\n### Fixed\n\n-   On `set`, `current` was returning undefined if `values` prop set as value, forcing an `adapter` read.\n\n## [5.0.4] 2016-04-13\n\n### Fixed\n\n-   If `adapter` returns a string that should be a pure number, we parse that as a float.\n\n## [5.0.3] 2016-04-06\n\n### Fixed\n\n-   Regression from testing `5.0.2`.\n\n## [5.0.2] 2016-04-06\n\n### Fixed\n\n-   Fixing entry point in `package.json`.\n\n## [5.0.1] 2016-03-30\n\nMinor bugfixes.\n\n## [5.0.0] 2016-03-29\n\n### Popmotion 5.0: timelines, streamlined API, tween blending, still 12kb.\n\n**Warning:** This is a major API revision. Previous Popmotion code **will** be incompatible with this upgrade.\n\n### Added\n\n-   **Timelines**: Super-simple yet fully-featured nestable timelines to easily sequence `tweens`.\n-   **Tween blending**: Smooth transitions between overlapping tweens.\n-   **Standalone actions**: `tween`, `physics` and `track` can all run without the need for an `actor`.\n-   **Adapters**: Minimal `get`/`set` API wrappers for smoothing differences between DOM, SVG and frameworks.\n-   **Transformers**: Composable functions to transform values between update and render.\n-   **Unified physics engine**: Handles `velocity`, `friction` and `spring` in one unified `physics` action.\n-   **Small**: All this for less than 12kb minified & gzipped.\n-   **Smaller**: Rewritten entirely using ES6 exports to allow tree-shaking, ignoring the parts of Popmotion you don't include.\n-   **Global time dilation**: `setGlobalDilation` method can change the global time.\n-   **Flow layer**: Replaces Actors and can work entirely in the background to manage multiple actions on the same object.\n-   Support `points` property for `polygon` and `polyline` tags.\n-   **MIT**: Changed licence to MIT.\n\n### Removed\n\n-   `new` - dropped in favour of factory functions (ie `new Tween()` becomes `tween()`). This will allow further non-API-breaking optimisations.\n-   `Actor` dropped in favour of `flow`. The Actor model was monolithic, flows are automatically generated for `element`s in the background and can be accessed optionally via `detectFlow`.\n-   `process`: Now `task`. Prevents conflict with global common in browsers.\n-   Removed Action `watch` property in favour of more flexible `transform`: Simply provide a function that returns a different value.\n-   Native Meteor support, as we kept forgetting to update it.\n-   jQuery support - provide elements as returned from `$('.yourElement').get()` instead.\n-   `Sequence`: Dropped in favour of the `timeline` function.\n-   `Iterator`: Dropped in favour of using native array methods and the new `stagger` function.\n-   `Simulate`: Dropped in favour of unified `physics` action.\n\n### Changed\n\n-   `friction` now a value between `0` and `1` - `0` provides no friction, `1` will strip all velocity within a single frame.\n\n## [4.3.4] 2015-12-30\n\n### Fixed\n\n-   `Simulate.hasChanged` incorrectly calculated.\n\n## [4.3.3] 2015-12-29\n\n### Fixed\n\n-   Added `acceleration` to list of properties that can be set as functions, resolved when an Action starts.\n\n## [4.3.2] 2015-12-26\n\n### Fixed\n\n-   Recursion bug with `Actor.sync` under specific circumstances.\n\n## [4.3.1] 2015-12-24\n\n### Removed\n\n-   `deceleration` from `Simulate`.\n\n### Fixed\n\n-   Fixed bug where `Tween` would start as ended if initialised during `update` ie via a `Sequence`.\n\n## [4.3.0] 2015-12-17\n\n### Added\n\n-   `scale` value type hooked up to CSS and SVG roles.\n-   `utils.camelToDash` utility function for converting camelCase props to dash-case.\n\n### Changed\n\n-   Default `Simulate` `stopSpeed` changed from `5` to `0.0001` to account for tiny numbers like 0-1.\n\n## [4.2.7] 2015-12-09\n\n### Fixed\n\n-   SVG properties set ie `fillOpacity` are now getting set as `fill-opacity`.\n\n## [4.2.6] 2015-12-08\n\n### Fixed\n\n-   Fixed recursive loop when splitting Actor values.\n\n## [4.2.5] 2015-12-07\n\n### Added\n\n-   `opacity`, `fillOpacity` and `strokeOpacity` to `ui.svg` Role type map.\n\n## [4.2.4] 2015-12-07\n\n### Added\n\n-   `Simulate.autoEnd` property, set to `false` to prevent simulations from automatically ending.\n\n### Fixed\n\n-   TweenControls `reverse` now work on completed Tweens.\n\n## [4.2.3] 2015-12-06\n\n### Added\n\n-   Actors automatically `sync` on init.\n\n## [4.2.2] 2015-12-03\n\n### Update\n\n-   Moving from Babel's official es2015 preset to a custom build.\n\n## [4.2.1] 2015-12-03\n\n### Update\n\n-   Updating Babel to fix transpilation errors in IE10.\n\n## [4.2.0] 2015-12-02\n\n### Changed\n\n-   Moving to dual commercial and GPLv3 licence.\n\n## [4.1.0] 2015-11-28\n\n### Added\n\n-   Actor value `watch` property can now be a function returning any numerical value.\n-   Added `smooth` for all actions.\n-   Added `calc.toDecimal` calculator function.\n\n## [4.0.0] 2015-11-20\n\n### Added\n\n-   New core processing loop. Separates processes into four stages: `update`, `preRender`, `render`, `postRender`.\n-   `Process.once` to fire a Process for a single frame.\n-   Run background processes by passing `true` to `Process.setBackground` or as the last argument to the `Process` constructor. Background processes won't spin up the process loop when activated, only running when non-background processes are active.\n\n### Changed\n\n-   `new ui.Process()` takes `callback, scope` instead of `scope, callback`.\n-   `Process` callbacks now receive `scope` as the first argument, then `framestamp, frameDuration`.\n\n### Removed\n\n-   `Process.every`, `Process.reset` and `Process.fire`. Processes should only be started/stopped with `Process.start` and `Process.stop` respectively, to ensure they're run as part of the main loop. `every` is redundant with a combination of `setInterval` and `Process.once`.\n-   `Process.start` no longer takes a time period as an argument - use `setTimeout` to `Process.stop`.\n\n## [3.8.1] 2015-11-19\n\n### Fixed\n\n-   Pow easings incorrectly named var.\n\n## [3.8.0] 2015-11-19\n\n### Added\n\n-   Elliot Geno's awesome `'anticipate'` easing. Follow him at [@ElliotGeno](https://twitter.com/ElliotGeno/).\n-   In-built easings now available in the `ui.ease` namespace. So instead of providing `'backOut'` you can reference it literally - `ui.ease.anticipate`.\n-   Create modified easing function strengths, for instance `ease: ui.modifyEase(ui.ease.backOut, 2)`. `'ease'` and `'back'` in/out/inOut variants and `'anticipate'` are available. You must provide the literal reference rather than string reference.\n\n## [3.7.1] 2015-11-11\n\n### Changed\n\n-   Refactored core clock to increase performance in lower-end devices.\n\n## [3.7.0] 2015-11-07\n\n### Changed\n\n-   Software licence changed. Popmotion is now free for non-commercial uses, and requires a per-project licence for commercial projects.\n-   More files converted to ES6 syntax.\n-   Moved back to small for production compilation.\n-   Upgraded Babel from 5 to 6.\n\n### Added\n\n-   Beginning suite of Mocha unit tests.\n\n## [3.6.3] 2015-11-03\n\n### Added\n\n-   Extra tests to ensure Popmotion is loading correctly in Meteor.\n\n### Fixed\n\n-   Explicit test for rAF for when `window` is available and `requestAnimationFrame` isn't.\n\n## [3.6.2] 2015-11-02\n\n### Added\n\n-   Meteor support. Published on [Atmosphere](https://atmospherejs.com/popmotion/popmotion) as `popmotion:popmotion`.\n\n### Fixed\n\n-   `performance` and `window` checks in Node.\n\n## [3.6.1] 2015-10-29\n\n### Fixed\n\n-   Smoothing lower than frameduration produced odd values.\n-   Smooth by `0` `Infinity` error\n\n## [3.6.0] 2015-10-29\n\n### Added\n\n-   New `transform(value, key, actor)` property for `Actor` values. Allows you to return a new value after its been processed by an action, but before it's been limited/rounded etc.\n-   Exposed our `Track` `smooth` calculator as `ui.calc.smooth`.\n\n### Changed\n\n-   Refactored some files to cut down on filesize.\n\n### Fixed\n\n-   Fixed a regression from `3.3.3` that fixed `performance` in IE9.\n\n## [3.5.0] 2015-10-21\n\n### Added\n\n-   Roles are now getter/setters, if `get` and `set` methods are present. For example: CSS role has getter/setters, so you can call:\n\n    ui.css(element, {\n    position: 'absolute',\n    top: 0\n    });\n\n## [3.4.4] 2015-10-22\n\n### Fixed\n\n-   `Actor.stop().start()` was failing to run.\n\n## [3.4.3] 2015-10-21\n\n### Fixed\n\n-   `Actor.sync` now returns `Actor` rather than the bound sync `Action`.\n\n## [3.4.2] 2015-10-21\n\n### Fixed\n\n-   `svg` tags are now assigned `ui.css` role.\n\n## [3.4.1] 2015-10-17\n\n### Fixed\n\n-   Delaying test element creation in CSS Role prevents error in server-side rendering.\n\n## [3.4.0] 2015-10-16\n\n### Added\n\n-   `Sequence` class, for creating a sequence of non-sequential actions.\n-   `onComplete` property to `Iterator.stagger`.\n-   Pass an action as the `Iterator.each` and `Iterator.stagger` `method` argument to automatically run `start` on each `Actor`.\n\n### Changed\n\n-   Using rAF-provided timestamp instead of `performance.now` for smoother motion.\n\n## [3.3.3] 2015-10-13\n\n### Fixed\n\n-   @stoikerty: Fixed `performance.now` check for IE9.\n\n## [3.3.2] 2015-10-10\n\n### Fixed\n\n-   `Pointer` events now properly unbound on `Actor` stop.\n\n## [3.3.1] 2015-10-09\n\n### Added\n\n-   `Actor.smooth` now settable on a per-value basis.\n-   `direct` value property added to take direct input values instead of inputOffset.\n\n## [3.3.0] 2015-10-08\n\n### Added\n\n-   `smooth` property added to `Track` - smoothes out values coming from `Input` sources.\n\n## [3.2.1] 2015-10-07\n\n### Fixed\n\n-   `watch` no longer overwritten on `set`.\n\n## [3.2.0] 2015-10-06\n\n### Added\n\n-   `ui.select` now caches and finds cached Actors bound to DOM elements. If one Actor is found, it returns an Actor. If multiple Actors are found, an Iterator.\n-   `reverse` method to `Iterator`.\n\n## [3.1.7] 2015-10-05\n\n## Fixed\n\n-   Adjusting `hasChanged` logic to always fire on first frame.\n-   Changing `Iterator.stagger` logic for more even staggers.\n\n## [3.1.6] 2015-10-05\n\n## Fixed\n\n-   Manually moved the library class filenames to uppercase.\n\n## [3.1.5] 2015-10-05\n\n## Fixed\n\n-   Renamed some class files to uppercase to fix include fails in some Browserify compilations.\n\n## [3.1.4] 2015-10-05\n\n## Added\n\n-   Simulation functions are now sent `value <object>, frameDuration <int>, timeStarted <timestamp>` as arguments.\n\n## [3.1.3] 2015-10-04\n\n## Fixed\n\n-   Actions fired within an `onComplete` wouldn't start because the number of active Actions was being counted incorrectly.\n\n## [3.1.2] 2015-10-03\n\n### Fixed\n\n-   Major Firefox bug 1) `values` false-positive test for `watch` property, now explicitly checking for `string`.\n-   Major Firefox bug 2) `element.style.hasOwnProperty()` always returning false, switching to `in element.style`.\n\n## [3.1.1] 2015-10-02\n\n### Fixed\n\n-   Clearing Actor then/next queue on `start`.\n-   Saving all arguments to queue via `then` so we can pass Inputs.\n\n## [3.1.0] 2015-10-01\n\n### Added\n\n-   Action-specific `onStart`, `onUpdate`, `onFrame` and `onComplete` callbacks. These callbacks will be active only for the duration of the action, while callbacks attached to the host Actor will persist through all actions.\n\n### Changed\n\n-   `onStart` callbacks are now fired immediately before the Actor is activated, giving actions extra time to initiate and make use of the [< 100ms response window](https://aerotwist.com/blog/flip-your-animations/).\n\n### Fixed\n\n-   Bugfix for deep-copying Actions on Action start. That was a whoops and a half.\n\n## [3.0.4] 2015-09-30\n\n### Fixed\n\n-   Bugfix for subvalues not being flipped correctly.\n\n## [3.0.3] 2015-09-30\n\n### Fixed\n\n-   SVG Role divide by 0 error when `scale` === 0.\n\n## [3.0.2] 2015-09-29\n\n### Fixed\n\n-   Bugfix where Popmotion would attempt to split numerical values.\n-   Bugfix for `complex` valueType regex where negative numbers were made positive.\n\n## [3.0.0] 2015-09-29\n\n### Added\n\n-   Full SVG support.\n-   Multiple simultaneous Actions on a single Actor - mix Simulations, Tracking and Tweens on the same elements!\n-   Animate complex strings, like `path` `d` attributes.\n-   Iterator - to allow single classes to be extended the ActorCollector has been dropped in favour of a generic Iterator class, which can iterate over any set of classes. This also makes it clearer when you're interacting with multiple items vs a single Actor, and these items are not longer limited to Actors.\n-   Roles - `ui.css`, `ui.attr`, `ui.svg`, `ui.draw`. These are auto-assigned to Actors when initialised with an `element` property, but can also be manually assigned with the `as` property on Actor initialisation.\n-   Actors can have multiple roles by providing an array to `as`.\n-   New roles can be created with `new ui.Role()`.\n-   Value names can be translated before a Role accesses it, via a Role's `map` property. For example `ui.cssRole` maps `x` to `translateX`.\n-   Action classes/definitions - `Tween`, `Simulate`, `Track`\n\n### Removed\n\n-   `ui.addRoute` - see Roles\n-   `ui.addPreset`, `ui.addAction` - see Tween, Simulate and Track classes\n-   `ActorCollection` - see Iterator\n-   `play`, `run`, `track` Actor methods - use `start`\n\n### Changed\n\n-   `addToQueue` Actor method is now `then` and takes Tween, Simulate and Track instances instead of raw properties.\n-   `mapLink` Actor value property is now `mapFrom`.\n-   Default tween `duration` set to `300`.\n-   Default tween `ease` set to `\"easeOut\"`.\n-   `reverse`, `reset` -> `restart`, `seek` methods moved to `TweenControls` (returned when a `Tween` is passed to `start`)\n\n### Deprecated\n\n-   `flipValues`, `reverse`, `reset`, `resetProgress`, `resetOrigins` and `seek` Actor methods - these are all going to be moved to the `Tween` class in `3.2.0`\n\n## [2.0.4] 2015-08-10\n\n### Fixed\n\n-   Fixing `bounce` and `capture` simulation calls.\n\n## [2.0.3] 2015-08-10\n\n### Removed\n\n-   Removed undocumented `ui.addSimulation` - new simulations now passed as function instead of simulation name.\n\n## [2.0.2] 2015-08-10\n\n### Changed\n\n-   `Actor.seek` no longer an Action, much higher performance.\n\n## [2.0.1] 2015-08-07\n\n### Changed\n\n-   Only numerical properties can be set as functions to be resolved on action start.\n\n## [2.0.0] 2015-08-07\n\n### Removed\n\n-   `ui.addEasing()`\n\n### Added\n\n-   New easing functions are now generated with `new ui.Easing()` and provided as the `ease` property. When provided an easeIn function, `in`, `out` and `inOut` methods are returned.\n\n## [1.0.0] 2015-08-06\n\n**Note:** Forked from Redshift v2.1.1.\n\n### Changed\n\n-   `redshift` object name now `ui`.\n-   Terminology changes to fix API semantics:\n    -   **Action:** Actor\n    -   **ActionCollection:** ActionCollection\n    -   **Rubix:** Action (as in, an Action an Actor can perform)\n\n### Added\n\n-   Add new easing functions with `ui.addEasing()`. Provide the easeIn function and Popmotion will generate easeOut and easeInOut variants.\n-   Add new simulation functions to `run` with `ui.addSimulation()`.\n-   Any value can be a special **value type**, ie a color. `'#FFF'` splits into four numerical properties, `Red`, `Blue`, `Green` and `Alpha`.\n-   Add new value types with `ui.addValueType()`.\n-   HSLA value type support.\n\n## [2.1.1] 2015-06-11\n\n### Fixed\n\n-   Change Action `rubix` from `\"seek\"` to `\"play\"` onEnd.\n\n## [2.1.0] 2015-06-11\n\n### Added\n\n-   Added `.seek()` method to Actions.\n\n## [2.0.5] 2015-06-02\n\n### Added\n\n-   ActionGroup returns array of values when a getter is called.\n\n## [2.0.4] 2015-06-01\n\n### Fixed\n\n-   `onStart` regression from 2.0.0 - only firing for 'values' route.\n\n## [2.0.3] 2015-06-01\n\n### Fixed\n\n-   Fixing hasChanged regression, prevented .run() from stopping automatically.\n\n## [2.0.2] 2015-06-01\n\n### Fixed\n\n-   Adding Alpha property to all split color values (default: 1), in case a value has mixed RGB and RGBA properties.\n\n## [2.0.1] 2015-06-01\n\n### Added\n\n-   CSS values travelling through a splitter (ie backgroundColor is split into RGB values) can be set as functions like normal values.\n\n## [2.0.0] 2015-06-01\n\n### Changed\n\n-   Upgraded stepped easing algorithm.\n-   `Action.hasChanged` set to `true` when `Action.isActive(true)`\n\n### Removed\n\n-   `.props()` method removed - properties now saved directly to Action object.\n-   `.data()` functionality removed, just set properties of Action instead.\n-   `.flip()` is now `.flipValues()`.\n\n## [1.4.1] 2015-05-31\n\n### Fixed\n\n-   ActionGroup.stagger() wasn't returning `this`\n\n## [1.4.0] 2015-05-31\n\n### Added\n\n-   Action Groups for controlling multiple Actions at once.\n-   Stagger method for Action Groups.\n-   DOM selection support for creating Actions prepopulated with DOM elements.\n\n### Fixed\n\n-   Calling .play(preset) while Action was in progress failed to add that call to the play queue.\n-   Added check for Process timers before clearing as clearTimeout is costing ~.4ms.\n"
  },
  {
    "path": "packages/popmotion/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright © 2019 Framer BV\n\nPermission 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:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE 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."
  },
  {
    "path": "packages/popmotion/README.md",
    "content": "# <a href=\"https://popmotion.io\"><img src=\"https://cloud.githubusercontent.com/assets/7850794/21642571/1910a15e-d27b-11e6-84c7-19e88e207c14.png\" height=\"52\" width=\"243\" alt=\"Popmotion\" /></a>"
  },
  {
    "path": "packages/popmotion/docs/api/action.md",
    "content": "---\ntitle: Action\ndescription: Create a reactive stream of values.\nnext: animations\n---\n\n# Action\n\nAction is a simplified Rx-inspired reactive stream focused on animation.\n\n**Every Popmotion animation and input is an action.**\n\nWhen an action is started, it returns a simple interface that includes **at least** a `stop` method.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { action } from 'popmotion';\n```\n\n## Usage\n\n### Definition\n\nThe `action` factory takes one argument, an `init` function.\n\nThis is a function that is provided an object of `update`, `complete`, and `error` functions.\n\nUsage of these functions is optional. Your action may call all or just some of them:\n\n```javascript\naction(({ update, complete, error }) => {\n  update(1);\n});\n```\n\n### Initialisation\n\n`action` returns a `start` method. This also accepts an object of `update`, `complete`, and `error` functions.\n\nWhen called, the `init` function is provided these functions, and a **new instance** of the action is created.\n\nCalling `start` multiple times will create multiple, separate instances of the action.\n\nFor example:\n\n```javascript\nconst foo = action(({ update }) => {\n  let i = 0;\n  setInterval(() => update(i++), 50);\n});\n\nfoo.start({\n  update: (v) => console.log(v)\n}); // 0, 1, 2...\n```\n\nIf `start` is passed **only a function**, that is assigned to the `update` function:\n\n```javascript\nfoo.start((v) => console.log(v)); // 0, 1, 2...\n```\n\nWe can also listen for the `complete` event like this:\n\n```javascript\nconst foo = action(({ update, complete }) => {\n  let i = 0;\n  setInterval(() => {\n    update(i++);\n    if (i === 10) complete();\n  }, 50);\n});\n\nfoo.start({\n  update: (v) => console.log(v), // ...8, 9, 10\n  complete: () => console.log('complete!')\n});\n```\n\n### Interface\n\nThe `init` function can **optionally** return an API.\n\nFor instance, we might use this to stop a timer:\n\n```javascript\nconst foo = action(({ update }) => {\n  const interval = setInterval(() => update('ping!'), 100);\n\n  return {\n    stop: () => clearInterval(interval)\n  };\n});\n\nconst bar = foo.start(console.log);\nsetTimeout(() => bar.stop(), 1000);\n```\n\nAny method returned by the action `init` function will be exposed when an action instance is created.\n\n### Modification\n\n`action` is **chainable**, which means it offers methods that can alter the behaviour of the base action. Currently, these are `while` and `pipe` (see [Methods](#methods)).\n\nWhen an action is chained, a **new action** is returned. For instance:\n\n```javascript\nconst foo = action(({ update }) => {\n  let i = 0;\n  setInterval(() => update(i++), 50);\n});\n\nconst lessThanTen = (v) => v < 10;\nconst log = (v) => console.log(v);\n\nfoo.start(log); // ...8, 9, 10, 11...\nfoo.while(lessThanTen).start(log); // ...8, 9\n```\n\n## Methods\n\n### pipe\n\n```typescript\npipe(...funcs: (v: any) => any)\n```\n\nReturns a **new** action that passes the output of the original action's `update` through the provided functions, from left to right.\n\n#### Example\n\n```javascript\nconst init = ({ update }) => update(10);\nconst double = (v) => v * 2;\nconst px = (v) => v + 'px';\n\naction(init)\n  .pipe(double, px)\n  .start((v) => console.log(v)); // '20px'\n```\n\n### start\n\n```typescript\nstart(update: (v: any) => void)\nstart({\n  complete? () => void,\n  error?: (err: any) => void,\n  update?: (v: any) => void\n})\nstart(reaction)\n```\n\nStarts the action by running its initiation function, and returning its API.\n\nEvery interface returned by a `start` call, **regardless of the API returned from the observable**, will return at least a `stop` function.\n\nIt can be provided either an `update` function, or an object with `update`, `complete` and `error` functions.\n\n#### Example\n\n```javascript\n// Doesn't return an API\nconst foo = action(({ update }) => update(1)).start();\nfoo.stop();\n\n// Returns a custom API\nconst bar = action(({ update }) => {\n  let i = 0;\n  setInterval(() => update(i), 100);\n\n  return {\n    setOutput: (v) => i = v\n  };\n}).start();\nbar.setOutput(2);\nsetTimeout(() => bar.stop(), 1000);\n```\n\n### while\n\n```typescript\nwhile(predicate: (v: any) => boolean)\n```\n\nReturns a new action, that will continue to run **while** the updated values match the provided predicate.\n\nWhen the predicate function returns `false`, the action will `complete`.\n\n### Example\n\n```javascript\nlet latest = 0;\n\nconst init = ({ update }) => {\n  let i = latest;\n  setInterval(() => update(i++), 50);\n};\n\naction(init)\n  .while((v) => v < 10)\n  .start({\n    update: (v) => latest = v,\n    complete: () => console.log(v) // 9\n  });\n```\n"
  },
  {
    "path": "packages/popmotion/docs/api/animation/decay.md",
    "content": "---\ntitle: Decay\ndescription: Exponential deceleration, primarily for use in momentum scrolling.\ncategory: animation\n---\n\n# Decay\n\nAn animation that decelerates to an automatically generated target value, based on its initial velocity.\n\nThis target can be modified.\n\n**Note:** This animation is deprecated in favour of [`inertia`](/api/inertia).\n\n<TOC />\n\n## Import\n\n```javascript\nimport { decay } from 'popmotion';\n```\n\n## Usage\n\nProvide a `velocity` and `from` value, and `decay` will calculate a `to` target value and decelerate towards it.\n\nIt will output values to a function provided to `start`:\n\n```javascript\ndecay({ velocity: 200, from: 50 })\n  .start(v => console.log(v))\n```\n\nWe can adjust the calculated target value with the `modifyTarget` prop.\n\nThis is a function that accepts the calculated target and returns a new one. For instance, we can snap the target to the nearest `100` like so:\n\n```javascript\ndecay({\n  velocity: 200,\n  from: 50,\n  modifyTarget: v => Math.round(v / 100) * 100\n})\n```\n\n## Props\n\nThe following properties may be passed to `decay`:\n\n### velocity\n\nInitial velocity to decelerate from.\n\n**Default:** `0`\n\n### from\n\nStart value of the animation.\n\n**Default:** `0`\n\n### power\n\nA constant with which to calculate a target value. Higher power = further target.\n\n**Default:** `0.8`\n\n### timeConstant\n\nAdjusting the time constant will change the duration of the deceleration, thereby affecting its feel.\n\n**Default:** `350`\n\n### restDelta\n\nAutomatically completes the action when the calculated value is this far away from the target. The final output value will be snapped to the target.\n\n**Default:** `0.5`\n\n### modifyTarget\n\nA function that receives the calculated target and returns a new one. Useful for snapping the target to a grid, for example.\n\n**Default:** `v => v`\n\n## Methods\n\n### Action methods\n\n`decay()` returns:\n\n#### start\n\nStarts the animation and returns playback controls.\n\nCan be provided **either** a function:\n\n```javascript\ndecay(props).start(v => {})\n```\n\nOr a named map of functions for `update` and `complete`:\n\n```javascript\ndecay(props).start({\n  update: v => {},\n  complete: () => {}\n})\n```\n\n#### filter\n\nReturns a new version of the animation, that filters out any value when the provided predicate function returns `false`:\n\n```javascript\nconst filtered = decay(props).filter(v => v > 0.5)\n\n// This animation will only output values higher than 0.5:\nfiltered.start(v => {})\n```\n\n#### pipe\n\nReturns a new animation that will pass any output value through this series of functions:\n\n```javascript\n// This animation will round output values and then double them:\ndecay({ from: 0, velocity: 1000 })\n  .pipe(Math.round, v => v * 2)\n  .start(v => {})\n```\n\n#### while\n\nReturns a new animation that will `complete` when the provided predicate function returns `false`:\n\n```javascript\n// This animation will end when an output value is higher than 0.5:\ndecay().while(v => v < 0.5)\n```\n\n### Playback methods\n\n`decay().start()` starts a new animation and returns the following playback methods:\n\n#### stop\n\nStops the animation.\n\n## Example\n\n<CodePen id=\"Kyewbv\" />\n"
  },
  {
    "path": "packages/popmotion/docs/api/animation/every-frame.md",
    "content": "---\ntitle: Every Frame\ndescription: Fires with timestamp, once every frame.\ncategory: animation\n---\n\n# Every Frame\n\n`everyFrame` fires once per frame, and provides `update` with the duration of time since it started.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { everyFrame } from 'popmotion';\n```\n\n## Usage\n\n```javascript\neveryFrame()\n  .start((timeSinceStart) => console.log(timeSinceStart));\n```\n\n## Methods\n\n### Action methods\n\n`everyFrame()` returns:\n\n- `filter((v: any) => boolean)`: Returns a new action that filters out values when the provided function returns `false`.\n- `pipe(...funcs: Array<(v) => v)`: Returns a new action that will run `update` values through this sequence of functions.\n- `start(update | { update, complete })`: Starts the action and returns a subscription.\n- `while((v: any) => boolean)`: Returns a new action that will `complete` when the provided function returns `false`.\n\n\n### Subscription methods\n\n`everyFrame().start()` returns:\n\n- `stop(): void`\n\n## Example\n\n<CodePen id=\"XzYJvP\" />\n"
  },
  {
    "path": "packages/popmotion/docs/api/animation/inertia.md",
    "content": "---\ntitle: Inertia\ndescription: Inertial scrolling with spring-loaded boundaries.\ncategory: animation\n---\n\n# Inertia\n\nAn animation decelerates a value based on its initial velocity, usually used to implement inertial scrolling.\n\nOptionally, `min` and `max` boundaries can be defined, and `inertia` will snap to these with a [`spring`](/api/spring) animation.\n\nThis animation will automatically precalculate a target value, which can be modified with the `modifyTarget` property. This allows you to add snap-to-grid or similar functionality.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { inertia } from 'popmotion';\n```\n\n## Usage\n\nProvide a `velocity` and `from` value, and `inertia` will automatically calculate a target and decelerate towards it.\n\n```javascript\ninertia({ velocity: 200, from: 50 })\n  .start(v => console.log(v))\n```\n\nWe can adjust the calculated target value with the `modifyTarget` prop.\n\nThis is a function that accepts the calculated target and returns a new one. For instance, we can snap the target to the nearest `100` like so:\n\n```javascript\ninertia({\n  velocity: 200,\n  from: 50,\n  modifyTarget: v => Math.round(v / 100) * 100\n})\n```\n\nWe can also set `min` and/or `max` boundaries:\n\n```javascript\ninertia({\n  velocity: 500,\n  from: 50,\n  max: 1000\n})\n```\n\nWhen the animated value breaches `max`, it'll snap to `max` using a [spring](/api/spring) animation.\n\n## Props\n\nThe following properties may be passed to `inertia`:\n\n### velocity\n\nInitial velocity to decelerate from.\n\n**Default:** `0`\n\n### from\n\nStart value of the animation.\n\n**Default:** `0`\n\n### modifyTarget\n\nA function that receives the calculated target and returns a new one. Useful for snapping the target to a grid, for example.\n\n**Default:** `v => v`\n\n### bounceStiffness\n\nStiffness of the bounce animations. Higher values will create more sudden movement.\n\n**Default:** `500`\n\n### bounceDamping\n\nStrength of opposing force for the bounce animations. If set to `0`, spring will oscillate indefinitely.\n\n**Default:** `10`\n\n### power\n\nHigher power = further target.\n\n**Default:** `0.8`\n\n### timeConstant\n\nAdjusting the time constant will change the duration of the deceleration, thereby affecting its feel.\n\n**Default:** `700`\n\n## Methods\n\n### Action methods\n\n`inertia()` returns:\n\n#### start\n\nStarts the animation and returns playback controls.\n\nCan be provided **either** a function:\n\n```javascript\ninertia(props).start(v => {})\n```\n\nOr a named map of functions for `update` and `complete`:\n\n```javascript\ninertia(props).start({\n  update: v => {},\n  complete: () => {}\n})\n```\n\n#### filter\n\nReturns a new version of the animation, that filters out any value when the provided predicate function returns `false`:\n\n```javascript\nconst filtered = inertia(props).filter(v => v > 0.5)\n\n// This animation will only output values higher than 0.5:\nfiltered.start(v => {})\n```\n\n#### pipe\n\nReturns a new animation that will pass any output value through this series of functions:\n\n```javascript\n// This animation will round output values and then double them:\ninertia({ from: 0, velocity: 1000 })\n  .pipe(Math.round, v => v * 2)\n  .start(v => {})\n```\n\n#### while\n\nReturns a new animation that will `complete` when the provided predicate function returns `false`:\n\n```javascript\n// This animation will end when an output value is higher than 0.5:\ninertia().while(v => v < 0.5)\n```\n\n### Playback methods\n\n`inertia().start()` starts a new animation and returns the following playback methods:\n\n#### stop\n\nStops the animation.\n\n## Example\n\n<CodePen id=\"BMNvqj\" />\n"
  },
  {
    "path": "packages/popmotion/docs/api/animation/keyframes.md",
    "content": "---\ntitle: Keyframes\ndescription: Animate through a linear sequence of values.\ncategory: animation\n---\n\n# Keyframes\n\nKeyframes accepts an array of values and will animate between each in sequence.\n\nTiming is defined with a combination of `duration`, `easings` and `times` properties (see [Props](#props))\n\n<TOC />\n\n## Import\n\n```javascript\nimport { keyframes } from 'popmotion';\n```\n\n## Usage\n\nYou can set the values to animate between with the `values` property. You can set as many values as you wish.\n\n```javascript\nkeyframes({ values: [0, 1, 3] })\n  .start(v => console.log(v))\n```\n\nThe overall length of the animation can be changed via `duration`.\n\nEach individual value can be given a progress value between `0` and `1` via the `times` array. That determines at which point during the animation it should be at the corresponding value.\n\nFinally, and `easings` property maps to the animations between each value transition (so the length of this array is one fewer than our total number of values).\n\n```javascript\nkeyframes({\n  values: [0, 100, 200],\n  times: [0, 0.2, 1],\n  duration: 1000,\n  easings: [ease.linear, ease.cubicBezier(.17,.67,.83,.67)]\n})\n```\n\n### Value types\n\n`keyframes` supports the animation of the following value types:\n\n#### Number\n\n```javascript\nkeyframes({\n  values: [10, 40, 100, -100]\n})\n```\n\n#### Units\n\n**Supported**: `px`, `%`, `deg`, `vh`, and `vw`\n\n```javascript\nkeyframes({\n  values: ['10%', '40%', '100%', '-100%']\n})\n```\n\n#### Colors\n\n**Supported**: RGB(A), HSL(A) and Hex\n\n```javascript\nkeyframes({\n  values: ['#fff', '#000', '#f00']\n})\nkeyframes({\n  values: [\n    'rgba(0, 200, 100, 1)',\n    'rgba(60, 100, 80, 0.5)',\n    'rgba(60, 100, 80, 1)'\n  ]\n})\nkeyframes({\n  values: [\n    'hsl(0, 50%, 50%)',\n    'hsl(180, 80%, 50%)',\n    'hsl(45, 60%, 60%)'\n  ]\n})\n```\n\n#### Complex\n\nComplex sequences of values, like SVG path definitions, CSS shadows and background gradients.\n\nThe non-numerical portions of these values must stay in the same format in the `from` and `to` props.\n\n```javascript\nkeyframes({\n  values: [\n    '0px 0px 0px inset rgba(0, 0, 0, 0.2)',\n    '3px 3px 10px inset rgba(0, 0, 0, 0.5)',\n    '10px 10px 20px inset rgba(0, 0, 0, 0.8)'\n  ]\n})\n```\n\n```javascript\nkeyframes({\n  values: [\n    'linear-gradient(to right, #f00, #0f0)',\n    'linear-gradient(to right, #00f, #f00)',\n    'linear-gradient(to right, #f00, #0f0)'\n  ]\n})\n```\n\n#### Objects\n\nNamed objects composed of any of the above types may also be animated.\n\n```javascript\nkeyframes({\n  values: [\n    { x: 0, background: 'hsla(125, 100, 50, 1)' },\n    { x: 0, background: 'hsla(20, 100, 60, 1)' },\n    { x: 100, background: 'hsla(20, 100, 60, 1)' }\n  ]\n})\n```\n\n#### Arrays\n\nArrays composed of any of the above types may also be animated.\n\n```javascript\nkeyframes({\n  values: [\n    [0, '10vh', 'hsla(125, 100, 50, 1)'],\n    [1, '20vh', 'hsla(20, 100, 60, 1)'],\n    [0, '40vh', 'hsla(125, 100, 50, 1)']\n  ]\n})\n```\n\n## Props\n\nThe following properties may be passed to `keyframes`:\n\n### values\n\nAn array of values to animate between.\n\n**Required**\n\n### duration\n\nTotal duration of animation, in milliseconds.\n\n**Default:** `300`\n\n### easings\n\nAn array of easing functions for each generated tween, or a single easing function applied to all tweens. This array should be `values.length - 1`.\n\n**Default** `[...easeOut]`\n\n### times\n\nAn array of numbers between `0` and `1`, representing `0` to `duration`, that represent at which point each number should be hit. Defaults to an array of evenly-spread durations.\n\n### elapsed\n\nDuration of animation already elapsed, in milliseconds.\n\n**Default:** `0`\n\n### ease\n\nA function, given a progress between `0` and `1`, that returns a new progress value. Used to affect the rate of playback across the duration of the **overall** animation.\n\n**Default:** `linear`\n\n### loop\n\nNumber of times to loop animation on `complete`. Set as `Infinity` to loop forever.\n\n**Default:** 0\n\n### flip\n\nNumber of times to flip animation on `complete`. Set as `Infinity` to flip forever.\n\n**Default:** 0\n\n### yoyo\n\nNumber of times to reverse animation on `complete`. Set as `Infinity` to reverse forever.\n\n**Default:** 0\n\n## Methods\n\n### Action methods\n\n`keyframes()` returns:\n\n`tween()` returns:\n\n#### start\n\nStarts the animation and returns playback controls.\n\nCan be provided **either** a function:\n\n```javascript\nkeyframes().start(v => {})\n```\n\nOr a named map of functions for `update` and `complete`:\n\n```javascript\nkeyframes().start({\n  update: v => {},\n  complete: () => {}\n})\n```\n\n#### filter\n\nReturns a new version of the animation, that filters out any value when the provided predicate function returns `false`:\n\n```javascript\nconst filtered = keyframes().filter(v => v > 0.5)\n\n// This animation will only output values higher than 0.5:\nfiltered.start(v => {})\n```\n\n#### pipe\n\nReturns a new animation that will pass any output value through this series of functions:\n\n```javascript\n// This animation will round output values and then double them:\nkeyframes()\n  .pipe(Math.round, v => v * 2)\n  .start(v => {})\n```\n\n#### while\n\nReturns a new animation that will `complete` when the provided predicate function returns `false`:\n\n```javascript\n// This animation will end when an output value is higher than 0.5:\nkeyframes().while(v => v < 0.5)\n```\n\n### Playback methods\n\n`keyframes().start()` starts a new animation and returns the following playback methods:\n\n#### getElapsed\n\nReturns time elapsed in milliseconds.\n\n#### getProgress\n\nReturns animation progress as a value of `0`-`1`.\n\n#### seek\n\nSeeks animation to this position as a value of `0`-`1`.\n\n```javascript\nconst playback = keyframes().start(v => {})\n\nplayback.seek(0.5)\n```\n\n#### pause\n\nPauses playback.\n\n#### resume\n\nResumes playback.\n\n#### reverse\n\nReverses the direction of playback.\n\n#### stop\n\nStops the animation.\n\n## Example\n\n<CodePen id=\"JOZGdp\" />\n"
  },
  {
    "path": "packages/popmotion/docs/api/animation/physics.md",
    "content": "---\ntitle: Physics\ndescription: Integrated simulation of velocity, acceleration, friction and springs.\ncategory: animation\n---\n\n# Physics\n\nSimulate velocity, acceleration, friction and springs.\n\nThis is an integrated simulation, meaning the latest state is incorporated at discrete time intervals. It exposes `set` methods that change the simulation while it's running.\n\nThis is unlike the differential equations in [decay](/api/decay) and [spring](/api/spring), which can't be changed while in motion (although both offer higher-accuracy simulations which lead to smoother animations).\n\n<TOC />\n\n## Import\n\n```javascript\nimport { physics } from 'popmotion';\n```\n\n## Usage\n\nWe can simulate a consistent velocity by providing the `velocity` property. Values are output to the function provided to `start`:\n\n```javascript\nphysics({ from: 0, velocity: 1000 })\n  .start(v => console.log(v))\n```\n\nTo slow the velocity down over time, we can provide a `friction` value between `0` (no friction) and `1` (dead stop):\n\n```javascript\nphysics({\n  from: 0,\n  velocity: 1000,\n  friction: 0.8\n})\n```\n\nTo put speed back in the system we can use `acceleration`, measured in units per second:\n\n```javascript\nphysics({\n  from: 0,\n  velocity: 1000,\n  acceleration: 200\n})\n```\n\nTo simulate a spring, we add `to` and `springStrength` values:\n\n```javascript\nphysics({\n  from: 0,\n  velocity: 1000,\n  friction: 0.8,\n  to: 400,\n  springStrength: 500\n})\n```\n\n### Value types\n\n`physics` supports the animation of a number of different value types.\n\n#### Number\n\n```javascript\nphysics({ from: 0, velocity: 100 })\n```\n\n#### Units\n\n**Supported**: `px`, `%`, `deg`, `vh`, and `vw`\n\n```javascript\nphysics({ from: '0px', velocity: 100 })\n```\n\n#### Objects\n\nNamed objects composed of any of the above types may also be animated.\n\n`friction`, `acceleration`, `velocity` and `springStrength` can also be set as objects, to apply property-specific settings:\n\n```javascript\nphysics({\n  from: { x: '0px', y: '0px' },\n  velocity: { x: 200, y: 1000 }\n})\n```\n\n#### Arrays\n\nArrays composed of any of the above types may also be animated.\n\n`friction`, `acceleration`, `velocity` and `springStrength` can also be set as arrays, to apply property-specific settings:\n\n```javascript\nphysics({\n  from: ['10vh', 0],\n  velocity: [100, 100]\n})\n```\n\n## Props\n\nThe following properties may be passed to `physics`:\n\n### velocity\n\nVelocity in units per second.\n\n**Default:** `0`\n\n### from\n\nStart simulation from this number.\n\n**Default:** `0`\n\n### acceleration\n\nIncrease `velocity` by this amount every second.\n\n**Default:** `0`\n\n### restSpeed\n\nWhen absolute speed drops below this value, `complete` is fired.\n\n**Default:** `0.001`\n\n### friction\n\nAmount of friction to apply per frame, from `0` to `1`.\n\n**Default:** `0`\n\n### springStrength\n\nIf set with `to`, will spring towards target with this strength.\n\n**Default:** `0`\n\n### to\n\nIf set with `springStrength`, will gradually \"spring\" towards this value.\n\n**Default:** `0` \n\n## Methods\n\n### Action methods\n\n`physics()` returns:\n\n#### start\n\nStarts the animation and returns playback controls.\n\nCan be provided **either** a function:\n\n```javascript\nphysics().start(v => {})\n```\n\nOr a named map of functions for `update` and `complete`:\n\n```javascript\nphysics().start({\n  update: v => {},\n  complete: () => {}\n})\n```\n\n#### filter\n\nReturns a new version of the animation, that filters out any value when the provided predicate function returns `false`:\n\n```javascript\nconst filtered = physics().filter(v => v > 0.5)\n\n// This animation will only output values higher than 0.5:\nfiltered.start(v => {})\n```\n\n#### pipe\n\nReturns a new animation that will pass any output value through this series of functions:\n\n```javascript\n// This animation will round output values and then double them:\nphysics({ from: 0, velocity: 100 })\n  .pipe(Math.round, v => v * 2)\n  .start(v => {})\n```\n\n#### while\n\nReturns a new animation that will `complete` when the provided predicate function returns `false`:\n\n```javascript\n// This animation will end when an output value is higher than 0.5:\nphysics().while(v => v < 0.5)\n```\n\n### Playback methods\n\n`physics().start()` starts a new animation and returns the following playback methods:\n\n#### set\n\nChange the current value.\n\n#### setAcceleration\n\nSet `acceleration`.\n\n#### setFriction\n\nSet `friction`.\n\n#### setSpringStrength\n\nSet `springStrength`.\n\n#### setSpringTarget\n\nSet `to`.\n\n#### setVelocity\n\nSet `velocity`.\n\n#### stop\n\nStops the animation.\n\n## Example\n\n<CodePen id=\"ooybYP\" />\n"
  },
  {
    "path": "packages/popmotion/docs/api/animation/spring.md",
    "content": "---\ntitle: Spring\ndescription: Accurate, versatile spring animation.\ncategory: animation\n---\n\n# Spring\n\nA spring animation based on `stiffness`, `damping` and `mass`.\n\nThis simulation offers smoother motion and a greater variety of spring-feels than the basic spring simulation found in [physics](/api/physics).\n\nIt's based on the same equations underlying Apple's `CASpringAnimation`.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { spring } from 'popmotion';\n```\n\n## Usage\n\n`spring` accepts a `from` and `to` value, and will output values to the function provided to `start`:\n\n```javascript\nspring({ from: 0, to: 100 })\n  .start(v => console.log(v))\n```\n\nPass props like `damping`, `stiffness` and `mass` to affect the character of the spring:\n\n```javascript\nspring({\n  from: 0,\n  to: 100,\n  stiffness: 200,\n  damping: 20\n})\n```\n\n### Value types\n\n`spring` supports the animation of a number of different value types.\n\nIt's generally best output as values that govern physical movement, like `x`, `y` and `rotate`, but it can be used to power colors and shadows.\n\n#### Number\n\n```javascript\nspring({ from: 0, to: 100 })\n```\n\n#### Units\n\n**Supported**: `px`, `%`, `deg`, `vh`, and `vw`\n\n```javascript\nspring({ from: '0px', to: '100px' })\n```\n\n#### Colors\n\n**Supported**: RGB(A), HSL(A) and Hex\n\n```javascript\nspring({ from: '#fff', to: '#000' })\nspring({ from: 'rgba(0, 200, 100, 1)', to: 'rgba(60, 100, 80, 0.5)' })\nspring({ from: 'hsl(0, 50%, 50%)', to: 'hsl(180, 80%, 50%)' })\n```\n\n#### Complex\n\nComplex sequences of values, like SVG path definitions, CSS shadows and background gradients.\n\nThe non-numerical portions of these values must stay in the same format in the `from` and `to` props.\n\n```javascript\nspring({\n  from: '0px 0px 0px inset rgba(0, 0, 0, 0.2)',\n  to: '3px 3px 10px inset rgba(0, 0, 0, 0.5)'\n})\n```\n\n```javascript\nspring({\n  from: 'linear-gradient(to right, #fff, #000)',\n  to: 'linear-gradient(to right, #333, #666)'\n})\n```\n\n#### Objects\n\nNamed objects composed of any of the above types may also be animated.\n\n`velocity`, `mass`, `damping` and `stiffness` can also be set as objects, to apply property-specific settings:\n\n```javascript\nspring({\n  from: { x: '0px', y: '0px' },\n  to: { x: '100px', y: '200px' },\n  stiffness: { x: 200, y: 1000 },\n  damping: { x: 10, y: 50 }\n})\n```\n\n#### Arrays\n\nArrays composed of any of the above types may also be animated.\n\n`velocity`, `mass`, `damping` and `stiffness` can also be set as arrays, to apply property-specific settings:\n\n```javascript\nspring({\n  from: ['10vh', 0],\n  to: ['50vh', 100],\n  stiffness: [400, 1000]\n})\n```\n\n## Props\n\nThe following properties may be passed to `spring`:\n\n### from\n\nStart value of the animation.\n\n**Default:** `0`\n\n### to\n\nEnd value of the animation.\n\n**Default:** `1`\n\n### stiffness\n\nStiffness of the spring. Higher values will create more sudden movement.\n\n**Default:** `100`\n\n### damping\n\nStrength of opposing force. If set to `0`, spring will oscillate indefinitely.\n\n**Default:** `10`\n\n### mass\n\nMass of the moving object. Higher values will result in more lethargic movement.\n\n**Default:** `1`\n\n### velocity\n\nInitial velocity of the object, measured in units per second.\n\n**Default:** `0`\n\n### restDelta\n\nEnd animation if distance to `to` is below this value **and** speed is below `restSpeed`. When animation ends, spring gets \"snapped\" to `to`.\n\n**Default:** `0.01`\n\n### restSpeed\n\nEnd animation if absolute speed (in units per second) drops below this value **and** delta is smaller than `restDelta`.\n\n**Default:** `0.01`\n\n## Methods\n\n### Action methods\n\n`spring()` returns:\n\n#### start\n\nStarts the animation and returns playback controls.\n\nCan be provided **either** a function:\n\n```javascript\nspring().start(v => {})\n```\n\nOr a named map of functions for `update` and `complete`:\n\n```javascript\nspring().start({\n  update: v => {},\n  complete: () => {}\n})\n```\n\n#### filter\n\nReturns a new version of the animation, that filters out any value when the provided predicate function returns `false`:\n\n```javascript\nconst filtered = spring().filter(v => v > 0.5)\n\n// This animation will only output values higher than 0.5:\nfiltered.start(v => {})\n```\n\n#### pipe\n\nReturns a new animation that will pass any output value through this series of functions:\n\n```javascript\n// This animation will round output values and then double them:\nspring({ from: 0, to: 100 })\n  .pipe(Math.round, v => v * 2)\n  .start(v => {})\n```\n\n#### while\n\nReturns a new animation that will `complete` when the provided predicate function returns `false`:\n\n```javascript\n// This animation will end when an output value is higher than 0.5:\nspring().while(v => v < 0.5)\n```\n\n### Playback methods\n\n`spring().start()` starts a new animation and returns the following playback methods:\n\n#### stop\n\nStops the animation.\n\n## Example\n\n<CodePen id=\"mqKyjd\" />\n"
  },
  {
    "path": "packages/popmotion/docs/api/animation/timeline.md",
    "content": "---\ntitle: Timeline\ndescription: Sequence a multitrack animation with full playback controls.\ncategory: animation\n---\n\n# Timeline\n\nTimeline is used to script complex sequences of animation, split across independent tracks.\n\nIf offers all the same playback options as a [`tween`](/api/tween).\n\n<TOC />\n\n## Import\n\n```javascript\nimport { timeline } from 'popmotion';\n```\n\n## Usage\n\n### Create a sequence of animations\n\n`timeline` accepts an array of playhead instructions.\n\nA playhead instruction can be an animation, array of animations for parallel or staggered execution, or a timestamp.\n\n#### Animation\n\nEach animation is defined as an object. This looks a lot like a simplified `tween`, with `from`, `to`, `duration` and `ease` properties:\n\n```javascript\ntimeline([\n  { track: 'x', from: 0, to: 300, duration: 1000 }\n])\n```\n\nThere's a **required** property called `track`. No two animations should overlap that share the same `track` label, and `timeline` will output every track to the function given to `start` together as an object:\n\n```javascript\ntimeline([\n  { track: 'x', from: 0, to: 300, duration: 1000 }\n]).start(v => console.log(v.x))\n```\n\n#### Sequencing\n\nIf we provide a second animation, it will (by default) play **after** the first:\n\n```javascript\ntimeline([\n  { track: 'x', from: 0, to: 300, duration: 1000 },\n  { track: 'y', from: 0, to: 300 }\n])\n```\n\nIn this example animation, the second animation will start after `1000` milliseconds, as that's when the first ends (as defined by `duration`).\n\n#### Timestamps\n\nWe can, however, move the playhead from that default position. If we provide a number as the next instruction, the playhead will move to that position.\n\nIn this example, the second animation will start after `500` milliseconds:\n\n```javascript\ntimeline([\n  { track: 'x', from: 0, to: 300, duration: 1000 },\n  500,\n  { track: 'y', from: 0, to: 300 }\n])\n```\n\nIf we instead provide a string, we can move the playhead **relative** to the current timestamp with either `'-'` or `'+'` instructions. For instance, this time the second animation will start after `800` milliseconds:\n\n```javascript\ntimeline([\n  { track: 'x', from: 0, to: 300, duration: 1000 },\n  '-200',\n  { track: 'y', from: 0, to: 300 }\n])\n```\n\n#### Parallel and stagger\n\nAnimations can be played in parallel, from the same point in time, by providing them in an array.\n\nIn this example, both animations provided after the first animation will play after `1000`ms:\n\n```javascript\ntimeline([\n  { track: 'x', from: 0, to: 300, duration: 1000 },\n  [\n    { track: 'x', to: 0 },\n    { track: 'y', from: 0, to: 300 }\n  ]\n])\n```\n\nIf we provide a number as the last item in the array, `timeline` will stagger over all the other items in the array with this delay:\n\n```javascript\ntimeline([\n  { track: 'x', from: 0, to: 300, duration: 1000 },\n  [\n    { track: 'x', to: 0 },\n    { track: 'y', from: 0, to: 300 },\n    50\n  ]\n])\n```\n\n### Value types\n\n`timeline` supports the animation of the following value types:\n\n#### Number\n\n```javascript\ntimeline([\n  { track: 'x', from: 0, to: 100 }\n])\n```\n\n#### Units\n\n**Supported**: `px`, `%`, `deg`, `vh`, and `vw`\n\n```javascript\ntimeline([\n  { track: 'x', from: '0%', to: '100%' }\n])\n```\n\n#### Colors\n\n**Supported**: RGB(A), HSL(A) and Hex\n\n```javascript\ntimeline([\n  { track: 'backgroundColor', from: '#fff', to: '#f00' }\n])\n```\n\n#### Complex\n\nComplex sequences of values, like SVG path definitions, CSS shadows and background gradients.\n\nThe non-numerical portions of these values must stay in the same format in the `from` and `to` props.\n\n```javascript\ntimeline([\n  {\n    track: 'boxShadow',\n    from: '0px 0px 0px inset rgba(0, 0, 0, 0.2)',\n    to: '3px 3px 10px inset rgba(0, 0, 0, 0.5)'\n  }\n])\n```\n\n#### Objects\n\nNamed objects composed of any of the above types may also be animated.\n\n```javascript\ntimeline([\n  {\n    track: 'ball',\n    from: {\n      backgroundColor: '#f00',\n      x: 0\n    },\n    to: {\n      backgroundColor: '#fff',\n      x: 100\n    }\n  }\n])\n```\n\n#### Arrays\n\nArrays composed of any of the above types may also be animated.\n\n```javascript\ntimeline([\n  {\n    track: 'ball',\n    from: [0, '10vh'],\n    to: [0, '0vh']\n  }\n])\n```\n\n## Props\n\nThe following props can be passed as the second argument to timeline:\n\n```javascript\ntimeline(playlist, props)\n```\n\n### duration\n\nTotal duration of animation, in milliseconds.\n\n**Default:** `300`\n\n### elapsed\n\nDuration of animation already elapsed, in milliseconds.\n\n**Default:** `0`\n\n### ease\n\nA function that, given a progress between `0` and `1`, will return a new progress value. Used to affect the speed of playback across the duration of the animation.\n\nIf `from` and `to` are set as objects or arrays, `ease` may be set with a corresponding structure to apply a unique easing for each animating value.\n\n**Default:** `easeOut`\n\n### loop\n\nNumber of times to loop animation on `complete`. Set as `Infinity` to loop forever.\n\n**Default:** 0\n\n### flip\n\nNumber of times to flip animation on `complete`. Set as `Infinity` to flip forever.\n\n**Default:** 0\n\n### yoyo\n\nNumber of times to reverse animation on `complete`. Set as `Infinity` to reverse forever.\n\n**Default:** 0\n\n## Methods\n\n### Action methods\n\n`timeline()` returns:\n\n#### start\n\nStarts the animation and returns playback controls.\n\nCan be provided **either** a function:\n\n```javascript\ntimeline().start(v => {})\n```\n\nOr a named map of functions for `update` and `complete`:\n\n```javascript\ntimeline().start({\n  update: v => {},\n  complete: () => {}\n})\n```\n\n#### filter\n\nReturns a new version of the animation, that filters out any value when the provided predicate function returns `false`:\n\n```javascript\nconst filtered = timeline().filter(v => v.x > 0.5)\n\n// This animation will only output values higher than 0.5:\nfiltered.start(v => {})\n```\n\n#### pipe\n\nReturns a new animation that will pass any output value through this series of functions:\n\n```javascript\ntimeline()\n  .pipe(v => v)\n  .start(v => {})\n```\n\n#### while\n\nReturns a new animation that will `complete` when the provided predicate function returns `false`:\n\n```javascript\n// This animation will end when an output value is higher than 0.5:\ntimeline().while(v => v.x < 0.5)\n```\n\n### Playback methods\n\n`timeline().start()` starts a new animation and returns the following playback methods:\n\n#### getElapsed\n\nReturns time elapsed in milliseconds.\n\n#### getProgress\n\nReturns animation progress as a value of `0`-`1`.\n\n#### seek\n\nSeeks animation to this position as a value of `0`-`1`.\n\n```javascript\nconst playback = tween().start(v => {})\n\nplayback.seek(0.5)\n```\n\n#### pause\n\nPauses playback.\n\n#### resume\n\nResumes playback.\n\n#### reverse\n\nReverses the direction of playback.\n\n#### stop\n\nStops the animation."
  },
  {
    "path": "packages/popmotion/docs/api/animation/tween.md",
    "content": "---\ntitle: Tween\ndescription: Animate between two values over a set duration of time.\ncategory: animation\n---\n\n# Tween\n\nAnimate between two values over a set duration of time.\n\nThe behaviour and feel of the animation can be affected by providing a different [easing](/api/easing) function.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { tween } from 'popmotion';\n```\n\n## Usage\n\nBy default, `tween` will tween from `0` to `1` over `300` milliseconds, with `easeOut` easing, and will output values to the function provided to `start`:\n\n```javascript\ntween()\n  .start(v => console.log(v))\n```\n\nPass props to adjust the character of the tween:\n\n```javascript\ntween({ to: 200, duration: 500 })\n```\n\n### Value types\n\n`tween` supports the animation of the following value types:\n\n#### Number\n\n```javascript\ntween({ from: 0, to: 1 })\n```\n\n#### Units\n\n**Supported**: `px`, `%`, `deg`, `vh`, and `vw`\n\n```javascript\ntween({ from: '0px', to: '100px' })\n```\n\n#### Colors\n\n**Supported**: RGB(A), HSL(A) and Hex\n\n```javascript\ntween({ from: '#fff', to: '#000' })\ntween({ from: 'rgba(0, 200, 100, 1)', to: 'rgba(60, 100, 80, 0.5)' })\ntween({ from: 'hsl(0, 50%, 50%)', to: 'hsl(180, 80%, 50%)' })\n```\n\n#### Complex\n\nComplex sequences of values, like SVG path definitions, CSS shadows and background gradients.\n\nThe non-numerical portions of these values must stay in the same format in the `from` and `to` props.\n\n```javascript\ntween({\n  from: '0px 0px 0px inset rgba(0, 0, 0, 0.2)',\n  to: '3px 3px 10px inset rgba(0, 0, 0, 0.5)'\n})\n```\n\n```javascript\ntween({\n  from: 'linear-gradient(to right, #fff, #000)',\n  to: 'linear-gradient(to right, #333, #666)'\n})\n```\n#### Objects\n\nNamed objects composed of any of the above types may also be animated.\n\n`ease` can also be set as an object, to apply property-specific [easing](/api/easing):\n\n```javascript\ntween({\n  from: {\n    x: 0,\n    background: 'hsla(125, 100, 50, 1)'\n  },\n  to: {\n    x: 100,\n    background: 'hsla(20, 100, 60, 1)'\n  },\n  ease: {\n    x: easeOut,\n    background: linear\n  }\n})\n```\n\n#### Arrays\n\nArrays composed of any of the above types may also be animated.\n\n`ease` can also be set as an array, to apply property-specific [easing](/api/easing):\n\n```javascript\ntween({\n  from: [0, '10vh', 'hsla(125, 100, 50, 1)'],\n  to: [1, '20vh', 'hsla(20, 100, 60, 1)'],\n  ease: [easeOut, backOut, linear]\n})\n```\n\n## Props\n\nThe following properties may be passed to `tween`:\n\n### from\n\nStart value of the animation.\n\n**Default:** `0`\n\n### to\n\nEnd value of the animation.\n\n**Default:** `1`\n\n### duration\n\nTotal duration of animation, in milliseconds.\n\n**Default:** `300`\n\n### elapsed\n\nDuration of animation already elapsed, in milliseconds.\n\n**Default:** `0`\n\n### ease\n\nA function that, given a progress between `0` and `1`, will return a new progress value. Used to affect the speed of playback across the duration of the animation.\n\nIf `from` and `to` are set as objects or arrays, `ease` may be set with a corresponding structure to apply a unique easing for each animating value.\n\n**Default:** `easeOut`\n\n### loop\n\nNumber of times to loop animation on `complete`. Set as `Infinity` to loop forever.\n\n**Default:** 0\n\n### flip\n\nNumber of times to flip animation on `complete`. Set as `Infinity` to flip forever.\n\n**Default:** 0\n\n### yoyo\n\nNumber of times to reverse animation on `complete`. Set as `Infinity` to reverse forever.\n\n**Default:** 0\n\n## Methods\n\n### Action methods\n\n`tween()` returns:\n\n#### start\n\nStarts the animation and returns playback controls.\n\nCan be provided **either** a function:\n\n```javascript\ntween().start(v => {})\n```\n\nOr a named map of functions for `update` and `complete`:\n\n```javascript\ntween().start({\n  update: v => {},\n  complete: () => {}\n})\n```\n\n#### filter\n\nReturns a new version of the animation, that filters out any value when the provided predicate function returns `false`:\n\n```javascript\nconst filtered = tween().filter(v => v > 0.5)\n\n// This animation will only output values higher than 0.5:\nfiltered.start(v => {})\n```\n\n#### pipe\n\nReturns a new animation that will pass any output value through this series of functions:\n\n```javascript\n// This animation will round output values and then double them:\ntween({ from: 0, to: 100 })\n  .pipe(Math.round, v => v * 2)\n  .start(v => {})\n```\n\n#### while\n\nReturns a new animation that will `complete` when the provided predicate function returns `false`:\n\n```javascript\n// This animation will end when an output value is higher than 0.5:\ntween().while(v => v < 0.5)\n```\n\n### Playback methods\n\n`tween().start()` starts a new animation and returns the following playback methods:\n\n#### getElapsed\n\nReturns time elapsed in milliseconds.\n\n#### getProgress\n\nReturns animation progress as a value of `0`-`1`.\n\n#### seek\n\nSeeks animation to this position as a value of `0`-`1`.\n\n```javascript\nconst playback = tween().start(v => {})\n\nplayback.seek(0.5)\n```\n\n#### pause\n\nPauses playback.\n\n#### resume\n\nResumes playback.\n\n#### reverse\n\nReverses the direction of playback.\n\n#### stop\n\nStops the animation.\n\n## Example\n\n<CodePen id=\"WXOPWX\" />\n"
  },
  {
    "path": "packages/popmotion/docs/api/calc.md",
    "content": "---\ntitle: Calculators\ndescription: Simple functions useful in UI calculations.\n---\n\nMoved to [Popcorn](/popcorn)"
  },
  {
    "path": "packages/popmotion/docs/api/compositors/chain.md",
    "content": "---\ntitle: Chain\ndescription: Chain a sequence of actions, move to the next when the current one completes.\ncategory: compositors\n---\n\n# Chain\n\nChain a sequence of actions, move to the next when the current one completes.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { chain } from 'popmotion';\n```\n\n## Usage\n\n```javascript\nchain(\n  tween({ to: 300 }),\n  spring({ from: 300, to: 0 })\n).start({\n  update: (v) => console.log(v),\n  complete: () => console.log('All actions complete')\n})\n```\n\n## Methods\n\n### Action methods\n\n`chain()` returns:\n\n- `filter((v: any) => boolean)`: Returns a new action that filters out values when the provided function returns `false`.\n- `pipe(...funcs: Array<(v) => v)`: Returns a new action that will run `update` values through this sequence of functions.\n- `start(update | { update, complete })`: Starts the action and returns a subscription.\n- `while((v: any) => boolean)`: Returns a new action that will `complete` when the provided function returns `false`.\n\n\n### Subscription methods\n\n`chain().start()` returns:\n\n- `stop(): void`\n"
  },
  {
    "path": "packages/popmotion/docs/api/compositors/composite.md",
    "content": "---\ntitle: Composite\ndescription: Control a map of actions and output to that same structure.\ncategory: compositors\n---\n\n# Composite\n\nControl a named map of actions, and output to the same structure.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { composite } from 'popmotion';\n```\n\n## Usage\n\n```javascript\ncomposite({\n  x: tween({ from: 60, to: 400 }),\n  y: physics({ from: 60, velocity: 300 })\n}).start(({ x, y }) => {});\n```\n\n`composite` outputs at most once per frame.\n\n## Methods\n\n### Action methods\n\n`composite()` returns:\n\n- `filter((v: any) => boolean)`: Returns a new action that filters out values when the provided function returns `false`.\n- `pipe(...funcs: Array<(v) => v)`: Returns a new action that will run `update` values through this sequence of functions.\n- `start(update | { update, complete })`: Starts the action and returns a subscription.\n- `while((v: any) => boolean)`: Returns a new action that will `complete` when the provided function returns `false`.\n\n### Subscription methods\n\n`composite().start()` returns:\n\n- `stop(): void`\n\n**Note:** If all actions return the same API, for instance all composed actions are `tween`s, the `composite` subscription will also return a version of that API that controls all child actions.\n"
  },
  {
    "path": "packages/popmotion/docs/api/compositors/crossfade.md",
    "content": "---\ntitle: Crossfade\ndescription: Fade between two numerical actions.\ncategory: compositors\n---\n\n# Crossfade\n\nFade between two numerical actions.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { crossfade } from 'popmotion';\n```\n\n## Usage\n\nExample: blend from one tween to another:\n\n```javascript\nconst blendTweens = crossfade(\n  tween({ from: 0, to: 500, elapsed: 200 }),\n  tween({ from: 500, to: 0 })\n).start((v) => console.log(v));\n\ntween({ duration: 100 }).start(blendTweens.setBalance);\n```\n\n## Methods\n\n### Action methods\n\n`crossfade()` returns:\n\n- `filter((v: any) => boolean)`: Returns a new action that filters out values when the provided function returns `false`.\n- `pipe(...funcs: Array<(v) => v)`: Returns a new action that will run `update` values through this sequence of functions.\n- `start(update | { update, complete })`: Starts the action and returns a subscription.\n- `while((v: any) => boolean)`: Returns a new action that will `complete` when the provided function returns `false`.\n\n\n### Subscription methods\n\n`crossfade().start()` returns:\n\n- `setBalance(): this`: Sets the balance of blended output from the first action (`0`) to the second (`1`).\n- `stop(): void`\n\n## Example\n\n<CodePen id=\"ooPjxj\" />\n"
  },
  {
    "path": "packages/popmotion/docs/api/compositors/delay.md",
    "content": "---\ntitle: Delay\ndescription: Fires complete after the defined interval.\ncategory: compositors\n---\n\n# Delay\n\nFires `complete` after the defined interval.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { delay } from 'popmotion';\n```\n\n## Usage\n\n```javascript\ndelay(100).start({\n  complete: () => console.log('complete!')\n});\n```\n\nUseful for delaying actions in a `chain`.\n\n```javascript\nchain(\n  delay(100),\n  tween({ to: 400, duration: 500 })\n);\n```\n\n### Action methods\n\n`delay()` returns:\n\n- `start(update | { update, complete })`: Starts the action and returns a subscription.\n\n### Subscription methods\n\n`delay().start()` returns:\n\n- `stop(): void`\n"
  },
  {
    "path": "packages/popmotion/docs/api/compositors/merge.md",
    "content": "---\ntitle: Merge\ndescription: Combine multiple actions into one output.\ncategory: compositors\n---\n\n# Merge\n\nCombine multiple actions into one output.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { merge } from 'popmotion';\n```\n\n## Usage\n\n```javascript\nmerge(\n  tween(),\n  action(({ update }) => update(1)),\n  physics({ velocity: 1000 })\n).start((v) => console.log(v));\n```\n\n## Methods\n\n### Action methods\n\n`merge()` returns:\n\n- `filter((v: any) => boolean)`: Returns a new action that filters out values when the provided function returns `false`.\n- `pipe(...funcs: Array<(v) => v)`: Returns a new action that will run `update` values through this sequence of functions.\n- `start(update | { update, complete })`: Starts the action and returns a subscription.\n- `while((v: any) => boolean)`: Returns a new action that will `complete` when the provided function returns `false`.\n\n\n### Subscription methods\n\n`merge().start()` returns:\n\n- `stop(): void`\n\n"
  },
  {
    "path": "packages/popmotion/docs/api/compositors/parallel.md",
    "content": "---\ntitle: Parallel\ndescription: Control multiple actions in parallel and output as an array.\ncategory: compositors\n---\n\n# Parallel\n\nControl an n-dimensional array of actions in parallel, and output as an array.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { parallel } from 'popmotion';\n```\n\n## Usage\n\n```javascript\nparallel(\n  tween({ from: 40, to: 50 }),\n  spring({ to: 500 })\n).start(([ tweenOutput, springOutput ]) => {});\n```\n\n`parallel` outputs max once per frame.\n\n## Methods\n\n### Action methods\n\n`parallel()` returns:\n\n- `filter((v: any) => boolean)`: Returns a new action that filters out values when the provided function returns `false`.\n- `pipe(...funcs: Array<(v) => v)`: Returns a new action that will run `update` values through this sequence of functions.\n- `start(update | { update, complete })`: Starts the action and returns a subscription.\n- `while((v: any) => boolean)`: Returns a new action that will `complete` when the provided function returns `false`.\n\n### Subscription methods\n\n`parallel().start()` returns:\n\n- `stop(): void`\n\n**Note:** If all actions return the same API, for instance all composed actions are `tween`s, the `parallel` subscription will also return a version of that API that controls all child actions.\n"
  },
  {
    "path": "packages/popmotion/docs/api/compositors/schedule.md",
    "content": "---\ntitle: Schedule\ndescription: Use an action to control the output of another.\ncategory: compositors\n---\n\n# Schedule\n\n`schedule` can use one action to control the output of another.\n\nFor instance, by default `pointer` outputs only when the pointer updates.\n\nWith `schedule`, you could compose it with `everyFrame` to output the latest `pointer` value every frame.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { schedule } from 'popmotion';\n```\n\n## Usage\n\n```typescript\nschedule(scheduler: Action, subject: Action): Action\n```\n\n```javascript\n// `pointer` will output at most once every frame\nschedule(\n  everyFrame(),\n  pointer()\n).start(({ x, y }) => {});\n```\n\n## Methods\n\n### Action methods\n\n`schedule()` returns:\n\n- `filter((v: any) => boolean)`: Returns a new action that filters out values when the provided function returns `false`.\n- `pipe(...funcs: Array<(v) => v)`: Returns a new action that will run `update` values through this sequence of functions.\n- `start(update | { update, complete })`: Starts the action and returns a subscription.\n- `while((v: any) => boolean)`: Returns a new action that will `complete` when the provided function returns `false`.\n\n### Subscription methods\n\n`schedule().start()` returns:\n\n- `stop(): void`\n\n"
  },
  {
    "path": "packages/popmotion/docs/api/compositors/stagger.md",
    "content": "---\ntitle: Stagger\ndescription: Stagger the execution of a series of actions.\ncategory: compositors\n---\n\n# Stagger\n\nStagger the execution of a series of actions.\n\n<TOC />\n\n## Import \n\n```javascript\nimport { stagger } from 'popmotion';\n```\n\n## Usage\n\n```typescript\nstagger(actions: Action[], interval: number | (i: number) => number): Action\n```\n\n`stagger` accepts two arguments, an array of actions and an `interval`:\n\n```javascript\nstagger([\n  tween(),\n  spring()\n], 100)\n```\n\nWhen started, it outputs the values as an array. Actions that haven't yet started will output `undefined`, and you can define a default.\n\n```javascript\nstagger([\n  tween(),\n  spring()\n], 100).start((values) => values.forEach((v = 0, i) => {\n  console.log(v);\n}))\n```\n\n## Methods\n\n### Action methods\n\n`stagger()` returns:\n\n- `filter((v: any) => boolean)`: Returns a new action that filters out values when the provided function returns `false`.\n- `pipe(...funcs: Array<(v) => v)`: Returns a new action that will run `update` values through this sequence of functions.\n- `start(update | { update, complete })`: Starts the tween and returns a subscription.\n- `while((v: any) => boolean)`: Returns a new action that will `complete` when the provided function returns `false`.\n\n### Subscription methods\n\n`stagger().start()` returns:\n\n- `stop(): void`\n\n"
  },
  {
    "path": "packages/popmotion/docs/api/easing.md",
    "content": "---\ntitle: Easing\ndescription: Functions that speed or slow a tween over time.\n---\n\n# Easing\n\nEasing functions make tweened motion look more natural by emulating the changes in velocity experienced by objects in the real world.\n\nThey work by accepting a progress value from `0` to `1`, and returning a new one.\n\nThere's a seperate Popmotion package for easing:\n\n<TOC />\n\n## Import\n\n```\nnpm install @popmotion/easing\n```\n\n```javascript\nimport { linear } from '@popmotion/easing';\n```\n\n## Example\n\n```javascript\nimport { tween, easing } from 'popmotion';\nimport { easeOut } from '@popmotion/easing';\n\ntween({\n  ease: easeOut\n}).start();\n```\n\n## Presets\n\nPopmotion comes with the following preset easing functions:\n\n- `cubicBezier`\n- `linear`\n- `easeIn`, `easeOut`, `easeInOut`\n- `circIn`, `circOut`, `circInOut`\n- `backIn`, `backOut`, `backInOut`\n- `anticipate`\n\nTry them out by editing this live example:\n\n```marksy\n<Example template=\"Ball\" id=\"b\">{`\nconst ball = document.querySelector('#b .ball');\nconst ballStyler = styler(ball);\n\ntween({\n  to: 300,\n  duration: 300,\n  ease: linear\n}).start(ballStyler.set('x'));\n`}</Example>\n```\n\n## Easing creation\n\nPopmotion provides the following functions to create your own easing functions:\n\n### cubicBezier\n\nCreates cubic bezier curve easing function.\n\n```javascript\nconst { cubicBezier } = easing;\nconst longTail = cubicBezier(0, .42, 0, 1);\n```\n\n### reversed\n\nAccepts an easing function and returns a new one that reverses the provided one.\n\nFor instance, an `easeIn` would become an `easeOut`.\n\n```javascript\nconst { anticipate, reversed } = easing;\nconst anticipateOut = reversed(anticipate);\n```\n\n### mirrored\n\nAccepts an easing function and returns a new one that mirrors the provided one. \n\nFor instance, an `easeIn` would become an `easeInOut`.\n\n```javascript\nconst { anticipate, mirrored } = easing;\nconst anticipateInOut = mirrored(anticipate);\n```\n\n### createExpoIn\n\nCreates an easing function based on the exponent function `progress ** exponent`. `easeIn` is `createExpoIn(2)`.\n\n```javascript\nconst { createExpoIn } = easing;\nconst strongerEaseIn = createExpoIn(3);\n```\n\n### createBackIn\n\nCreates an easing function with an overshoot. `backIn` is `createBackIn(1.525)`.\n\n```javascript\nconst { createBackIn, reversed } = easing;\nconst strongerBackOut = reversed(createBackIn(3));\n```\n\n### createAnticipateEasing\n\nCreates an easing function with a small anticipate and ease out. `anticipate` is `createAnticipateEasing(1.525)`.\n\n```javascript\nconst { createAnticipateEasing } = easing;\nconst strongerAnticipate = createAnticipateEasing(3);\n```\n"
  },
  {
    "path": "packages/popmotion/docs/api/faqs.md",
    "content": "---\ntitle: FAQs\ndescription: Popmotion frequently asked questions\n---\n\n# FAQs\n\n<TOC />\n\n## Browser support?\n\nPopmotion supports all major browsers.\n\nFor legacy IE11 support, the following polyfills are required:\n\n- [String.endsWith](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith#Polyfill)\n\n- [WeakSet](https://github.com/dy/weakset)\n\n## Filesize?\n\nAs of version 8.3.4, Popmotion is **12kb**.\n"
  },
  {
    "path": "packages/popmotion/docs/api/framesync.md",
    "content": "---\ntitle: Framesync\ndescription: Schedule functions to run at specific steps on the render loop.\n---\n\n# Framesync\n\nA tiny frame scheduler for performantly batching reads, updates and renders.\n\nSegregating actions that read and write to the DOM will avoid [layout thrashing](https://developers.google.com/web/fundamentals/performance/rendering/avoid-large-complex-layouts-and-layout-thrashing).\n\nIt's also a way of ensuring order of execution across a frame. For instance, Popmotion batches updates on the `update` step, and Stylefire batches renders on the `render` step, allowing independent animation of `transform` properties.\n\n<TOC />\n\n## Install\n\n```bash\nnpm install framesync\n```\n\n## Usage\n\nFramesync splits a frame into discrete `read`, `update`, `render` and `postRender` steps.\n\n### Scheduling functions\n\nFunctions can be scheduled to different parts of the render loop with `sync`.\n\n```javascript\nimport sync from 'framesync';\n```\n\nIt provides four functions, one for scheduling a function to run on each part of the frame:\n\n```javascript\nsync.update(() => {});\n```\n\n### Frame data\n\nEach function is provided data about the current frame:\n\n```javascript\nsync.update({ delta, timestamp }) => {});\n```\n\n- `delta`: Time since last frame (in milliseconds)\n- `timestamp`: Timestamp of the current frame.\n\nThis object is recycled across frames, so values should be destructured if intended to be used asynchronously.\n\n### Keep alive\n\nWe can run a function as an ongoing process by passing `true` as the second parameter:\n\n```javascript\nlet count = 0;\n\nsync.update(() => count++, true);\n```\n\nThis will keep the process running until it's actively cancelled.\n\n### Run immediately\n\nThe third parameter, `immediate`, can be used to sync a function on the **current frame step**.\n\nBy default, Framesync will schedule functions to run the next time that frame step is fired:\n\n```javascript\nsync.update(({ timestamp }) => {\n  // The following function will run on the subsequent frame:\n  sync.update((frame) => frame.timestamp !== timestamp);\n});\n```\n\nBy setting `immediate` to `true`, we can add this at the end of the current step:\n\n```javascript\nsync.update(({ timestamp }) => {\n  // The following function will run on the **current** frame:\n  sync.update(\n    (frame) => frame.timestamp === timestamp,\n    false,\n    true\n  );\n});\n```\n\n### Cancelling\n\nSynced processes can be cancelled with the `cancelSync` function:\n\n```javascript\nimport sync, { cancelSync } from 'framesync';\n\nlet count = 0;\n\nconst process = sync.render(() => {\n  count++;\n  if (count >= 10) cancelSync.render(process);\n}, true);\n```\n"
  },
  {
    "path": "packages/popmotion/docs/api/input/listen.md",
    "content": "---\ntitle: Listen\ndescription: Creates a DOM event listener as an action stream.\ncategory: input\n---\n\n# Listen\n\n`listen` creates DOM event listeners as an action stream.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { listen } from 'popmotion';\n```\n\n## Usage\n\nTo listen to an event, provide a DOM element and an event name to `listen`:\n\n```javascript\nlisten(document, 'mousemove')\n  .start((e) => console.log(e));\n```\n\n### Multiple events\n\nMultiple events can be subscribed to by providing a space-delimited string:\n\n```javascript\nlisten(document, 'touchstart touchend')\n```\n\n### Chainable actions\n\nThe primary benefit of using `listen` is passing each event through the chainable actions like `filter`. For instance, here's an event listener that only fires when two or more touches are detected:\n\n```javascript\nconst onMultitouch = listen(document, 'touchstart')\n  .filter(({ touches }) => touches.length > 1);\n\nonMultitouch.start((e) => ...);\n```\n\n### Options\n\n`listen` optionally accepts a third argument of options:\n\n```typescript\ntype EventOpts = boolean | {\n  capture?: boolean;\n  passive?: boolean;\n  once?: boolean;\n};\n\nlisten(element: Element, eventNames: string, opts?: EventOpts): Action\n```\n\n## Methods\n\n### Action methods\n\n`listen()` returns:\n\n- `filter((v: any) => boolean)`: Returns a new action that filters out values when the provided function returns `false`.\n- `pipe(...funcs: Array<(v) => v)`: Returns a new action that will run `update` values through this sequence of functions.\n- `start(update | { update, complete })`: Starts the action and returns a subscription.\n- `while((v: any) => boolean)`: Returns a new action that will `complete` when the provided function returns `false`.\n\n### Subscription methods\n\n`listen().start()` returns:\n\n- `stop(): void`\n"
  },
  {
    "path": "packages/popmotion/docs/api/input/multitouch.md",
    "content": "---\ntitle: Multitouch\ndescription: Tracks multitouch input.\ncategory: input\n---\n\n# Multitouch\n\nTracks multitouch input and outputs a list of active touches, plus scale and rotation delta between the first two touch points.\n\nFor single-point input, generally [pointer](/api/pointer) is more appropriate as it provides a simple, cross-platform interface.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { multitouch } from 'popmotion';\n```\n\n## Usage\n\n```typescript\nmultitouch({\n  preventDefault?: boolean = true,\n  scale?: number,\n  rotate?: number\n})\n```\n\n```javascript\nmultitouch().start(({ touches, scale, rotate }) => {\n  touches.forEach(({ x, y }) => console.log(x, y))\n});\n```\n\n`multitouch` provides:\n\n- `touches: { x: number, y: number }[]`: An array of `x`/`y` coordinates representing each active finger.\n- `scale: number`: The distance between the first two fingers since `start`, represented as a multiplier of the original distance. `scale` starts from `1.0`, or the initially provided `scale`.\n- `rotate: number`: The angle rotation of the first two fingers as a delta of the original rotation. `rotate` starts from `0.0`, or the initially provided `rotate`.\n\n### Commonly-used properties\n\nIf you often use, for instance, `rotate`, you can easily create a new action that returns only that value:\n\n```javascript\nconst touchRotation = (initialRotate = 0) => multitouch({ rotate: initialRotate })\n  .pipe(({ rotate }) => rotate);\n\ntouchRotation(45).start((rotate) => console.log(rotate));\n```\n\n## Props\n\n- `preventDefault?: boolean = true`\n- `scale?: number = 1.0`\n- `rotate?: number = 0.0`\n\n## Methods\n\n### Action methods\n\n`multitouch()` returns:\n\n- `filter((v: any) => boolean)`: Returns a new action that filters out values when the provided function returns `false`.\n- `pipe(...funcs: Array<(v) => v)`: Returns a new action that will run `update` values through this sequence of functions.\n- `start(update | { update, complete })`: Starts the action and returns a subscription.\n- `while((v: any) => boolean)`: Returns a new action that will `complete` when the provided function returns `false`.\n\n### Subscription methods\n\n`multitouch().start()` returns:\n\n- `stop(): void`\n\n## Example\n\n<CodePen id=\"LOBjxQ\" />\n"
  },
  {
    "path": "packages/popmotion/docs/api/input/pointer.md",
    "content": "---\ntitle: Pointer\ndescription: Outputs the screen position of a single mouse or touch point.\ncategory: input\n---\n\n# Pointer\n\nOutputs the screen position of a single mouse or touch point.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { pointer } from 'popmotion';\n```\n\n## Usage\n\n### Absolute position\n\n```javascript\npointer()\n  .start(({ x, y }) => console.log(x, y));\n```\n\n### Relative position\n\nProvide initial `x` and `y` properties to output pointer movement **applied to this initial point**.\n\nThis is useful for dragging motion.\n\n```javascript\npointer({ x: 200, y: 175 })\n  .start(({ x, y }) => console.log(x, y));\n```\n\nReactions are provided the following pointer data:\n\n- `x`, `y`: Alias of `clientX` / `clientY`, or \n- `clientX`, `clientY`: Position relative to the viewport.\n- `pageX`, `pageY`: Position relative to the document.\n\n## Props\n\n- `preventDefault: boolean = true`\n- `x?: number`: If defined, apply pointer `y` movement to this number.\n- `y?: number`: If defined, apply pointer `y` movement to this number.\n\n## Methods\n\n### Action methods\n\n`pointer()` returns:\n\n- `filter((v: any) => boolean)`: Returns a new action that filters out values when the provided function returns `false`.\n- `pipe(...funcs: Array<(v) => v)`: Returns a new action that will run `update` values through this sequence of functions.\n- `start(update | { update, complete })`: Starts the action and returns a subscription.\n- `while((v: any) => boolean)`: Returns a new action that will `complete` when the provided function returns `false`.\n\n### Subscription methods\n\n`pointer().start()` returns:\n\n- `stop(): void`\n\n## Example\n\n<CodePen id=\"RjBZoe\" />\n"
  },
  {
    "path": "packages/popmotion/docs/api/reactions/multicast.md",
    "content": "---\ntitle: Multicast\ndescription: A reaction that multiple reactions can subscribe to.\ncategory: reactions\n---\n\n# Multicast\n\nThe multicast reaction provides a reaction that many other reactions can `subscribe` to.\n\nIt also helps manage actions: if a `multicast` reaction is passed to another `action`, the first `action` will automatically `stop`.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { multicast } from 'popmotion';\n```\n\n## Usage\n\n### Subscription\n\nProvide a reactions to `mulitcast.subscribe()`:\n\n```javascript\nconst foo = multicast();\nfoo.subscribe((v) => console.log('first subscriber', v));\nfoo.subscribe((v) => console.log('second subscriber', v));\n```\n\nWhen the multicast reaction is `update`d, all listeners will fire:\n\n```javascript\nfoo.update(5);\n// first subscriber, 5\n// second subscriber, 5\n```\n\n### Automatically stop previous action\n\nPassing the multicast reaction to a new action will stop the previous one:\n\n```javascript\ntween().start(foo);\nspring().start(foo); // This will stop `tween`\n```\n\n### Chain methods\n\n`multicast` can be chained in the same way as [actions](/api/action).\n\n```javascript\nconst double = (v) => v * 2;\nconst px = (v) => v + 'px';\n\nconst foo = multicast().pipe(double, px);\n\nfoo.update(5); // 10px\n```\n\n### Unsubscribe\n\n`subscribe` returns an `unsubscribe` method:\n\n```javascript\nconst foo = multicast();\nconst sub = foo.subcribe(console.log);\n\nsub.unsubscribe();\n```\n\n## Methods\n\n### Multicast methods\n\n`multicast()` returns:\n\n- `filter((v: any) => boolean)`: Returns a new action that filters out values when the provided function returns `false`.\n- `pipe(...funcs: Array<(v) => v)`: Returns a new reaction that will run `update` values through this sequence of functions.\n- `subscribe(update | { update, complete, error })`: Returns a subscription.\n- `stop()`: Stops current parent action.\n- `while((v: any) => boolean)`: Returns a new reaction that will `complete` when the provided function returns `false`.\n\n### Subscription methods\n\n`multicast().subscribe()` returns:\n\n- `unsubscribe()`\n"
  },
  {
    "path": "packages/popmotion/docs/api/reactions/value.md",
    "content": "---\ntitle: Value\ndescription: Track value state and query velocity\ncategory: reactions\n---\n\n# Value\n\nA [multicast reaction](/api/multicast) that tracks the state of a number and allows velocity queries.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { value } from 'popmotion';\n```\n\n## Usage\n\n```typescript\nvalue(initialValue, onUpdate);\n```\n\n```javascript\nimport { tween, value } from 'popmotion';\nimport styler from 'stylefire';\n\nconst div = styler(document.querySelector('div'));\nconst divX = value(0, div.set('x'));\n\ntween({ to: 500 }).start(divX);\n\nsetTimeout(() => console.log(() => {\n  physics({\n    velocity: divX.getVelocity()\n  }).start(divX); // This will automatically `stop` the tween\n}), 150);\n```\n\n`value` can also handle objects and arrays:\n\n```javascript\nconst foo = value({ x: 0, y: 0 });\nconst bar = value([0, 0]);\n\nfoo.getVelocity(); // { x: 0, y: 0 }\nbar.getVelocity(); // [0, 0]\n```\n\nAs a multicast reaction, you can optionally `subscribe` with multiple other reactions rather than providing an initial subscription:\n\n```javascript\nconst foo = value(0);\nfoo.subscribe(() => console.log('first reaction'));\nfoo.subscribe(() => console.log('second reaction'));\n```\n\n## Methods\n\n### Reaction methods\n\n`value()` returns:\n\n- `get(): number`: Returns the current value state.\n- `getVelocity: number`: Returns the current value velocity.\n- `filter((v: any) => boolean)`: Returns a new action that filters out values when the provided function returns `false`.\n- `pipe(...funcs: Array<(v) => v)`: Returns a new reaction that will run `update` values through this sequence of functions.\n- `stop()`: Stops parent action.\n- `subscribe(update | { update, complete })`: Returns a subscription.\n- `while((v: any) => boolean)`: Returns a new reaction that will `complete` when the provided function returns `false`.\n\n### Subscription methods\n\n`value().subscribe()` returns:\n\n- `unsubscribe(): void`\n"
  },
  {
    "path": "packages/popmotion/docs/api/transformers.md",
    "content": "---\ntitle: Transformers\ndescription: Simple composable functions that take a value and return a new one.\n---\n\nMoved to [Popcorn](/popcorn)"
  },
  {
    "path": "packages/popmotion/docs/blog/20170703-choosing-a-default-easing-for-popmotion.md",
    "content": "---\ntitle: Choosing the correct default easing for Popmotion\ndescription: \"Why I settled on easeOut for Popmotion's default easing, and why easeInOut sucks for interfaces\"\npublished: 20170703\n---\n\n# Choosing the correct default easing for Popmotion\n\nChoosing default values for a library is difficult. Should you be the benefactor/victim of a wider audience:\n\n- These defaults will be used, often unwittingly, by your consumers.\n- You can change them only at the risk of breaking other people's stuff.\n\nIn a motion engine, these choices manifest themselves in a visual and visceral way. A duration here, a spring tightness there.\n\nThis means there's responsibility to choose values intelligently, so that the little patches of the web that use your library benefit from more responsive motion.\n\nAs the userbase of Popmotion is relatively small, I've always felt comfortable shirking the shackles of API stability until I finally felt like it had arrived at a the Good Place. Apologies to anyone who's lived that.\n\nLuckily, over the years of wildly oscillating GitHub activity graphs,\nthere has been one (one) decision that I felt like I got right at the start: Making the `tween` default easing property `easeOut`.\n\n![An example of a sweet easeOut, generated with Ceaser @ matthewlein.com/ceaser](/guides/ease-out-example.png)\n\n## A brief history of timing\n\nLike many greying front end devs, my first exposure to UI animation was [Greensock's](https://greensock.com) then-ActionScript library, TweenMax. For a platform so disposed to garish show-off loading screen animations, Flash animations were disgusting to hand code unless you were using TweenMax.\n\nAnd that's largely what we used it for: showy animations. The Flash days were as over-the-top and as divorced from the user's interests as the Amiga demoscene. All you wanted to do was play your cracked version of Worms but first you had to sit through the seizure-inducing cock-prancing of some git in Norwich. At least Flash intros occasionally had a skip button.\n\n![This, but flashing, and scrolling, and waving. Forever](/guides/amiga-demoscene.png)\n\nGreensock, in its sunrise years, had the right intentions. It did, and still to this day, has an `easeOut` as default. That's because the author understands, despite our hedonism and heathenism, that animation in UI design **should** be as a result of a user's action. `easeOut` is snappy, and as we'll see later, \"snappy\" is how we should respond to user actions.\n\nFlash died, and the community collectively denied any involvement.\n\n![\"Honestly never heard of it. Like Gordon?\"](/guides/flash-gordon.jpg)\n\nThen it was all about jQuery. jQuery was incredible for literally **everything**, which in the new world of composable asynchronous micropackages is probably why we again collectively deny any involvement, and why I'm talking about it in the past tense even while it's standing **right there**, watching us.\n\nFor me, and maybe for you, the coolest thing about jQuery was `animate`. It was amazing to easily get something resembling movement in humble HTML. Even if it defaulted to `swing` easing, a tepid, muddy `easeInOut` of homeopathic strength.\n\nThat easing was coupled with a default duration of `400`ms. Then that was folded into our neanderthal, performance-ignorant tweening of the CPU-choking, layout-breaking `width` and `height` properties. Lethargic animation ruled the internet.\n\n![Feels like a good idea at the time](/guides/ease-in-out-example.png)\n\n## The problem with `easeInOut`\n\nTo arrive at an actual point, the problem with `easeInOut` is that it **feels** incredibly slow. When we [watch videos about the principles of animation](https://vimeo.com/93206523), one of the things we're taught is that objects in motion don't start in motion and they don't stop dead.\n\nThey start slow, and end slow.\n\nSo that sounds about right, we think, and then we stop thinking, and use `easeInOut` by choice, or a framework like jQuery makes it default, and then everyone uses it, by default, and everything feels sluggish, by default. Why?\n\n## Why\n\nOur eyes and brain are hardwired to detect motion. We've evolved to find that motion distracting. Motion indicates that the present situation has changed, and we need to react if we'd prefer to survive. We **need** motion to be distracting.\n\nWhen you're scrolling through a website, and a space opens for an advert in the middle of your article, and everything jumps around, and then after a couple of seconds your crap, overpriced \"4G\" connection finally loads the banner ad, which animates on loop, until you scroll past it, when it then needlessly closes, god I hate Motherboard, your text jumps back up, you think of the poor bastard forced to make it, their hopes, their dreams, their broken dreams - all of those things are distracting.\n\nThat motion, the things causing it: They're not imparting useful information, they're not even trying to kill you. So it's annoying.\n\nIt's all shit, the user isn't involved in any of this, he's happy about the broken dreams. And yet, `easeInOut` is entirely appropriate, it is the least damaging easing to use for uninstigated animation, it is the right choice.\n\nWhat does it say about an easing that **this** is a good use case for it?\n\n## It's sometimes okay, I guess\n\nA **very** tiny amount of uninstigated motion is fine in a UI, as long as it correctly indicates that **the situation has changed, and the user needs to react**. A small \"new message\" dot, probably. Or a notification panel, possibly.\n\nFor this kind of animation, an `easeInOut` or `anticipate` is very appropriate because it gives the user a little bit of time to acclimatise to the movement, and it stops quite gently, naturally. It adheres to the principles of animation, these dots and panels now feel a little more real, your UI a little more alive.\n\nIt's certainly better than things just flicking around the page without the user understanding what's changed.\n\n## But usually it very much isn't\n\nThe **vast majority** of animation in UI is, or should be, user instigated.\n\nFor these animations, these interactions, the user already knows that an action has taken place. **They** started the motion, and the situation has changed, and the UI needs to react. The \"in\" of an `easeIn` or `easeInOut` feels sluggish in this instance because for god's sake hurry up, get on with it.\n\nThe energy and momentum of `easeInOut` starts in the virtual reality and stays there. The energy and momentum `easeOut`, conversely, starts in the user's reality and ends in the interface's.\n\nIt takes the user's energy, directly from their finger, through the wire or screen, straight into the button, the tooltip, the whatever, and bursts with the maximum energy at that initial moment of contact.\n\n`easeInOut` is barely bothered to get out of bed, like a stupid stroppy teenager who probably doesn't even have a finger. Probably.\n\nA user will feel that difference, even if it's subconscious, even if I have to pretend to myself that deep down they **know**, just to justify the hours of my life I've spent writing (and now writing about) animations.\n\nThis is why Greensock comes with `easeOut` by default. It's why [Anime.js](http://animejs.com/) uses a zinger `elasticOut`. And it's why Popmotion uses `easeOut` too.\n\nWhereas, CSS transitions default to the `swing`-alike `ease`, which is exactly as bland as it sounds. Worse, the native Web Animations API uses `linear` easing, which is, frankly, a fucking crime.\n\n![Blood at crime scene. Yawn.](/guides/ease-linear-example.png)\n\n## Feel it for yourself\n\nHere's `easeInOut`.\n\n```marksy\n<Example template=\"Ball\" id=\"a\">{`\nconst ball = document.querySelector('#a .ball');\nconst ballRenderer = styler(ball);\n\ntween({\n  to: 300,\n  duration: 500,\n  ease: easing.easeInOut\n}).start((x) => ballRenderer.set('x', x));\n`}</Example>\n```\n\nBuuuuuuurrrrr. END ME.\n\nConversely, here's an `easeOut` with the Popmotion default of `300`ms.\n\n```marksy\n<Example template=\"Ball\" id=\"b\">{`\nconst ball = document.querySelector('#b .ball');\nconst ballRenderer = styler(ball);\n\ntween({\n  to: 300,\n  ease: easing.easeOut\n}).start((x) => ballRenderer.set('x', x));\n`}</Example>\n```\n\nI. Am. Blushing.\n\nNotice that when you press start on these examples, you're pressing the button yet it's the ball that's moving. Even with this physical disconnect, the first example feels like you're **telling** the ball to move, and then it moves of its own accord. Whereas the second example, you're **making** the ball move, it's using **your** energy.\n\nIt makes a difference! Users can tell.\n\nIt does. It makes a difference.It does.Userscantellitmakesadifferencepleasemakeadifferenceuserscantell\n\n---\n\n[Get started with Popmotion](/learn/get-started)\n"
  },
  {
    "path": "packages/popmotion/docs/blog/20170704-manually-set-scroll-while-ios-momentum-scroll-bounces.md",
    "content": "---\ntitle: How to manually set scrollTop during an iOS momentum bounce\ndescription: Why does existence hurt so much\npublished: 20170804\n---\n\n# How to manually set scrollTop during an iOS momentum bounce\n\nHere's one to file under [the mobile is web is awful](/blog/20170710-mobile-web-is-awful-and-were-all-to-blame).\n\nI've been writing a Slack-esque chat that lazy-loads new messages as you scroll up. The adventure of reliably anchoring scroll position as these new messages are added to the DOM is probably a blog post in itself, but there's a specific issue on iOS that I'd like to share solution to.\n\n## The problem\n\nHere's the code to restore a previous scroll position, (which has to be recalculated to accommodate the newly-loaded messages):\n\n```javascript\nnode.scrollTop = node.scrollHeight - prevScrollTop;\n```\n\nWorks great in every browser, except of course the modern-day IE:\n\n![Knew this wouldn't be so simple](/images/chat-without-hack.gif)\n\nAs you can see, the scroll position stays at the top, almost as if we never manually reset the scroll position at all.\n\nThe problem, as I began to understand, was that if you try and manually set a node's (and probably the viewport's) scroll position **while iOS is doing it's out-of-bounds bouncy thing**, that scroll position will be immediately overridden by the rest of the bounce animation.\n\n## The fix\n\nTo fix, we simply disable momentum scrolling on that element, restore scroll position, and then re-enable momentum scrolling:\n\n```javascript\nnode.style['-webkit-overflow-scrolling'] = 'auto';\nnode.scrollTop = node.scrollHeight - prevScrollTop;\nnode.style['-webkit-overflow-scrolling'] = 'touch';\n```\n\nHere's how that looks:\n\n![Better](/images/chat-with-hack.gif)\n\nNot as graceful as I'd prefer, but looking at the timestamps the user is still left on the correct message. It also avoids funny residual momentum effects, so I presume this technique can also be used to kill scroll momentum when a pointer moves from one overflowing node to another.\n\n---\n\nPopmotion is a 9kb JavaScript motion engine, and it'll give you way less bother than mobile Safari. Create awesome interactions with tweens, physics and input tracking.\n\n[Excite your users with Popmotion](/learn/get-started) and/or [excite us with 140 characters](https://twitter.com/popmotionjs)\n\n"
  },
  {
    "path": "packages/popmotion/docs/blog/20170710-mobile-web-is-awful-and-were-all-to-blame.md",
    "content": "---\ntitle: The mobile web is awful, and everyone's to blame\ndescription: From browser vendors to front end developers, everyone is implicated in the state of the mobile web.\npublished: 20170710\n---\n\n# The mobile web is awful, and everyone's to blame\n\nAt work today, we were discussing the future direction of the website and app. A concern was raised that, without a clear mandate, the website would \"continue to be a great desktop version, and a much poorer version of the app.\"\n\nAs the front end lead, that stung. I felt like the \"much\" was undeserved.\n\nI took the point. It's worth imagining that the use-case of the app and website may well be different.\n\nHowever, the comment came as a response to a mini-moan that it'd taken me a couple hours to get an input field to stick to the bottom of the page and still be tappable in mobile Safari. A simple task made difficult.\n\nIt was an indictment that I haven't yet changed perceptions about the capabilities of the mobile web. Maybe those perceptions don't deserve to be changed.\n\nI've long held that the web experience **can** be just as performant and polished as native. It's only for a lack of time and ambition that it isn't. That belief is the reason I wrote Popmotion in the first place.\n\nSo I began to think, it's usually easy and quite enjoyable to make a great desktop experience. Yet developing for mobile is a constant headache.\n\nWith some mobile Geekbench scores approaching laptops, the technical argument is diminishing. So why?\n\nI realised that everyone is to blame. Browser vendors, Business People, every member of the Google AMP team, you reading this, me writing this: Everyone.\n\n## Browsers Know Best\n\nImplementing simple design features like overlays or bottom navigation on mobile browsers invariably involves trawling through blogs and forums to find that special hack that worked for that one guy that one day in June.\n\nAs every developer knows, no good hack goes unpunished. Testing cross-browser serves a specific cocktail; a nostalgic blend of heart palpitations, dream-like confusion and a palpable sense of impending disappointment. It takes you right back to '99.\n\nIt usually comes down to the same problem. Browsers Know Best. In their infinite wisdom, browser vendors implement novel or specific behaviour, ostensibly to aid performance and accessibility.\n\nIt's a noble aim but developing for browsers is already quite chaotic enough, thankyouverymuch. The absolute last thing the internet needs is more platform-specific behaviour. Let's take a look at some examples.\n\n### Safari\n\nA search for \"Safari is the new IE\" brings up enough results **refuting** that statement that there is, at the very least, a **vibe**.\n\nIt also wouldn't be surprising that a team of self-isolated Apple engineers working out of their space bunker would be susceptible to Browsers Know Best (BKB).\n\nThey've historically dragged their moonboots over implementing new performance-enhancing standards and APIs (like Service Workers), and what progress they do make is diminished by a lethargic release schedule intimately coupled with iOS and macOS.\n\nWhich is fine on desktop because virtually nobody gives a shit about desktop Safari. On mobile, however, the demographics are different, and this holds up progress.\n\n### Bottom navigation\n\nThe behaviour that inspired this 2000-word rant.\n\nNow we live in the future, the outrageous size of phones means they can't be safely touched in their upper halves. Reflecting this shift, design guidelines are increasingly recommending putting app navigation at the bottom of the screen.\n\nExcept, the greedy gits at Apple have colonised the bottom 40-ish pixels and used it as invisible magic space. Touch this, and the app navigation reappears.\n\nIn exchange for this genius piece of UX, you can't put a nav there, or an action button, or a link or or a chat box or whatever.\n\nNo, because we're dirty web peasants, we have to put our nav at the top, where no one can ever reach it. Unless, of course, we resort to the now-canonical hack detailed on [this god-given Eventbrite blog post](https://www.eventbrite.com/engineering/mobile-safari-why/), rightfully titled \"Mobile Safari (Whyyyy?)\". BKB.\n\nOr what do `100%` and `100vh` mean in a viewport that constantly changes and never seems to report the right size? BKB.\n\nOr why is it so difficult to lock page scroll when displaying an overlay, or prevent the page from scrolling to the top when you **do** manage to lock it, or or or. BKB.\n\n### Get over here\n\nChrome isn't blameless, either.\n\nIn Chrome 56, the Chrome team set `touch` events to `{ passive: true }` by default. They [excuse themselves in this blog post](https://developers.google.com/web/updates/2017/01/scrolling-intervention).\n\n`passive: true` allows a developer to reassure the browser that the page will not be calling `e.preventDefault()`, which would block page scroll. This allows the browser to respond immediately to scroll, which at risk of singing its praises, I don't remember ever being an issue in Safari. Is this an Android thing?\n\nEither way, it's broken every instance of a draggable DOM element I've implemented, and every virtual DOM event-handler abstraction like those found in React. Thanks, Chrome team.\n\n### A decade of this\n\nIt's been ten years of this shit.\n\nTake `hover` events. A hover event **obviously** has no place firing on a touch device. Originally though, large parts of the web weren't written as an input-agnostic place. As a result, key functionality was hidden behind hover events.\n\nTo unbreak the web on mobile, browsers starting emulating `hover` on the very `mousedown`-looking `touchstart`.\n\nSo, we end up with very weird interactions, like having to double-tap to open menus that rely on hover. Or CSS hover styles enabling on taps. Or sticky hover states when you're merely trying to scroll the page. Or or or...\n\nIf Apple had the bravery to break Flash websites, where was this bravery with hover interactions? Just break them, stick to a standard, the web will fix itself. \n\nNow, ten years later, we're still stuck with this. Scoping `:hover` effects to special capability classes and yet another esoteric behavior that's difficult to grok and embarrassing to explain to newcomers. \"Well you see, in 2007...\"\n\nBKB.\n\n## Business has feelings too\n\nWhether the interests of business and user are polarised or harmonised is a debate much older than software.\n\nAs a wide-eyed, UX-minded front end dev, I'm predisposed to thinking the latter. I think most people **believe** they are.\n\nInterests are hard to quantify. It's easy, then, for a business person to frame a stat in a way that makes interests look aligned.\n\nIn my own experience it's been an obvious, and incidentally statistical truth, that app users are stickier and more engaged with the product than mobile web users.\n\nSomehow it then leads that it's in the user's interests to be sticky and engaged, which then leads into all manner of poor choices for the mobile web user's experience.\n\n### Reddit\n\nFor example. I have installed two Reddit apps - Alien Blue and the official app. I usually use the desktop web version. Periodically, I'll be mid-surf and it'll be easier to hit the address bar, type \"sta\" and spent the next five minutes browsing the preloaded Star Trek subreddit.\n\nMy point is, as a user, **I'm engaged**. So why is it that I'm occasionally given the ol' mobile fuck you:\n\n![What on earth](/images/reddit-popover.png)\n\nThe USPs are mind-bending.\n\n- **50% faster:** By what metric?\n- **Infinite scrolling:** Infinite scrolling isn't difficult to implement, so why isn't it? Either the devs are lazy and/or incompetent, or much more likely the Business People needed another bullet point to whack on the pop-up and bag themselves a cheeky conversion. So there was a specific choice to make the web version worse.\n- **Autoplay gifs:** BKB.\n\n### Facebook\n\nI had the Facebook app, once. Then, because an analyst got a whiff that Messenger had higher engagement on the stand-alone app, the Business People decided to force users to download that. Once that was downloaded, the analyst got a whiff that users were stickier when push notifications were enabled. So the Business People forced users to turn those on. So I deleted it and used the web instead.\n\nThe mobile messages worked perfectly. I was quite happy not to have Facebook on my phone - despite lacking a messenger, it's half a gig. The mobile site loaded near-instantly with just a couple hundred of progressively downloaded kb.\n\nSniff.\n\n**Sniff.**\n\n![What on earth](/images/facebook-messenger.jpg)\n\nNow, when we click the \"new messages\" icon, we're treated to a splash screen telling us to download Messenger (or we were, there's presently a bug so it does literally nothing). This is purposeful degradation of a perfectly capable website and it is totally anti-user.\n\nIt is wild. I am wild.\n\n## AMP\n\nA lot has been made of the ill-comings of AMP (Accelerated Mobile Pages) recently, so I won't go too deep. My favourite is this [mic drop by The Register](https://www.theregister.co.uk/2017/05/19/open_source_insider_google_amp_bad_bad_bad/).\n\nThe complaints are usually the same; it's proprietary, Google is using you for your content, homogeneous, opaque, maintaining two views. Etc.\n\nIMO the biggest problem is the flagrant abuse of power. Google has a special AMP section at the top of their search results, where AMP results get a nice picture. It's labeled \"Top stories\", but realistically it's just a carousel of sell-outs. Not that you can blame them.\n\nMobile browser usage is, on some sites, far higher than desktop. Yet can you imagine if Google created a special standard for desktop sites and showcased those at the top of their results? There'd be outrage. It'd be a clear power play. But this is just the shitty mobile web, so who cares, right?\n\nNow, there's no denying that AMP pages are faster than the majority of the net and this definitely has some value for the user. AMP isn't magic though, and if a normal site is fast enough to be featured, why not include those, too?\n\nWe can't complain, though. AMP is our fault, yours and mine.\n\n## Mostly you\n\nI'll take a bit of this blame. You can take the rest.\n\nUltimately we're in this position because the mobile web is slow. We develop sites on our fancy Macbook Pros and fiber connections and then serve those sites to low-end Android phones on Edge networks.\n\nWhen we're not being mindful of our user, this is our fault.\n\nOr when we include expansive libraries like Lodash or Moment in their entirety, this is our fault.\n\nOr when we serve a site without server-side rendering, this is our fault.\n\nOr when we don't split our bundles, this is our fault.\n\nOr or or.\n\n## Do we even deserve redemption\n\nJohn Gruber of [Daring Fireball](https://daringfireball.net) has been banging on recently about how JavaScript was a mistake, that the web would load in under a second if it didn't exist.\n\nWell, maybe. It's an interesting thought experiment. Practically, JS does make things slower in the majority of cases. A little bit of power.\n\nWith care, and `fetch`, and code sharding, it can theoretically also make things quicker.\n\nIt can also be the case that a server-side rendered website with a JS payload of 100kb can belt down the network and render **quicker** than a bloated 500mb app can load into memory. There is opportunity here.\n\nThe address bar is an app launcher of power user speeds, and browsers can preload pages while the user is still thinking. No context-switching, or sloshing about with Apple's horrific app search, no need to delete, to arrange.\n\nThere's opportunity here, too.\n\n## Proceed with caution\n\nBrowsers Still Know Best, and keep releasing breaking changes that we have to learn to hack around. Business interests will always inexplicably collide with user interests. Google will always want control.\n\nAnd you'll always be lazy. Me, too, a bit. Mostly you.\n\nLet's be optimistic though. JavaScript, for all Gruber's delicious tears, isn't going anywhere. Nor should it. It's important that there's a democratic and open platform, and in the emerging world of closed devices the **web is it**.\n\nIt's essential this platform remains open, and continues to become more and more capable.\n\nWe're getting WebAssembly, so it'll get faster. WebGL is gaining adoption and we'll see improved AR and VR support, so it'll become more capable.\n\nAlready, we can use tools like Webpack and [bundlesize](https://github.com/siddharthkp/bundlesize) to code split and maintain size budgets.\n\nTools like [Next.js](https://github.com/zeit/next.js/) makes SSR trivial to implement.\n\nHopefully, [Popmotion](/learn/get-started) can help create delightful, high-quality interactions.\n\nWe just need to have the opportunity to create the time and space to dedicate to polish and performance, rather blindly belting along the Business People's feature treadmill. Then next time there won't be a \"much\" in sight.\n\n---\n\nPopmotion is a 9kb JavaScript motion engine. Create awesome interactions with tweens, physics and input tracking.\n\n[Make the mobile web marginally better](/learn/get-started) or [follow us on Twitter](https://twitter.com/popmotionjs)\n"
  },
  {
    "path": "packages/popmotion/docs/blog/20170803-coding-style-dont-be-a-dick.md",
    "content": "---\ntitle: \"Adhering to a project's coding style: Don't be a dick\"\ndescription: \npublished: 20170803\nauthor: Matt Perry\n---\n\n# When it comes to adhering to a project's coding style, follow the golden rule.\n\nI just finished reading Ben Nadel's blog post, titled [After 3 Months Of JavaScript Linting, It's Pretty Much All Pain And No Gain](https://www.bennadel.com/blog/3312-after-3-months-of-javascript-linting-it-s-pretty-much-all-pain-and-no-gain.htm). It makes the argument that linting for maintaining a consistent style is burdensome.\n\nI couldn't disagree more. In fact, I wouldn't disagree more even if the post was titled \"2 plus 2 actually equals 5\", a 500 word rebuttal of a hard, rudimentary, objective fact.\n\nFor both solo, pet projects, and sprawling codebases with multiple contributors, linting for maintaining style is essential.\n\nPopmotion itself is just under 3,000 lines of code, I'm the primary contributor, and linting is useful even to keep just my messy self in check.\n\nIf anything, I'd argue it doesn't go far enough. The number of times I've argued with myself about whether I should declare as a `function` or an arrow function `const`, in different situations, and decided **different things**... I would to deprecate that from my life.\n\nAt work, five of us sit on about 100,000 lines of code. To you, this might be relatively big, or relatively small. It's all relative. Here, linting is one of many tools (types, tests) that have helped keeps us sane, for reasons we'll explore.\n\n> [...] the goal of consistency is a complete charade.\n\nA charade? Well it isn't a charade in the sense that linting does a great job of achieving that goal. To use Ben's own examples, indentation, quotes etc are easily kept consistent. So it's a slightly self-defeating argument.\n\nOne example given is `let` vs `const`. I don't understand how this is stealth-bundled in amongst actual stylistic choices. There is a right way and a wrong way to use these, they have semantic and practical meaning and a linter helps here, too.\n\nBut I suppose his question is, why would you want to? The following quotes are, with varying quantities of melodrama, essentially saying **because I don't want to**.\n\n> [...] my approach to code formatting is the best. If it weren't, I wouldn't use it.\n\nAnd a doozy:\n\n> When I'm asked to change my style, I am - quite literally - asked to deny a fundamental Truth of my being.\n\nMe, I know best, you do it your way, I do it my way. But my way's the best way.\n\nThis attitude simply isn't very team-like. One of the nice things about code consistency is simply the human interaction that leads you to your linting settings. It is team bonding. Not as bonding as oversharing at the pub, but certainly bonding, learning how to compromise and sharing ownership.\n\nWhen we originally set up linting at work, I insisted on semicolons. The team didn't feel strongly either way, fine, semicolons. The team liked two space indentations. Despite my preference for four, I compromised on two. I now like two. And safely refactoring Popmotion to also use two was a simple as changing - yes - my linting config.\n\nOn a more practical note, this discussion settles the argument early. You don't \"ugh\" when you inevitably stumble across four-space indentations and you don't get passive-aggressive PRs back-and-forthing over indentation.\n\nThe thought hurts my brain a little. Are there seriously projects out there where lines are written by Bobbie Two-Spaces, interleaved with heathen lines written by Four-Space Jimmy?\n\nIf we remember to consider that our own stylistic **preferences** are **not** a \"fundamental Truth of [our] being\", we'll immediately arrive at a more collaborative, less combative mindset and thus workplace.\n\nIt's fine. Nobody is dying today.\n\nThe sober point comes a little later:\n\n> [...] code is so much more than indentation and quotation choices.\n\nIt is true that code is an expression, even an artistic one. If the one thing we can all agree on is that indentation and quotation choices are essentially petty, then we won't feel so precious about them and start to trust that our character will come through in the actual solutions we choose and invent.\n\nWe're not selling out through compromise.\n\nIt doesn't make things hard, it doesn't make things painful. It is a collaborative effort and an act of imposed self-discipline. It's the act of letting go of ego, a little, and acting as a team. Because we're not all fucking \"peacocks\". We're just assholes, trying to do something cool.\n\n---\n\nPopmotion is a 9kb JavaScript motion engine, and way better than this daft nonsense. Create awesome interactions with tweens, physics and input tracking.\n\n[Make things lovely](/learn/get-started) and/or [send us your stupid abuse on Twitter](https://twitter.com/popmotionjs)\n\n"
  },
  {
    "path": "packages/popmotion/docs/blog/20171210-popmotion-8-upgrade-guide.md",
    "content": "---\ntitle: Popmotion 8 upgrade guide\ndescription: How to upgrade Popmotion 7 to 8\npublished: 20171210\nauthor: Matt Perry\n---\n\n# Popmotion 8 upgrade guide\n\nThis guide will explain the breaking changes in Popmotion 8 and how to upgrade your project from version 7.\n\n## `onUpdate` and `onComplete`\n\nThe biggest change, from a practical point of view, is the way animations are initialised.\n\nPreviously, a `tween` might have been defined like this:\n\n```javascript\ntween({\n  from: 0,\n  to: 1,\n  onUpdate: (v) => console.log(v)\n}).start();\n```\n\nNow, that `onUpdate` is instead provided to `start`:\n\n```javascript\ntween({ from: 0, to: 1 })\n  .start((v) => console.log(v));\n\n// This is equivalent:\ntween({ from: 0, to: 1 })\n  .start({\n    update: (v) => console.log(v)\n  });\n```\n\nLikewise, `onComplete` also provided to `start`:\n\n```javascript\ntween({\n  from: 0,\n  to: 1\n}).start({\n  update: (v) => console.log(v),\n  complete: () => console.log('complete!')\n})\n```\n\n## Immutable\n\nEach animation, once defined, is immutable. Once `start` is called, a **new instance** of that animation is created and executed. Which means you can define an animation once:\n\n```javascript\nconst foo = tween({ from: 0, to: 1 });\n```\n\nAnd use that definition to power multiple animations:\n\n```javascript\nfoo.start((v) => console.log('first animation', v));\nfoo.start((v) => console.log('second animation', v));\n```\n\n## Playback controls\n\nThis means that `stop`, and other playback controls, aren't returned by `tween`, they're returned from `start`:\n\n```javascript\nconst myTween = foo.start(console.log);\nmyTween.stop();\n```\n\n## `transform` property\n\nPreviously, there was a `transform` property available to actions. It accepted  a pure function that accepted a value and returned a new one.\n\nIn Popmotion, we refer to these as [transformers](/api/transformers). As the API has evolved, its skewed towards using these pure functions to define functionality. Documents increasingly included references to the `pipe` transformer, which composes a new transformer from multiple others.\n\nIn Popmotion 8, `pipe` has been promoted to an action method. When used, it returns **a new version of that action** that pipes all `update` values through the functions given to `pipe`:\n\n```javascript\nconst double = (v) => v * 2;\nconst px = (v) => v + 'px';\n\nconst foo = tween({ from: 0, to: 1 });\nconst bar = foo.pipe(double, px);\n\nfoo.start(console.log); // Ends with 1\nbar.start(console.log); // Ends with '2px'\n```\n\n## Chainable\n\n`pipe` isn't the only chainable functions available to actions. There's also `while` and `filter`, and an API to add new functions will be available in the near future.\n\nHere's a `listen` action, which is our [DOM event listener action](/api/listen), that only fires when it detects more than two `touches`:\n\n```javascript\nlisten(document, 'touchstart')\n  .filter(({ touches }) => touches.length > 1)\n  .start(({ touches }) => {\n    console.log(touches.length); // more than 1\n  });\n```\n\n## `value.set`\n\n`value` is now a **reaction**. Which means you can still pass one to an action like this:\n\n```javascript\nconst foo = value(0, console.log);\nspring({ to: 300 }).start(foo);\n```\n\nAs `start` accepts reactions either as a function or an object with an `update` function, `value.set()` becomes `value.update()`.\n\n## `getVelocity`\n\nPreviously, every action has a `getVelocity` method. In Popmotion 8 I'm attempting to reduce statefulness and move to reactive streams.\n\n`value` is now the only stateful function to offer a `getVelocity` function. It's a special type of reaction that maintains state.\n\n```javascript\nconst ball = document.querySelector('#ball');\nconst ballX = value(0, styler(ball).set('x'));\n\nspring({ to: 400, stiffness: 500 }).start(ballX);\n\nsetTimeout(() => console.log(ballX.getVelocity()), 200);\n```\n\n## Every animation can handle color\n\nThe `colorTween` animation has been replaced by the capability for every animation to handle colors. Even `spring` and `physics`!\n\nSo this:\n\n```javascript\ncolorTween({ from: '#fff', to: '#000' })\n```\n\nIs now this:\n\n```javascript\ntween({ from: '#fff', to: '#000' })\n```\n\n## Every animation can handle arrays and objects\n\nIn Popmotion 7, animation of arrays and objects was achieved via the `parallel` and `composite` actions respectively.\n\nThese functions still exist in order to compose different animations. But when the animations are the same, this syntax has been greatly simplified:\n\n```javascript\nphysics({\n  from: 0,\n  velocity: {\n    x: 100,\n    y: 200\n  }\n}).start(console.log) // Receives { x, y }\n```\n\n`value` can now also be an n-dimensional array or object too, and `value.getVelocity` will return velocities in the defined format.\n\n## `stagger`\n\nAs the `update` method is bound to an animation only when `start` is called, `stagger` now accepts functions that can **optionally** return a started action. So this:\n\n```javascript\nstagger([\n  tween({ onUpdate: (v) => console.log('1st', v) }),\n  tween({ onUpdate: (v) => console.log('2nd', v) })\n], 50).start();\n```\n\nBecomes: \n\n```javascript\nstagger([\n  () => tween().start((v) => console.log('1st', v)),\n  () => tween().start((v) => console.log('2nd', v))\n], 50).start();\n```\n\nThis also means that `stagger` can iterate over any function, not just animations.\n\n## `touch` is now `multitouch`\n\nThe `touch` action has been renamed `multitouch`.\n\nPreviously, it provided `onUpdate` with an array of touches. Now, `touches` is a property that sits alongside `scale` and `rotate` properties:\n\n```javascript\nmultitouch().start(({ touches, scale, rotate }) => {});\n```\n\n## And the rest\n\n- `physics` `spring` property is now `springStrength`.\n- `physics` `autoStopSpeed` property is now `restSpeed`.\n- `spring` `restDisplacement` property is now `restDelta`.\n- `flow` alias for `pipe` has been removed.\n- `add`, `subtract`, `divide`, `multiply`, `conditional`, `alpha`, `percent`, `degrees`, `px`, `rgbUnit`, `rgba`, `hex`, `color`, `hsla` transformers have been removed. Value type transformers like `hex` can still be accessed from the [valueTypes](https://github.com/Popmotion/popmotion/tree/master/packages/style-value-types).\n- Render loop function must be imported separately from [Framesync](https://github.com/Popmotion/framesync)\n\n"
  },
  {
    "path": "packages/popmotion/docs/blog/20171211-introducing-popmotion-8.md",
    "content": "---\ntitle: Introducing Popmotion 8\ndescription: Popmotion 8 is a functional, reactive approach to animation.\npublished: 20171211\nauthor: Matt Perry\n---\n\n# Introducing Popmotion 8\n\nPopmotion 8 is a functional, reactive animation library.\n\nIt's the result of over three months work, the result of wanting to add a humble `pipe` method and instead tumbling down the rabbit hole.\n\nIt introduces new animations: `decay`, `everyFrame`, `keyframes` and `timeline`. It makes input dragging a breeze with our revamped `pointer` and `multitouch` actions.\n\nCrucially, there's a new streamlined, reactive API.\n\nThis new API reflects Popmotion's gradual shift towards functional programming and adopts it as a core part of the design philosophy.\n\nThe result is a small, flexible and composable library that I hope you'll find fun to use. Let's take a look at what's new.\n\n## Animations\n\n### `decay`\n\n`decay` models a form of exponential deceleration to create motion like momentum scrolling on smartphones.\n\nJust provide it `velocity` and `from` properties:\n\n```javascript\ndecay({\n  velocity: 1000,\n  from: 0\n}).start((v) => ...)\n```\n\n<CodePen id=\"Kyewbv\" />\n\nIt also exposes a `modifyTarget` option that provides a functional API for adding features like snap-to-grid.\n\n### `everyFrame`\n\n`everyFrame`, as you might imagine, fires once per frame. It provides the amount of time since it started:\n\n```javascript\neveryFrame().start((timeSinceStart) => ...);\n```\n\nIt's the fundamental driver of every Popmotion animation. We've exposed it because we reckon this kind low-level action will be useful in animations, like porting After Effects expressions:\n\n<CodePen id=\"XzYJvP\" />\n\n### `keyframes`\n\n`keyframes` transitions through a number of states over a set duration of time.\n\nIts API is inspired by Apple's `CAKeyframeAnimation`, which makes it trivial to resize the overall animation:\n\n```javascript\nkeyframes({\n  values: [\n    { x: 0, y: 0 },\n    { x: 100, y: 0 },\n    { x: 100, y: 100 }\n  ],\n  times: [0, 0.3, 1],\n  duration: 1000\n})\n```\n\n<CodePen id=\"JOZGdp\" />\n\n### `timeline`\n\n`timeline` is used to orchestrate more complicated patterns of tweens.\n\nIt supports absolute and relative timestamps, as well as parallel and staggered motion. The output action has all the same playback methods as `tween`, making it fully scrubbable.\n\nIn most animation libraries, the timeline function is a bit of a black box that we chuck setters or selectors into.\n\nAs Popmotion is a reactive library, we label each segment with a `track` property, and that then the latest state gets output as an object with those labels:\n\n```javascript\ntimeline([\n  { track: 'shade', from: 0, to: 1 },\n  '-100',\n  {\n    track: 'modal',\n    from: { y: -100, opacity: 0 },\n    to: { y: 0, opacity: 1 }\n  }\n]).start(({ shade, modal }) => ...)\n```\n\nThis means we can pass the output of timeline through the chainable methods `pipe`, `while` and `filter` (more on those later).\n\nAs timelines become more complicated, maintaining the link between labels and setters can become increasingly difficult, but the trade-off is a timeline that is immutable, composable, pure, and testable.\n\nWe're also experimenting with functions that can take a timeline definition and automatically generate the output reaction.\n\n<CodePen id=\"aEoqEG\" height={400} />\n\n## Input\n\n### `pointer`\n\nThe `pointer` action has been in Popmotion since before it was called Popmotion. But, its API has always been confused making simple tasks like dragging more convoluted than they needed to be.\n\nIn Popmotion 7, `pointer` output its absolute position and it was up to a second action, `trackOffset`, to get the **movement** of `pointer` relative to another point (say, a DOM element).\n\nPopmotion 8 scraps the `trackOffset` action entirely. Now, `pointer` will output its absolute position when used like this:\n\n```javascript\npointer().start(({ x, y }) => ...)\n```\n\n(Also notice how we no longer need to provide `pointer` with a `MouseEvent` or `TouchEvent`.)\n\nTo output that pointer's movement **applied to another point**, we simply need to provide that point as our initial argument:\n\n```javascript\npointer({ x: 0, y: 0 }).start(({ x, y }) => ...)\n```\n\n<CodePen id=\"RjBZoe\" />\n\n### `multitouch`\n\nThanks to the efforts of [Mars](https://twitter.com/marsi), Popmotion has had multitouch support since version 6.\n\nThere are two major changes coming in 8. The first and most apparent is we've changed the name of the action from `touches` to `multitouch` to highlight the second change:\n\nIt no longer outputs just an array of touches. `touches` is joined by `scale` and `rotate` properties:\n\n```javascript\nmultitouch().start(({ touches, scale, rotate }) => ...)\n```\n\n<CodePen id=\"LOBjxQ\" />\n\nLike `pointer`, `multitouch` accepts `scale` and `rotate` arguments and, if defined, will output the **change** in those properties as applied to the given values.\n\n## Reactive API\n\nAt the heart of all these new features is a change in the core building block of all animations, the **action**.\n\nThe `action` function is used to create streams of reactive values. Think of it as an animation-focused, tiny alternative to Rx Observables.\n\nIt looks like this:\n\n```javascript\naction(({ update, complete, error }) => {})\n```\n\nFor a practical example of how `action` works, let's define an function called `just`. It'll return an action that, when started, will fire `update` with the provided value and then `complete`:\n\n```javascript\nconst just = (v) => action(({ update, complete }) => {\n  update(v);\n  complete();\n});\n\njust(2).start(console.log); // 2\n```\n\nEvery time we `start` an action, its initialisation function runs anew, creating a new instance of the action. Because all animations are actions, we can define an animation once:\n\n```javascript\nconst moveRight = tween({ to: 300 });\n```\n\nAnd use it multiple times:\n\n```javascript\nmoveRight.start(console.log); // 0 - 300\nmoveRight.start(console.log); // 0 - 300\n```\n\nActions offer a number of chainable methods (currently `filter`, `pipe` and `while`, with an API for adding more on the way). Each returns a brand new version of the action with the added functionality:\n\n```javascript\nconst double = v => v * 2;\nconst px = v => v + 'px';\n\nconst justTwo = just(2);\n\njustTwo.start(console.log); // 2\n\njustTwo\n  .pipe(double, px)\n  .start(console.log); // '4px'\n```\n\nIn the last 6 months Popmotion has spun out [Framesync](/api/framesync) and [Stylefire](/stylefire) as standalone libraries.\n\nIt's helped me take greater care and consideration over where to draw the lines between the role and responsibilities of various parts of the library and enables people to use the isolated functionality in their own code or libraries.\n\nI can imagine a near-future where actions are spun out as a tiny reactive library, where people can start dabbling with reactive programming outside of animation without the full payload of something the size of Rx.\n\n## And the rest...\n\n### File size and individual imports\n\nPopmotion has always tried to respect your bytes. One of the reasons I wrote it in the first place was a dissatisfaction with the size of existing libraries in comparison to the benefits they provided.\n\nPopmotion 8 is a little bigger than 7 (11.5kb vs 10kb). Though, as such a radical rewrite with so many new features, I think there are efficiencies to be made over the coming months.\n\nIn the meantime, everything in Popmotion is **now available as an individual import**. Which means, if you only want to use (for instance) `spring`, you can import and use that for roughly 2kb. \n\n### Colours and multi-prop animations\n\nIn Popmotion 7, we exposed the ability to animate colours with `colorTween`. Multi-property animations could be composed with the `composite` and `parallel` compositors.\n\nThis has all been streamlined in 8. Every animation can now animate colors, objects, arrays (and objects and arrays of colors!).\n\nIt's as simple as this:\n\n```javascript\ntween({\n  from: { x: 0, color: '#f00' },\n  to: { x: 100, color: '#fff' }\n}).start(({ x, color }) => ...)\n```\n\n## Conclusion\n\nThat's most of what's new in Popmotion 8. Existing users should check out our [upgrade guide](/blog/20171210-popmotion-8-upgrade-guide) to handle breaking changes.\n\nAfter three years of development I'm **finally** happy with the API. I think the reactive model works incredibly well for neatly and declaratively handling streams of values and fits perfectly with the functional approach I was already moving towards.\n\nWith these solid foundations in place, the next logical step feels like exploring a way of describing the properties of UI elements and having motion and interactions derive naturally from that. Like a physically-based rendering for motion.\n\nOnce more down the rabbit hole.\n\n---\n\n[Get started with Popmotion](/learn/get-started)\n"
  },
  {
    "path": "packages/popmotion/docs/blog/20180104-when-ios-throttles-requestanimationframe.md",
    "content": "---\ntitle: When iOS throttles requestAnimationFrame to 30fps\ndescription: In specific situations, iOS throttles rAF to 30fps. Here's when, and why it's wrong.\npublished: 20180104\nauthor: Matt Perry\n---\n\n# When iOS throttles requestAnimationFrame to 30fps\n\n> **TL;DR:** iOS throttles `requestAnimationFrame` to 30fps in cross-origin iframes and low power mode.\n\nYesterday I was looking at the examples on the [Popmotion homepage](https://popmotion.io) with my iPhone. They looked odd, clearly suffering a sluggish stutter, the cruel affliction of (**gasp**) 30 frames per second.\n\nHere's an artificially-throttled example:\n\n<CodePen id=\"dJzaMo\" />\n\nI'd seen this illness once before. If you're looking at the example above on an iOS browser, check out this unthrottled example:\n\n<CodePen id=\"WXOPWX\" />\n\nLooks the same, right? To other readers, this second example runs at a silky 60fps. Animation as the gods intended.\n\nI found that it was only affecting animations running on CodePen. The reason was initially unclear.\n\nI assumed that CodePen itself was doing **something** weird in the background that caused the stuttering. They helpfully pointed me to the Debug View, which runs the pen without the iframe.\n\nIt worked. 60fps on iOS. It wasn't CodePen after all.\n\nMy first discovery:\n\n## iOS throttles `requestAnimationFrame` in iframes\n\nSpecifically, it turns out, **cross-origin iframes**. Which is every CodePen embed, even the ones hosted on CodePen's own site (as the live panel is served on a subdomain).\n\nAs detailed in this [WebKit changelog](https://trac.webkit.org/changeset/215070/webkit), the throttling is cleared once a user interacts with the iframe.\n\nTry it for yourself. If you're on iOS, take a look at the tween animation again:\n\n<CodePen id=\"WXOPWX\" />\n\nThis time, tap anywhere within the frame and watch as the 30fps eye-thrashing is replaced by the soft caress of 60fps.\n\n### But... why?\n\nI haven't found a stated reason for this behaviour. But that doesn't stop semi-educated speculation.\n\nIframes are commonly used for advertising. Adverts are fairly liberal with your CPU cycles. So I imagine the throttling is an attempt to prevent adverts from eating your battery.\n\nThe performance cap is cleared once the user interacts with the iframe and indicates that the advert (or other embedded content) isn't unwelcome.\n\nAn alternative solution might be to throttle iframes that lie outside the current viewport (maybe pause execution entirely), and unthrottle when they enter. This current solution feels heavy-handed.\n\n### The remaining mystery\n\nBack to the present, this didn't explain why the examples on the homepage were stuttering. They're part of the page itself, no iframes.\n\nAs the myriad of known and unknown potential causes flashed before my eyes, a familiar feeling of nausea set in.\n\nStanding on the precipice of a rabbit hole of unknown depth, I began the ritual.\n\nOpened my MacBook. Chrome. Performance tab. Throttled CPU... 60fps.\n\nChecked my partner's phone, same OS, same make and model... 60fps.\n\nGoogled for bugs with iOS 11.2.1 and 30fps rAF... Nothing. What the fuuuuuu...\n\nI stared at my phone, dumbfounded. Maybe I needed to reset my phone. Maybe it was because my phone was the wrong colour. Maybe I simply needed to be kinder to Siri.\n\nLuckily, I saw it, and I knew I'd found the culprit. The nausea lifted. Relief settled:\n\n![Take me from this earth](/images/low-power-mode.png)\n\nLow power mode. Though part of me wouldn't believe it until I toggled it on and off and saw the difference with my own eyes, it made sense.\n\nMy second discovery:\n\n## iOS throttles `requestAnimationFrame` in low power mode\n\nAs detailed in this [WebKit bug](https://bugs.webkit.org/show_bug.cgi?id=168837), iOS throttles `requestAnimationFrame` to 30fps whilst low power mode is active.\n\nI have mixed feelings about this.\n\nFirst, there's no doubt that it's very clever. It is, in the short-term, a boon for users.\n\nIn the long-term, I'm not so sure. I've already covered in detail why the [mobile web is a dreadful platform](https://popmotion.io/blog/20170710-mobile-web-is-awful-and-were-all-to-blame/) to develop for.\n\nThis is yet another unpredictable tributary feeding into a much larger river of unpredictable nonsense that we have to put up with.\n\nThe salmon will get tired. It's a self-perpetuating cycle. Horizons, ambitions and standards will drop. Further emboldening mobile browser vendors to push for clever solutions to improve user experience and degrade the developer one.\n\nOn iOS, the app developers themselves are given the responsibility to [respond to low power mode](https://developer.apple.com/library/content/documentation/Performance/Conceptual/EnergyGuide-iOS/LowPowerMode.html), whereas WebKit still hasn't implemented the [Battery Status API](https://developer.mozilla.org/en-US/docs/Web/API/Battery_Status_API). It's a familiar story, and a shame.\n\nA clever, battery-saving shame.\n\n---\n\nIf you still have any energy left in your tired little salmon fins, make the mobile web an app-quality kinda place with [Popmotion](https://popmotion.io). Alternatively, throw your opinions in my stupid salmon face [on Twitter](https://twitter.com/popmotionjs)\n"
  },
  {
    "path": "packages/popmotion/docs/blog/20180521-pose-2-migration-guide.md",
    "content": "---\ntitle: \"What's new in Pose 2.0\"\ndescription: A quick overview of what's new in Pose and React Pose 2.0, and how to migrate\npublished: 20180529\n---\n\n# What's new in Pose 2.0?\n\nPose and React Pose 2.0 are out now!\n\nThey introduce a simple new API for `transition`, so there's now no requirement to import Popmotion separately for custom transitions.\n\n`transition` can also now accept a named map of values, meaning no more having to check `key` to return different animations.\n\nAs we all know all-too-well, major version increases also mean one thing: All your shit's broke. Just kidding. Only some of your shit's broke.\n\nLet's take a look.\n\n## Transition definitions\n\nUntil now, creating custom transitions involved importing Popmotion animations and manually passing along Pose-generated values like `from`, `to` and `velocity`:\n\n```javascript\nimport { tween, easing } from 'popmotion';\n\nconst config = {\n  visible: {\n    opacity: 0,\n    transition: (props) => tween({\n      ...props,\n      duration: 1000,\n      ease: easing.linear\n    })\n  }\n};\n```\n\nNow, we can simply define `transition` as an object of animation props:\n\n```javascript\nconst config = {\n  visible: {\n    opacity: 0,\n    transition: { duration: 1000, ease: 'linear' }\n  }\n};\n```\n\nNotice that we don't need to import easing functions separately, as Pose provides a collection of named easings. We can even automatically define a cubic bezier easing by providing an array:\n\n```javascript\nease: [.01, .64, .99, .56]\n```\n\nBy default, a transition defined like this will be a [tween](/api/tween). But Pose supports Popmotion's [spring](/api/spring), [keyframes](/api/keyframes), [physics](/api/physics) and [decay](/api/decay) animations too.\n\nWe can switch to one of these by setting `transition.type`:\n\n```javascript\nconst config = {\n  dragEnd: {\n    x: 0,\n    transition: { type: 'spring', stiffness: 1000 }\n  }\n}\n```\n\nOr dynamically set them as a function:\n\n```javascript\nconst config = {\n  dragEnd: {\n    x: 0,\n    transition: ({ velocity }) => velocity < 0\n      ? { type: 'spring', stiffness: 1000 }\n      : { type: 'physics', to: -1000 }\n  }\n}\n```\n\nThere's also some new properties supported by all animations: `round`, `min`, `max` and `delay`. Take a look at the [custom transition tutorial for full details](/pose/learn/custom-transitions).\n\nOf course, for animations that aren't yet possible with the new transition API, these functions can still return Popmotion animations just as before. \n\n## Named transition maps\n\nPreviously, to return different animations for different properties, we had to check the provided `key` property:\n\n```javascript\nconst config = {\n  hidden: {\n    x: -100,\n    opacity: 0,\n    transition: ({ key, ...props }) => (key === 'x')\n      ? spring({ ...props, stiffness: 1000 })\n      : tween({ ...props, duration: 100 })\n  }\n}\n```\n\nInstead, we can now **optionally** define `transition` as a named map, with a `default` prop for a catch-all transition:\n\n```javascript\nconst config = {\n  hidden: {\n    x: -100,\n    opacity: 0,\n    transition: {\n      x: { type: 'spring', stiffness: 1000 },\n      default: { duration: 100 }\n    }\n  }\n}\n```\n\nThese named transitions can also be functions that return dynamic transition definitions or Popmotion animations.\n\nTransition definitions and named transition maps will both be coming to React Native Pose in the near future.\n\n## Migration guide\n\nOf course, with a major version change there's always a breaking change or two. We've started flagging these in advance with deprecation warnings, where possible, so hopefully the impact will be minimal.\n\nHere's what's changed:\n\n### `transitionProps` is now `props`\n\nIn a bit of bikeshedding that should, nonetheless, make the API a little easier to explain, `transitionProps` is now `props`.\n\nWhen they were first introduced, `transitionProps` were used to dynamically generate `transition`s. Now, they can be used to dynamically set any pose prop, hence the change in terminology:\n\n```javascript\nconst config = {\n  open: {\n    x: ({ x }) => x\n  },\n  props: { x: 0 }\n};\n\n// Pose\nconst poser = pose(config);\n\n// React Pose\nconst Posed = posed.div(config);\n() => <Posed x={10} />\n```\n\nThis has also led to the renaming of `setTransitionProps` to `setProps` for the vanilla Pose users in the audience.\n\n### FLIP is now opt-in\n\nPreviously, Pose would detect if you were animating a layout property like `width` or `top` and automatically convert that to a FLIP animation.\n\nAlthough FLIP animations are more performant, if not handled with care they can cause unexpected visual artifacts. We also don't currently have a good strategy for animating to `0` (which makes the \"invert\" stage of FLIP decidedly tricky - what's the inverse of 0?)\n\nThis was one of the most commonly-occurring points of confusion with the API, so I've made it opt-in with `flip: true`:\n\n```javascript\nconst config = {\n  open: {\n    width: '100vw',\n    height: '100vh',\n    flip: true\n  },\n  close: {\n    width: '100px',\n    height: '100px',\n    flip: true\n  }\n}\n```\n\nThe good news is that this shouldn't break any of your code. If left unchanged, Pose will simply animate the layout property, **unless**, as above, you're animating between two different unit types which Pose doesn't currently support (PRs welcome!)\n"
  },
  {
    "path": "packages/popmotion/docs/blog/20180820-introducing-pose-3.md",
    "content": "---\ntitle: Introducing Pose 3.0\ndescription: A look at the latest Pose features, changes, and a hint of what's next\npublished: 20180820\n---\n\n# Introducing Pose 3.0\n\n[Pose 3.0](/pose) is officially out, and with it, some new features! Let's take a look at what's new, what's changed, and what's next.\n\n<TOC />\n\n## New UI events\n\nPose is designed to simplify **both** animations and interactions. But so far, it's only supported dragging.\n\nNow, elements can animate on `hover`, `focus` and `press` too, with code as simple as this:\n\n```javascript\nconst config = {\n  hoverable: true,\n  init: { scale: 1 },\n  hover: { scale: 1.2 }\n};\n```\n\nAs usual, these poses flow through the pose tree. So all children of these posed components will also animate receive these poses, allowing simple coordination of animations across the DOM.\n\nIt also handles some usually finicky logic, which we solve with our new pose resolution logic.\n\n## Pose resolution\n\nImagine an element that is both hoverable and draggable. This sequence of events often happens:\n\n1. User hovers: hover animation plays\n2. User drags: drag animation plays\n3. User hovers out while still dragging: hover out animation plays\n4. User hovers: hover animation plays\n5. User stops dragging: ???\n\nThere's two problems with this flow. The first is that if a user hovers out while still dragging (usually because the UI is updated slower than the pointer), **no** animation should play. The dragging animation should take precedence.\n\nSecond, when dragging stops we should know that the user is still hovering and animate to that state, rather than to an \"at rest\" state. Pose handles this for you:\n\n<CodeSandbox id=\"yqmzz4mz0v\" />\n\nThis is because values can now be in multiple poses at once. Instead of this:\n\n```javascript\n'drag'\n```\n\nWe have this:\n\n```javascript\n['drag', 'hover', 'init']\n```\n\nBecause vanilla and React Pose are configured to prioritise the `'drag'` pose over `'hover'`, if hover is removed and then re-added, it'll always be added **after** drag. So the value will continue to resolve to `'drag'`.\n\nThis also means that when both drag and hover states are removed, the value reverts to whichever pose it was in previously. In this case, that's the new special `'init'` pose (which does what it says on the tin).\n\nThis is in contrast to the more state-machine-like approach previously taken, which expected a constant stream of a new poses.\n\n## Breaking changes\n\nOf course, being a major release, there's breaking changes. This release, it's precautionary. Because we're resolving poses in a new way, it's possible that some of your animations work a little differently. Unlikely, but possible.\n\nAlso, we've changed the special `dragging` pose to just `drag`. This was undocumented, so again this is precautionary, but it's possible I might have let it slip in a CodePen. You can learn how to animate with it, and all the other new event poses, in our new [UI events tutorial](/pose/learn/ui-events/).\n\n## What's next\n\nThe flurry of activity will continue over the coming weeks and months. We've just opened our [new Patreon and Open Collectives](/support/) which will help support Popmotion's continued development.\n\nWe've also just released the long-requested [Pose examples](/pose/examples/) page, which we're going to be filling up with all-new examples.\n\nOn the [features board](https://github.com/Popmotion/popmotion/projects/1) the most requested card is the ability to animate between different value types, and to `auto`.\n\nThere'll also be tutorials, both articles and video, for commonly-requested implementations like carousels and route transitions.\n"
  },
  {
    "path": "packages/popmotion/docs/blog/20180829-pose-3-1-animate-between-anything.md",
    "content": "---\ntitle: \"Pose 3.1: Animate between any unit type\"\ndescription: A look at the latest Pose features, changes, and a hint of what's next\npublished: 20180830\nauthor: mattperry\n---\n\n# Pose 3.1: Animate between any unit type\n\nThis week we released [Pose 3.1](/pose), Animate Between Anything.\n\nIt's a much-requested feature that enables you to animate `x`, `y`, `width`, and `height` between any unit type.\n\nPreviously this capability was only available via FLIP (by setting `flip: true`), but in some cases you may want to be animating `width` and `height` directly. And of course FLIP doesn't work with `x` and `y` transforms.\n\nNow, you can animate `'100vh'` to `'50%'`, or `'calc(50vw - 50%)'` to `0`.\n\n<CodeSandbox id=\"k3qx6p3r55 \" />\n\nYou can also animate `width` and `height` to and from `'auto'`.\n\n<CodeSandbox id=\"pwk5yq8pzx \" />\n\nIt works with any valid CSS style, and the animations themselves happen in pixels so spring animations feel consistent between every transition.\n\nWhen the animation finishes, the defined style is applied. So your designs will continue to be responsive.\n\n## Still to come\n\nThis will probably be the last big new feature for a few weeks. I'll be working on more tutorials and examples, as well as a bug burn down.\n\nI'll also be taking another look at React Native Pose. Compared to Pose, it's still fairly limited.\n\nThis owes in part to the restrictions in the underlying React Animated library. In part, its the difficulty in animating colors, and the ease with which an animation can be delegated to the JavaScript thread.\n\nI'll be looking into potentially porting it to [Reanimated](https://github.com/kmagiera/react-native-reanimated) to enable native-driven gestures, and to try and bring the library to feature-party with Pose.\n"
  },
  {
    "path": "packages/popmotion/docs/blog/20180904-introducing-pose-for-vue.md",
    "content": "---\ntitle: Introducing Pose for Vue\ndescription: An introduction to the declarative animation library for Vue\npublished: 20180409\nauthor: mattperry\n---\n\n# Introducing Pose for Vue\n\nFor as long as there's been a flavour of Pose for React, there's been requests for a Pose for Vue.\n\nOver the last week I've been tinkering with Vue and figuring out the best way to bring Pose's declarative animations and interactions to this fast-growing framework.\n\nToday, I'm pleased to announce the first release of [Pose for Vue](/pose)!\n\nLet's take a look at this new library.\n\n<TOC />\n\n## Posed components\n\nAs with Pose for React, the core of the library is the `posed` object.\n\n```javascript\nimport posed from 'vue-pose';\n```\n\nIt's used for making posed HTML and SVG components, components that will magically animate from a single prop change. No `transition` needed!\n\n```javascript\nexport default {\n  components: {\n    Box: posed.div({\n      visible: { opacity: 1 },\n      hidden: { opacity: 0 }\n    })\n  },\n  template: `<Box :pose=\"isVisible ? 'visible' : 'hidden'\" />`\n};\n```\n\n<CodeSandbox id=\"3vov3orj71\" height=\"500\" vue />\n\nPose will automatically figure out an animation based on the types of prop you're animating. But, for those of you who haven't used Pose before, it's worth mentioning that you can have full control over transitions, and Pose offers full access to [Popmotion Pure's](/pure) tween, spring, decay, physics and keyframes animations.\n\n## Interactions\n\nOf course, all the normal Pose features are here. Making a component respond to pointer interactions is a matter of a couple of props:\n\n```javascript\nexport default {\n  components: {\n    Box: posed.div({\n      draggable: true,\n      hoverable: true,\n      init: { scale: 1 },\n      hover: { scale: 1.2 },\n      drag: { scale: 1.1 }\n    })\n  },\n  template: `<Box />`\n};\n```\n\n<CodeSandbox id=\"qvnw69lv9\" height=\"500\" vue />\n\n## Animating children\n\nOne of Pose's most popular features is how simple it becomes to orchestrate animations throughout the DOM.\n\nPose for Vue is no different. Poses set on a parent component flow through the DOM automatically, so any children components with the same poses defined will animate too.\n\nProperties like `delayChildren` and `staggerChildren` allow total control over when child animations get fired.\n\n```javascript\nexport default {\n  components: {\n    Sidebar: posed.ul({\n      visible: {\n        x: 0,\n        beforeChildren: true,\n        staggerChildren: 50\n      },\n      hidden: { x: '-100%', afterChildren: true }\n    }),\n    Item: posed.li({\n      visible: { opacity: 1, y: 0 },\n      hidden: { opacity: 0, y: 20 }\n    })\n  },\n  template: `<Sidebar :pose=\"isVisible\">\n    <Item v-for=\"item in items\" v-bind:key=\"item\" />\n  </Sidebar>`\n};\n```\n\n<CodeSandbox id=\"qq667ljpz4\" height=\"500\" vue />\n\n## Enter/exit transitions\n\nThere's even a special version of Vue's `transition` component.\n\nCalled `PoseTransition`, it automatically creates opacity animations for children DOM elements, but posed components can be used to define custom transitions.\n\n```javascript\nexport default {\n  components: {\n    PoseTransition,\n    Modal: posed.div({\n      enter: { opacity: 1, y: 0 },\n      exit: { opacity: 0, y: 100 }\n    })\n  },\n  template: `<PoseTransition>\n    <Modal v-if=\"isVisible\" />\n  </PoseTransition>`\n}\n```\n\nThese \"enter\" and \"exit\" poses flow through children as with other posed components, so you can use this to orchestrate some complex animations.\n\n<CodeSandbox id=\"3qvz9w2rp6\" height=\"500\" vue />\n\n## And the rest\n\nThat's to say nothing of the powerful [passive values](/pose/learn/vue-passive) or [FLIP](/pose/learn/vue-flip) features, that are both here as expected.\n\n## What's missing\n\nCurrently, Pose for Vue doesn't have `transition-group` support. Vue's in-built `transition-group` is excellent, with all the FLIP-powered goodness that Pose for React offers with the `PoseGroup` component.\n\nUnfortunately, `transition-group` doesn't offer JavaScript hooks for the move animations. Which means it would take serious time investment to offer the same feature with Pose for Vue.\n\nIf Pose for Vue proves popular, I'll be able to take another look in the coming weeks.\n\n## What's next\n\nOver the coming weeks we'll be doubling-down on making Popmotion libraries easier to contribute to and more robust. That means introducing [CircleCI](https://circleci.com/), and improving test coverage around the DOM Pose flavours.\n\nUntil then, [get started with Pose for Vue](/pose/learn/vue-get-started)!\n"
  },
  {
    "path": "packages/popmotion/docs/blog/20181101-react-pose-4-forwardref.md",
    "content": "---\ntitle: \"Pose for React 4.0: Custom components made simple(r)\"\ndescription: Pose previously used special properties to animate custom components. 4.0 simplifies this by enforcing forwardRef.\npublished: 20181101\nauthor: mattperry\n---\n\n# Pose for React 4.0: Custom components made simple(r)\n\nToday, we release Pose for React 4.0. As per Pose tradition, the major release brings with it no big-splash features or complicated migration, just one simple breaking change that should clarify the API going forward.\n\n<TOC />\n\n## What's the problem?\n\nPose for React was written in a time before `React.forwardRef()`. To enable user access to the internal `ref` property, it took the `innerRef` naming convention from [Styled Components](https://www.styled-components.com/).\n\nThis extra API is a small point of confusion. But it also meant that to animate a custom component, Pose needed developers to forward either an `innerRef` (for SC and similar) or `hostRef` (proposed but unrealised React standard) to the custom component's inner DOM element. And when `forwardRef` was released, we added support for that, too.\n\nThis all led to a messy story around animating custom components and the extra ref props flagged errors in stricter linting and typing environments. As CSS-in-JS libraries like SC and upcoming Emotion 10 support `forwardRef`, it's time to clean this up in Pose too.\n\nFrom today:\n\n1. Posed components will accept `ref` to grab inner DOM nodes (`innerRef` works but is **deprecated** and will throw a warning in development mode).\n2. `forwardRef` is the **single** canonical way to animate custom components.\n\n## What do I need to do?\n\n### Fetching DOM refs\n\n`innerRef` will continue working until `5.0`. But now when you want to grab a posed component's DOM reference from outside, you should use `ref`:\n\n```javascript\nconst Button = posed.button(config);\n\nclass MyComponent extends React.Component {\n  setRef = ref => this.ref = ref;\n\n  render() {\n    return <Button ref={this.setRef} />;\n  }\n}\n```\n\n### Animating custom components\n\nAnimated custom components are a little different. Currently, your code might look like this:\n\n```javascript\n// CustomComponent.js\nexport default ({ innerRef }) => <div ref={innerRef} />;\n\n// index.js\nimport CustomComponent from './CustomComponent';\n\nconst PosedCustomComponent = posed(CustomComponent)(config);\n```\n\nNow, `CustomComponent` **must** be wrapped in React's `forwardRef` function. Typically, you'd call its second argument `ref`, but to ease migration you can rename it to whichever property you're already using. For instance:\n\n```javascript\nimport { forwardRef } from 'react';\n\nexport default forwardRef((props, innerRef) => <div ref={innerRef} />);\n```\n\n## Conclusion\n\nNow, it doesn't matter whether you `styled` your `posed` or `posed` your `styled` components. This new approach is robust no matter how strict your environment is.\n\nMost importantly, it's simpler to communicate to users, which typically has the happy side-effect of simpler expression in code. This time, it nets us a saving of ~0.6kb!\n"
  },
  {
    "path": "packages/popmotion/docs/blog/20190123-introducing-inertia-animation-for-popmotion-pure.md",
    "content": "---\ntitle: Introducing Inertia for Popmotion Pure\ndescription: The new inertia animation allows the creation of physics-based sliders and scroll views\npublished: 20190123\n---\n\n# Introducing Inertia for Popmotion Pure\n\nToday, we're releasing the first new animation for Popmotion Pure in over a year!\n\n[Inertia](/api/inertia) combines the best of the [spring](/api/spring) and [decay](/api/decay) animations, to allow for momentum-scrolling and other visceral slider interactions. Check it out:\n\n<CodePen id=\"BMNvqj\" />\n"
  },
  {
    "path": "packages/popmotion/docs/blog/20190704-upgrade-to-pure-9.md",
    "content": "---\ntitle: \"Popmotion Pure 9: How to upgrade\"\ndescription: Popmotion Pure 9 introduces some breaking changes - here's how to upgrade!\npublished: 20190704\n---\n\n# Popmotion Pure 9: How to upgrade\n\nPopmotion Pure 9 is a slimmed-down version of Popmotion that includes just the stuff that makes it unique - the opinionless streams of values to plug into anything!\n\nAll animations and gestures work exactly as before. `styler` now lives in Stylefire, while calculators and \n\nInstall Stylefire and import `styler` from there.\n\n\n```bash\nnpm install stylefire\n```\n\n```javascript\nimport styler from 'stylefire'\n```"
  },
  {
    "path": "packages/popmotion/docs/blog/20200115-pose-is-deprecated.md",
    "content": "---\ntitle: Pose is deprecated\ndescription: All versions of Pose are now deprecated.\npublished: 20200115\nauthor: Matt Perry\n---\n\n# Pose is deprecated\n\nOver a year ago I joined [Framer](https://framer.com) to help write the next version of their animation API. This resulted in the release of [Framer Motion](https://framer.com/motion), a production-ready, declarative animation library for React.\n\nIt takes Popmotion, which is a low-level, unopinionated animation library, and wraps it in a super-simple API that lowers the time and knowledge investment required for people to make beautifully animated websites.\n\nThis raised a problem in that I'd already written a library that did pretty much that that: [Pose](/pose).\n\nIn the broadest strokes the two work quite similarly. Framer Motion just does more, a lot simpler, in roughly the same bundle size.\n\nThe key difference between the two is that supporting Pose as an open source library was an untenable situation for me. OSS funding is completely broken and without it, maintainers are going to burn out at some point.\n\nIt's refreshing to work on Framer Motion because it powers the animations both within the Framer UI and those created by its users. The same way Facebook's dogfooding of React leads to its continued investment, the same is true of Framer Motion. This is a much healthier product.\n\nSo we positioned it as the \"successor to Pose\", and React Pose was deprecated.\n\n## A carnival of flavours\n\nPose was written as a configurable abstraction that was easy adapt for different view libraries. Relatively quickly we ended up with React Pose, React Native Pose, and Vue Pose. There was even an unreleased React 360 Pose.\n\nHowever, React Pose was always the primary focus. At its peak, it was generating over 100k downloads a week. React Native Pose has sat at around 4.5k downloads, while Vue Pose has never breached 2k. Vanishingly small in comparison.\n\nIt was easy to write the different Pose implementations, but the resulting abstraction tree meant that it was a nightmare to maintain them over time. I chose the wrong abstractions and there's probably a deep dive retrospective on that topic alone.\n\nGiven the relative audience sizes and my lack of free time for open source, when I officially deprecated React Pose, I effectively deprecated the lot. Since then there's been no updates to the React Native or Vue flavours and there won't be in the future. So today I'm making it official.\n\n## What next?\n\nReact Pose users already have an upgrade path in Framer Motion, and can follow the [official migration guide](https://www.framer.com/api/motion/migrate-from-pose/).\n\nI would love to write a React Native version of Framer Motion, but there's plenty of cool animation-related features to write for Framer that will take priority.\n\nIt's also hard to gauge demand - the Pose download numbers above paint an unfortunate but possible incomplete picture. If you're interested in a React Native version let us know on the [GitHub ticket](https://github.com/framer/motion/issues/180).\n\nAs for Vue Pose, there are no current plans for a Vue Framer Motion and I suspect there won't be.\n\nAll these libraries will continue to be available on npm, and the documentation will continue to be found in the footer on this site. I just won't be releasing updates to the code, so they may break in future backwards-incompatible releases of their respective view libraries.\n\nThe code itself will be accessible in the [Popmotion `master` branch](https://github.com/popmotion/popmotion) for at least another month but beyond that you might need to go spelunking in the repo history if you want to fork it.\n\nPopmotion itself has a much brighter future. Framer Motion's existence and upcoming Framer product requirements has opened up space and created demand for Popmotion to become even lower-level, even more unopinionated, so look forward to these changes in the future.\n\n---\n\n[Framer Motion](https://framer.com/motion)"
  },
  {
    "path": "packages/popmotion/docs/blog/draft-60fps-hi-res-image-scaling-with-translatez-and-maths.md",
    "content": "---\ntitle: Achieve 4K 60fps image scaling animations with translateZ and maths\ndescription: At high resolutions, image scaling in CSS can become sluggish. By using `translateZ` and maths, we can emulate `scale` at 60fps.\npublished: 20170710\nauthor: Matt Perry\ndraft: true\n---\n\n# Achieve 4K 60fps image scaling animations with `translateZ` and maths\n\nAbout a year ago I received a design to implement: a full-screen image slideshow, with a togglable sidebar.\n\nI thought it'd be cool to have a transition where, rather than lay the sidebar **over** the image, the image itself would scale down to accommodate the sidebar. A little like this:\n\n![Sidebar animation](/images/sidebar-effect.gif)\n\nThe function to achieve this effect is pretty simple. We first have to figure out, in pixels, how much of the sidebar to show at any given time. Then, figure out what percentage of the viewport that leaves us and use **that** for the image scale:\n\n```javascript\n(progress) => {\n  const visibleSidebarWidth = sidebarWidth * progress;\n  const imageScale = (viewportWidth - visibleSidebarWidth) / viewportWidth;\n\n  sidebarRenderer.set('x', - visibleSidebarWidth + sidebarWidth);\n  imageRenderer.set('scale', imageScale);\n}\n```\n\nInitially, I thought this approach was working well. It looked 60fps by eye, and a quick look at the Chrome Performance panel output graphs like this:\n\n![Low paint times = happy users](/images/scale-dev-small-screen.gif)\n\nHowever, when I added high resolution images and increased the viewport to full screen on a 4K monitor, the framerate was so bad that I didn't need to see the graphs to know they'd probably look like this:\n\n![High paint times = MY EYES](/images/scale-dev-small-screen.gif)\n\n## Performance graphs explained\n\nA quick aside for those who don't spend too much of their spare time in the Chrome dev tools.\n\nIn the images above, each shows two green graphs:\n- The top, light green graph is FPS. Higher bars = higher fps.\n- The bottom, dark green graph is actually made of three different colors. These are CPU resources, and the fact that yellow and purple are barely visible is good as it means we're not running a lot of JS and we're not causing the page to reflow. The massive green spikes means we're causing a lot of paints on the CPU.\n\nThis is odd: By default, Popmotion uses the `translateZ` force-GPU hack on `transform`. I had also set `will-change: transform` on the image itself, which would render this unnecessary. So CPU usage should be very low.\n\n## The fix\n\nI'd previously used `translateZ` to animate full-screen elements and thought that if we used it to physically \"push\" the image into the screen, we'd be able to make something that looked identical to a 2D scale.\n\nThe problem is knowing exactly **how far** to push the image into the screen in order to figure out\n\n[Aldo Stracquadanio](https://twitter.com/astr4c)"
  },
  {
    "path": "packages/popmotion/docs/blog/draft-css-vs-js-animation.md",
    "content": "---\ndraft: true\n---"
  },
  {
    "path": "packages/popmotion/docs/blog/draft-the-emerging-reality.md",
    "content": "---\ntitle: UX in the Emerging Reality\ndescription: \ndraft: true\n---"
  },
  {
    "path": "packages/popmotion/docs/learn/advanced/value-pipelines.md",
    "content": "---\ntitle: Composable value pipelines\ndescription: Use `pipe` to compose reusable value pipelines\ncategory: advanced\n---\n\n# Composable value pipelines\n\nPopmotion provides simple utility functions that can take a value and return it transformed. These are, unsurprisingly, called **[transformers](/api/transformers)**.\n\n```javascript\nimport { transform } from 'popmotion';\n// Or save your user's bytes!\nimport * as transform from 'popmotion/transformers';\n```\n\nThese functions can perform a wide range of tasks. Something as simple as appending a unit:\n\n```javascript\nconst { appendUnit } = transform;\nconst px = appendUnit('px');\npx(5); // '5px'\n```\n\nMake an infinite looping sequence:\n\n```javascript\nwrap(0, 100)(150); // 50\n```\n\nOr converting a value from one range to another:\n\n```javascript\ninterpolate([0,1], [-500, 500])(0.5); // 0\n```\n\n## Curry\n\nAs you can see, many of these transformers are curried. So we can make a function:\n\n```javascript\nconst restrictNormalised = clamp(0, 1);\n```\n\nAnd then reuse it elsewhere:\n\n```javascript\nrestrictNormalised(5); // 1\n```\n\n## Compose\n\nBecause these functions are very simple and all carry the same signature, we can compose them. Popmotion provides a special transformer to do just that.\n\n```javascript\nconst { pipe } = transform;\n```\n\n`pipe` is named as such because it takes a list of functions and returns a new function that will run these functions from **left to right**. Essentially, creating a value pipeline.\n\nAs our functions are descriptively named, and as many of them are curried, our pipelines become very easy to read. They become less imperative, and more declarative.\n\nFor instance, let's compose a function that will always return a valid RGB value. RGB values are simply integers between `0` and `255`.\n\n```javascript\nconst rgbUnit = pipe(\n  clamp(0, 255),\n  Math.round\n);\n```\n\nWhat's cool about this example is that it shows that **any** function that 1) takes a number and 2) returns a number, can be composed. `Math.round` does exactly that, so we can compose it.\n\nYou don't have to write this function yourself, because that exact code is already included as a Popmotion transformer, and used in the `rgba` [value type](/api/value-types).\n\nThe `rgba` transformer is **itself** composed. Here's the exact code:\n\n```javascript\nconst rgba = pipe(\n  transformMap({\n    red: rgbUnit,\n    green: rgbUnit,\n    blue: rgbUnit,\n    alpha\n  }),\n  rgbaTemplate\n);\n```\n\nThis is an example of composing functions **which were themselves composed**. This is a very clear way of expressing and reusing our logic.\n\n## Applying transformers to animations\n\nEvery Popmotion [action](/api/action) and [reaction](/api/reaction) has a native `pipe` function.\n\nProviding a list of functions to `pipe` will return a new instance of the action or reaction, and whenever its `update` function is called, the value will be passed through these functions before being emitted.\n\nConsider this tween:\n\n```javascript\ntween({ from: 0, to: 255 });\n```\n\nWe can use our `rgbUnit` transformer from before to ensure that whenever this tween is called, it **always** returns a valid RGB unit:\n\n```javascript\ntween({ from: 0, to: 255 })\n  .pipe(rgbUnit)\n  .start(console.log);\n```\n\nThis is a versatile approach to adding functionality to any animation. For instance, many animation libraries offer an option to create stepped tweens, but with this kind of composition we can easily bring that same functionality to `physics` (or any other animation).\n\nHere, we can easily create something that spins at a constant velocity, outputting an angle value that snaps to `45` degree intervals:\n\n```javascript\nphysics({ velocity: 100 })\n  .pipe(\n    snap(45),\n    appendUnit('deg')\n  );\n```\n\nEtc.\n\n## Conclusion\n\nThese pure, simple functions are easily composed and reused. They can be used on their own, or with any action (not just tweens), making them extremely versatile.\n\nWe believe this functional approach gives developers the greatest flexibility and predictability.\n\nWe've covered just some of the many transformers here, but more are documented in our [API docs](/api/transformers). As they're pure functions, not specific to Popmotion, you can easily have fun creating your own.\n"
  },
  {
    "path": "packages/popmotion/docs/learn/basics/action-reaction.md",
    "content": "---\ntitle: Actions and reactions\ndescription: A quick look at Popmotion's simplified reactive model.\ncategory: basics\nnext: input-tracking\n---\n\n# Actions and reactions\n\nThe `tween` function returns what's known in Popmotion as an **action**.\n\nPopmotion is a reactive library, and actions are functions that **create** streams of values. These actions output to **reactions**.\n\n**In Popmotion, every animation and input is an action**. In this quick tutorial, we'll gain a better understanding of actions and reactions by writing our own.\n\n## Import\n\n```javascript \nimport { action } from 'popmotion';\n```\n\n## Creating an action\n\nThe `action` function accepts a single argument. It's an initialisation function that will be executed **each time the returned action is started** via its `start` method.\n\nThis means that we can define one action, and start it multiple times, leading to multiple instances of that action.\n\nThe `init` function is provided an object of three functions: `update`, `complete`, and `error`:\n\n```javascript\naction(({ update, complete, error }) => {})\n```\n\nLet's define a function called `just`. It'll return an action that, when started, will fire `update` with the provided value and then `complete`:\n\n```javascript\nconst just = (v) => action(({ update, complete }) => {\n  update(v);\n  complete();\n});\n```\n\nNow, when the action returned from `just` is `start`ed, it'll emit the provided value:\n\n```javascript\njust(1).start(console.log); // 1\n```\n\n`console.log` is being used as a **reaction**. It will fire whenever the new action instance calls `update` with a new value.\n\nWe also defined `just` to fire `complete` once it's finished. Instead of a function, we can provide an object of `update` and `complete` functions as our reaction:\n\n```javascript\njust(1).start({\n  update: console.log,\n  complete: () => console.log('complete!')\n});\n```\n\nWhen `start` runs, the initialisation function is run anew, and a **new instance** of the active action is returned:\n\n```javascript\nconst justOne = just(1);\njustOne.start(console.log); // 1\njustOne.start(console.log); // 1\n```\n\nAs all Popmotion animations are actions, we can define an animation once and use it multiple times:\n\n```javascript\nconst mySpring = spring({ to: 500 });\n\nmySpring.start({\n  update: console.log,\n  complete: () => console.log('complete!')\n});\n\nmySpring.start({\n  update: (v) => console.log('second spring: ' + v),\n  complete: () => console.log('second spring also complete!')\n});\n```\n\n## Chainable modifiers\n\nAll actions, as well as special reactions like [multicast](/api/multicast) and [value](/api/value), are **chainable**.\n\nThey offer methods that **return a new instance of the action or reaction** with altered behaviour.\n\nCurrently, there are three chainable methods: `filter`, `pipe` and `while`.\n\nAn API for developers to add more is on the roadmap.\n\nLet's take a look at an example of each:\n\n### `filter`\n\n`filter` accepts a single function. This function is passed the latest value emitted from `update`.\n\nThe value is only passed down the chain if the function provided to `filter` returns `true`.\n\n```javascript\naction(({ update }) => {\n  update(1);\n  update(2);\n  update(1);\n}).filter((v) => v === 1)\n  .start(log); // 1, 1\n```\n\n### `pipe`\n\n`pipe` accepts a series of functions.\n\nEach function is provided the latest value emitted from `update`, and returns a new value that is passed down the chain:\n\n```javascript\nconst double = (v) => v * 2;\nconst px = (v) => v + 'px';\n\nconst one = just(1);\nconst twoPx = one.pipe(double, px);\n\none.start(console.log); // 1\ntwoPx.start(console.log); // '2px'\n```\n\n### `while`\n\n`while` accepts a single function. This function is passed every value from `update` and fires `complete` if the function returns `false`:\n\n```javascript\njust(1)\n  .while((v) => v === 2);\n  .start(console.log); // never fires, as while returned false\n```\n\n### Combining\n\nLet's combine `pipe` and `while` to make a [pointer](/api/pointer) that outputs its `x` position as percentage of the current viewport, and automatically stops itself if the pointer is more than 75% across the screen:\n\n```javascript\nconst pickX = ({ x }) => x;\nconst viewportWidth = window.innerWidth;\nconst percentageOfViewport = (v) => v / viewportWidth * 100;\nconst asPercent = (v) => v + '%';\n\npointer()\n  .pipe(pickX, percentageOfViewport) // The output of this\n  .while((v) => v < 75) // Gets passed to this\n  .pipe(asPercent) // Before being passed to this\n```\n\n## Stopping actions\n\nEvery action returns a `stop` method:\n\n```javascript\nconst foo = tween().start(console.log);\nfoo.stop();\n```\n\nBut how does the code defined in your `init` function know its been stopped?\n\nEach init function can **optionally** return an API. This can include a `stop` function:\n\n```javascript\nconst oneEverySecond = action(({ update }) => {\n  const updateOne = () => update(1);\n  const interval = setInterval(updateOne, 1000);\n\n  return {\n    stop: () => clearInterval(interval)\n  };\n});\n\nconst foo = oneEverySecond.start();\nsetTimeout(() => foo.stop(), 3000); // 1, 1, 1\n```\n\n## Custom API\n\nYour action can return a custom API, too:\n\n```javascript\nconst valueEverySecond = action(({ update }) => {\n  let outputValue = 1;\n  const updateOne = () => update(outputValue);\n  const interval = setInterval(updateOne, 1000);\n\n  return {\n    stop: () => clearInterval(interval),\n    setOutputValue: (v) => outputValue = v\n  };\n});\n\nconst foo = valueEverySecond.start();\nfoo.setOutputValue(2); // 2, 2...\n```\n\n## Conclusion\n\nBy chaining actions we can create new actions with different behaviour.\n\nThis flexibility is available on all animations and inputs, and later tutorials will touch on these capabilities.\n\nIn the next tutorial, we'll learn how to implement pointer tracking with two input actions, [Pointer and Listen](/learn/input-tracking).\n"
  },
  {
    "path": "packages/popmotion/docs/learn/basics/get-started.md",
    "content": "---\ntitle: Get started\ndescription: Introduction to Popmotion's tween animation.\ncategory: basics\nnext: action-reaction\n---\n\n# Get started\n\nPopmotion is a low-level, functional JavaScript motion library.\n\nIt allows developers to animate in any JavaScript environment (browser, Node), to any render target (CSS, SVG, Three.js, canvas, etc).\n\n**Note:** If you're looking for React animation, you're probably after the [Motion](https://framer.com/motion) library. For absolute animation freedom, carry on reading!\n\nIn this simple introductory guide we're going to install Popmotion and use it to animate a DOM element using the `tween` animation.\n\n## Installation\n\nYou can install Popmotion directly from npm:\n\n```bash\nnpm install popmotion --save\n```\n\nAlternatively, you can also **download pre-bundled files** or **fork CodePen playgrounds**. Full installation options are available on the [Install Popmotion](/learn/install) page.\n\n## Import\n\nIn Popmotion, everything can be imported from the main library like this:\n\n```javascript\nimport { tween } from 'popmotion';\n```\n\n## The \"Hello World\" tween\n\nA `tween` is a function that changes **one number to another, over a set duration of time**. If you're familiar with CSS transitions, that's a form of tweening.\n\nBy default, a `tween` will change `0` to `1` over `300` milliseconds:\n\n```marksy\n<Example template=\"Counter\" id=\"a\" autostart={false}>{`\nconst counter = document.querySelector('#a .counter');\nconst updateCounter = (v) => counter.innerHTML = v;\n\ntween().start(updateCounter);\n`}</Example>\n```\n\n**All examples in the green-bordered boxes are editable**. Try editing the above example by writing\n\n```javascript\n{ to: 300, duration: 500 }\n```\n\nas the argument to the `tween` function. The counter will now count up to `300` over the course of half a second.\n\n## Animate!\n\nAs web developers, the DOM is our most common render target for animations.\n\nSo, let's use the exact same animation from before to output to an element's `translateX` property.\n\nWe can do this by setting the element's `style` property.\n\n```javascript\nconst element = document.querySelector('.ball');\n\ntween({ to: 300, duration: 500 })\n  .start((v) => element.style += 'translateX(' + v + 'px)');\n```\n\nAlternatively there's a Popmotion library called [Stylefire](/stylefire) that provides a simple API for setting HTML and SVG styles. It also aggregates all style changes and renders them just once per frame, making it performant to run multiple different animations on a single DOM element.\n\n```\nnpm install stylefire\n```\n\nImport `styler`:\n\n```javascript\nimport { tween } from 'popmotion';\nimport styler from 'stylefire';\n```\n\n`styler` accepts a single HTML or SVG element. It returns a simple get/set interface for styling the element that unifies the transformation model of CSS and SVG and batches all styling to a single moment, once per frame.\n\nThis helps prevent layout-thrashing and allows you to animate transformation properties separately.\n\nIt's used like this:\n\n```javascript\nconst element = document.querySelector('.ball');\nconst ball = styler(element);\n```\n\nWhen `ball.set` is called, it schedules a render on the following frame:\n\n```marksy\n<Example template=\"Ball\" id=\"b\" autostart={false}>{`\nconst element = document.querySelector('#b .ball');\nconst ball = styler(element); \n\ntween({ to: 300, duration: 500 })\n  .start(v => ball.set('x', v));\n`}</Example>\n```\n\nAnd that's it! Your first animation. \n\n## Multi-property animations\n\nAll animations included with Popmotion can animate:\n\n- Numbers\n- Colors (rgba, hsla and hex)\n- Units `px`, `%`, `deg`, `vh`, and `vw`\n- Complex strings containing numbers, units and colors, e.g. CSS shadows, gradients and SVG path definitions\n- Objects of the above\n- Arrays of the above\n\nFor instance, by replacing `300` in the previous example with `{ x: 300, scale: 2 }` the action will animate both `x` and `scale` values:\n\n```marksy\n<Example template=\"Ball\" id=\"c\" autostart={false}>{`\nconst ball = document.querySelector('#c .ball');\nconst ballStyler = styler(ball);\n\ntween({\n  from: { x: 0, scale: 1 },\n  to: { x: 300, scale: 2 },\n  ease: easing.easeInOut,\n  flip: Infinity,\n  duration: 1000\n}).start(v => ballStyler.set(v));\n`}</Example>\n```\n\n## Next\n\nThis tutorial has covered the very the basics for the `tween` animation. You can find more details in the full [tween API docs](/api/tween).\n\n`tween`, and all other Popmotion animations/interactions, are **actions**. Actions are simple reactive streams of values.\n\nIn the next tutorial, we'll briefly look at these [actions and reactions](/learn/action-reaction).\n"
  },
  {
    "path": "packages/popmotion/docs/learn/basics/input-tracking.md",
    "content": "---\ntitle: Pointer tracking\ndescription: Learn to track pointer movement and use that to drag DOM elements.\ncategory: basics\nnext: velocity-and-physics\n---\n\n# Pointer tracking\n\nPointer tracking is an integral part of user interfaces.\n\nDrag & drop, scrolling galleries, and measuring touch scroll speed are some obvious use cases.\n\nIn this quick tutorial, we'll first see how to convert DOM events into streams of values with the `listen` action.\n\nThen, we'll look at how to track mouse and touch movement with the `pointer` action and then use that pointer's movement to drag a DOM element.\n\n## The `listen` action\n\nPopmotion provides the [`listen` action](/api/listen) to add event listeners to the DOM.\n\n```javascript\nimport { listen } from 'popmotion';\n```\n\nIt accepts event names as a space-delimited string, meaning you can use a single `listen` call to listen to multiple events:\n\n```javascript\nlisten(document, 'mousedown touchstart')\n  .start((e) => console.log(e));\n```\n\nJust like the good-old days of jQuery!\n\nAs `listen` is an [action](/api/action), it offers all the same chainable methods.\n\nFor example, here's how you could make a `touchmove` listener that only fires when there's more than two `touches`:\n\n```javascript\nlisten(document, 'touchmove')\n  .filter(({ touches }) => touches.length >= 2)\n  .start((e) => /* This event has more than 2 touches! */);\n```\n\n## The `pointer` action\n\nThe `pointer` action provides a generic interface for interacting with **single point** mouse and touch inputs (for multitouch, Popmotion offers the [`multitouch` action](/api/multitouch)).\n\n```javascript\nimport { pointer } from 'popmotion';\n```\n\nBy default, `pointer` outputs the pointer's `clientX` and `clientY` properties as `x` and `y`.\n\n```javascript\nlet pointerTracker;\n\nlisten(document, 'mousedown touchstart').start(() => {\n  pointerTracker = pointer()\n    .start(({ x, y }) => console.log(x, y));\n});\n\nlisten(document, 'mouseup touchend').start(() => {\n  if (pointerTracker) pointerTracker.stop();\n});\n```\n\n## Dragging\n\nThe majority of time we actually want to use this movement data to drag or scroll.\n\nLet's use the `styler` function again to create a DOM element interface to provide the positional data to.\n\nLook at `startTracking` function and try to drag the ball:\n\n```marksy\n<Example template=\"Ball\" id=\"a\" autostart={true}>{`\nconst ball = document.querySelector('#a .ball');\nconst ballStyler = styler(ball);\nlet pointerTracker;\n\nconst startTracking = () => {\n  pointerTracker = pointer()\n    .start(ballStyler.set);\n};\n\nconst stopTracking = () => {\n  if (pointerTracker) pointerTracker.stop();\n};\n\nlisten(ball, 'mousedown touchstart').start(startTracking);\nlisten(document, 'mouseup touchend').start(stopTracking);\n`}</Example>\n```\n\n**Oh dear.** The ball moves, but it jumps to a weird location (maybe one that's off-screen entirely!)\n\nThe reason for this is simple. `pointer` is outputting the `{ x, y }` position of the pointer **relative to the viewport**.\n\nThe **ball's** `{ x, y }` transform begins at `0, 0`. So if we apply the pointer's absolute position directly to the ball, it won't move where we want it to.\n\nInstead, we want to apply the **movement** of the `pointer` to the ball's initial position.\n\nTo do this, we can provide `pointer` with an initial `{ x, y }` point, and it will output the movement of its `{ x, y }` **relative to that point**:\n\n```javascript\npointer({ x: 0, y: 0 })\n```\n\nDragging becomes trivial:\n\n```marksy\n<Example template=\"Ball\" id=\"b\" autostart={true}>{`\nconst ball = document.querySelector('#b .ball');\nconst ballStyler = styler(ball);\nlet pointerTracker;\n\nconst startTracking = () => {\n  pointerTracker = pointer({\n    x: ballStyler.get('x'),\n    y: ballStyler.get('y')\n  }).start(ballStyler.set);\n};\n\nconst stopTracking = () => {\n  if (pointerTracker) pointerTracker.stop();\n};\n\nlisten(ball, 'mousedown touchstart').start(startTracking);\nlisten(document, 'mouseup touchend').start(stopTracking);\n`}</Example>\n```\n\n## Single-axis dragging\n\nLimiting dragging to a single axis is a matter of using just the `x` or `y` output from `pointer`.\n\nWe could do this via the reaction:\n\n```javascript\npointer().start(({ x }) => ballStyler.set('x', x));\n```\n\nBut the more reusable way is to **compose a new action** using `pointer`'s `pipe` method. We can provide it a simple picker function that selects `x` from `pointer`'s output and returns it:\n\n```javascript\nconst xPointer = (initialX) => pointer({ x: initialX })\n  .pipe(({ x }) => x);\n```\n\nNow we can use our newly composed `xPointer` like so:\n\n```javascript\nxPointer(ballStyler.get('x'))\n  .start(ballStyler.set('x'));\n```\n\n```marksy\n<Example template=\"Ball\" id=\"c\" autostart={true}>{`\nconst ball = document.querySelector('#c .ball');\nconst ballStyler = styler(ball);\nconst xPointer = (initialX) => pointer({ x: initialX })\n  .pipe(({ x }) => x);\n\nlet pointerTracker;\n\nconst startTracking = () => {\n  pointerTracker = xPointer(ballStyler.get('x'))\n    .start(ballStyler.set('x'));\n};\n\nconst stopTracking = () => {\n  if (pointerTracker) pointerTracker.stop();\n};\n\nlisten(ball, 'mousedown touchstart').start(startTracking);\nlisten(document, 'mouseup touchend').start(stopTracking);\n`}</Example>\n```\n\n## Conclusion\n\n`listen` can convert DOM events into reactive streams of values. Useful for leveraging `pipe` and other chainable methods, and composing `listen` with other actions.\n\n`pointer` can output values either absolutely, or, if we provide initial coordinates, by applying its delta relatively.\n\nFinally, we can compose new actions to produce reusable bits of code with new behaviour, like single-axis dragging.\n\n## Next\n\nNow that we've got dragging working, in the [next tutorial](/learn/velocity-and-physics) we will learn how to inspect the `velocity` of the dragged object and apply that to `decay`, `physics` and `spring` actions to create natural-feeling interactions.\n"
  },
  {
    "path": "packages/popmotion/docs/learn/basics/install.md",
    "content": "---\ntitle: Install Popmotion\ndescription: Overview of Popmotion's different installation options.\ncategory: basics\nnext: get-started\n---\n\n# Install Popmotion\n\n## Package managers\n\n### npm\n\n```bash\nnpm install popmotion --save\n```\n\n### yarn\n\n```bash\nyarn add popmotion\n```\n\n## File include\n\n**Note:** The Popmotion documentation uses the `import` syntax for importing individual modules.\n\n**If you use one of the following installation methods, Popmotion will be available on the global `popmotion` variable.**\n\nSo, when you see in the docs `import { tween } from 'popmotion'`, you will use `const { tween } = popmotion` instead.\n\n### Download\n\nYou can download the latest version of Popmotion at https://unpkg.com/popmotion/dist/popmotion.global.min.js\n\n### `script` include:\n\nOr include it directly in your HTML with this `script` tag:\n\n```html\n<script src=\"https://unpkg.com/popmotion/dist/popmotion.global.min.js\"></script>\n```\n\n### CodePen\n\nYou can fork the [Popmotion playground on CodePen](https://codepen.io/popmotion/pen/zPjXWa?editors=0010), which is set up with the latest version of Popmotion.\n\nYou an also add Popmotion to any existing CodePen project by clicking on Settings > JavaScript and then pasting `https://unpkg.com/popmotion/dist/popmotion.global.min.js` into the \"Add External JavaScript\" field.\n"
  },
  {
    "path": "packages/popmotion/docs/learn/basics/velocity-and-physics.md",
    "content": "---\ntitle: Physics and velocity\ndescription: Create responsive interactions with velocity, decay, physics and spring.\ncategory: basics\n---\n\n# Physics and velocity\n\nA core feature of Popmotion is the ability for some animations ([decay](/api/decay), [spring](/api/spring) and [physics](/api/physics)) to take a `velocity` parameter.\n\n`velocity` changes each of these animations in a way that feels natural and visceral.\n\nBy passing the velocity of an existing animation to another, we can create natural-feeling transitions. And if that existing animation is `pointer`, it allows the user to directly affect animations with their own force leading to natural and playful interactions. \n\n## Inspect velocity\n\nBut how do we get `velocity`?\n\nPopmotion provides a special type of reaction called `value`.\n\n```javascript\nimport { value } from 'popmotion';\n```\n\n`value` sits between your action and another reaction (for instance a style setter), and can be queried with `get` and `getVelocity`:\n\n```javascript\nconst myValue = value(0, console.log);\n\ntween().start(myValue);\n\nsetTimeout(() => myValue.getVelocity(), 100)\n```\n\nThe returned `velocity` is measured in **units per second**. Why? Although 60fps is the current common framerate, VR devices support 90+ fps and the iPad Pro delivers a silky 120 frames per second!\n\nTo future-proof our code, we decouple velocity from the device framerate, otherwise our animations would run at 1.5x or even 2x the speed on these faster displays.\n\n## Using `value`\n\n`value` is provided two arguments: A value, and a function to call when this value updates:\n\n```javascript\nconst foo = value(0, console.log);\n```\n\nAs `value` is a reaction, it has an `update` method. We can call it to update the value:\n\n```javascript\nfoo.update(5);\n```\n\nUsually though, we provide the `value` directly to an action:\n\n```javascript\ntween({ to: 5 }).start(foo);\n```\n\nLike our animations, `value` can accept objects and arrays:\n\n```javascript\nconst xy = value({ x: 0, y: 0 }, console.log);\nconst foo = tween({\n  to: { x: 100, y: 200 }\n}).start(xy);\n\nsetTimeout(() => xy.getVelocity(), 100); // Returns as object\n```\n\nNow we know enough about `value` to get the velocity of our user's pointer.\n\n## Get `pointer` velocity\n\nUsing the example from the [previous tutorial](/learn/input-tracking), let's first make a `value` that updates `ballStyler`'s `x` and `y` properties:\n\n```javascript\nconst ballXY = value({ x: 0, y: 0 }, ballStyler.set);\n```\n\nNow we can replace our `startTracking` function with this:\n\n```javascript\nconst startTracking = () => {\n  pointer(ballXY.get()).start(ballXY);\n};\n```\n\nAs an added benefit of using `value`, a `value` **can't be subscribed to more than one action at a time**.\n\nThis means that we can stop using `pointerTracker` to maintain a reference to our active `pointer`.\n\nInstead, we can either use `ballXY.stop()`, which will stop the action it's currently subscribed to. Or, we simply provide it to a different action, which is what we'll do in the following examples.\n\nFor now, amend `stopTracking` so it queries `ballXY`'s current velocity:\n\n```javascript\nconst stopTracking = () => {\n  const velocity = ballXY.getVelocity();\n};\n```\n\n## Using `velocity`\n\nThree Popmotion animations accept a `velocity` property: `decay`, `physics` and `spring`.\n\nLet's modify `stopTracking` three times, once for each, to see what they each do with `velocity`.\n\n### `decay`\n\n[`decay`](/api/decay) exponentially decreases a velocity over time. It's a form of the algorithm used in smartphone momentum scrolling, making it a natural-feeling way of slowing something down.\n\nBased on the initial properties and `velocity`, it'll automatically calculate a `target` to animate to.\n\nUsing it is as easy as passing our newly-calculated `velocity` to `decay`:\n\n```javascript\ndecay({ velocity }).start(ballXY);\n```\n\n```marksy\n<Example template=\"Ball\" id=\"a\" autostart={true}>{`\nconst ball = document.querySelector('#a .ball');\nconst ballStyler = styler(ball);\nconst ballXY = value({ x: 0, y: 0 }, ballStyler.set);\n\nfunction startTracking() {\n  pointer(ballXY.get())\n    .start(ballXY);\n}\n\nfunction stopTracking() {\n  decay({\n    from: ballXY.get(),\n    velocity: ballXY.getVelocity()\n  }).start(ballXY);\n}\n\nlisten(ball, 'mousedown touchstart').start(startTracking);\nlisten(document, 'mouseup touchend').start(stopTracking);\n`}</Example>\n```\n\n`decay` also accepts a `modifyTarget` function, which is provided the calculated target and returns a new one.\n\nThis can be used, for instance, to snap the target to a grid:\n\n```javascript\ndecay({\n  from: ballX.get(),\n  velocity,\n  modifyTarget: (target) => Math.ceil(target / 100) * 100\n})\n```\n\n### `spring`\n\n[`spring`](/api/spring) is a spring simulation using `mass`, `velocity`, `stiffness` and `damping`. It can be used to simulate a wide variety of spring-feels.\n\nSprings are great for interaction designers because they're expressive. For instance, you could design a spring that has a `stiffness` and `damping` property, but the `mass` property is based on the relative size of the element moving.\n\n`spring` has defaults for all properties but you'll likely want to adjust at least `stiffness` and `damping`:\n\n```javascript\nspring({\n  from: ballXY.get(),\n  velocity,\n  stiffness: 300,\n  damping: 10\n}).start(ballXY);\n```\n\n```marksy\n<Example template=\"Ball\" id=\"b\" autostart={true}>{`\nconst ball = document.querySelector('#b .ball');\nconst ballStyler = styler(ball);\nconst ballXY = value({ x: 0, y: 0 }, ballStyler.set);\n\nfunction startTracking() {\n  pointer(ballXY.get())\n    .start(ballXY);\n}\n\nfunction stopTracking() {\n  spring({\n    from: ballXY.get(),\n    velocity: ballXY.getVelocity(),\n    stiffness: 100,\n    damping: 10\n  }).start(ballXY);\n}\n\nlisten(ball, 'mousedown touchstart').start(startTracking);\nlisten(document, 'mouseup touchend').start(stopTracking);\n`}</Example>\n```\n\n### `physics`\n\nThe `physics` animation is the swiss army knife of velocity-based animations.\n\nIt offers `friction`, `to` and `springStrength` properties, so it can theoretically be used to create motion similar to `decay` and `spring`. \n\nHowever, `decay` and `spring` animations are **differential equations** that resolve for a given `elapsedTime`. In practical terms, this means that if you want to change the animation they're creating, you need create a new animation with the new properties.\n\nThese equations are incredibly accurate, offering the smoothest motion and in the near future, will allow these animations to be scrubbable the same way `tween` is.\n\nInstead, `physics` is an **integrated simulation**. This means that, once the simulation has started, its properties **can be modified** because `physics` uses **its current state** to calculate its next\n\nFor instance, we can tether a `physics` spring between the ball and the pointer:\n\n```javascript\nconst springTo = physics({\n  velocity: ballXY.getVelocity(),\n  friction: 0.6,\n  springStrength: 400,\n  to: ballXY.get(),\n  restSpeed: false\n}).start(ballXY);\n\npointer(ballXY.get())\n  .start((v) => springTo.setSpringTarget(v));\n```\n\n```marksy\n<Example template=\"Ball\" id=\"c\" autostart={true}>{`\nconst ball = document.querySelector('#c .ball');\nconst ballStyler = styler(ball);\nconst ballXY = value({ x: 0, y: 0 }, ballStyler.set);\n\nlet activeAction;\nlet pointerTracker;\n\nfunction startTracking() {\n  activeAction = physics({\n    velocity: ballXY.getVelocity(),\n    friction: 0.6,\n    springStrength: 400,\n    to: ballXY.get(),\n    restSpeed: false\n  }).start(ballXY);\n\n  pointerTracker = pointer(ballXY.get())\n    .start((v) => activeAction.setSpringTarget(v));\n}\n\nfunction stopTracking() {\n  if (activeAction) activeAction.stop();\n  if (pointerTracker) pointerTracker.stop();\n  spring({\n    velocity: ballXY.getVelocity(),\n    from: ballXY.get(),\n    stiffness: 300,\n    damping: 10\n  }).start(ballXY);\n}\n\nlisten(ball, 'mousedown touchstart').start(startTracking);\nlisten(document, 'mouseup touchend').start(stopTracking);\n`}</Example>\n```\n\n## Conclusion\n\n`velocity` is a key part of creating natural interactions with Popmotion.\n\nBe sure to check out the full docs of [value](/api/value), [decay](/api/decay), [spring](/api/spring) and [physics](/api/physics), as there's much more to each than we've been able to cover in this introductory tutorial.\n"
  },
  {
    "path": "packages/popmotion/docs/learn/how-to/circular-motion.md",
    "content": "---\ntitle: Circular motion\ndescription: How to animate angle and radius to output x and y coordinates.\ncategory: how-to\n---\n\n# Circular motion\n\nHTML and SVG elements are positioned by `x` and `y` coordinates. This type of positioning is known as **cartesian coordinates**, and animating these is great for moving elements in straight lines (the majority use-case).\n\nHowever, to move elements in a circular fashion, it's much easier to animate position using **polar coordinates**: Position as defined by `angle` and `radius`.\n\nWe can then convert these polar coordinates into `x` and `y` to produce movement like this:\n\n<CodePen id=\"eygBGW\" height={400} />\n\nIn this quick tutorial, we'll create circular motion converting polar to cartesian coordinates using functional composition.\n\nAs a bonus step, we'll then explain how we can rotate the element to face its direction of travel.\n\nYou can [fork this CodePen](https://codepen.io/popmotion/pen/qpRROg?editors=0010) to follow along.\n\n## Position\n\nWe can convert `radius` and `angle` into `x` and `y` using `cos` and `sin` functions:\n\n```javascript\nconst x = radius * Math.cos(angle);\nconst y = radius * Math.sin(angle);\n```\n\nBy expressing this as a pure function, we'll be able to provide it to any animation's `pipe` method:\n\n```javascript\nconst polarToCartesian = ({ angle, radius }) => ({\n  x: radius * Math.cos(angle),\n  y: radius * Math.sin(angle)\n});\n```\n\nWith this function we can write a simple animation that:\n- 1) Changes `radius` at a constant velocity of 5 radians a second.\n- 2) Pipes the animation output through `polarToCartesian` to convert into `x` and `y`.\n- 3) Styles the div by using `boxStyler.set`:\n\n```javascript\nphysics({\n  from: { angle: 0, radius: 150 },\n  velocity: { angle: 5, radius: 0 }\n}).pipe(polarToCartesian)\n  .start(boxStyler.set);\n```\n\nNow our box moves in a circular motion.\n\n<CodePen id=\"GyrWJv\" />\n\nIn this animation we're keeping `radius` at a constant value by setting `velocity` to `0`. By using the `composite` function, we can combine two different animations to animate `radius` and `angle` in different ways:\n\n```javascript\ncomposite({\n  angle: physics({ velocity: 5 }),\n  radius: tween({\n    from: 0,\n    to: 150,\n    yoyo: Infinity,\n    ease: easing.easeInOut,\n    duration: 2000\n  })\n}).pipe(polarToCartesian)\n  .start(boxStyler.set);\n```\n\n## Direction\n\nIt looks a little awkward to have a square stay upright as it moves in a circular motion.\n\nWe can calculate and inject a `rotate` property based on the current `angle` to ensure the square is facing the direction of travel.\n\nFirst, let's make our `polarToCartesian` function more composable by allowing it to pass through any properties that it doesn't consume using spread props:\n\n```javascript\nconst polarToCartesian = ({ angle, radius, ...props }) => ({\n  x: radius * Math.cos(angle),\n  y: radius * Math.sin(angle),\n  ...props\n});\n```\n\nNext, we need to make a function that simply takes `angle` and returns the angle perpendicular to it as a new property, `rotate`.\n\n`cos` and `sin` functions accept radians, whereas CSS and SVG `rotate` properties are defined in degrees. We can use Popmotion's [`radiansToDegrees` calculator](/api/calc) to convert `angle` into degrees, and then simply rotate it by `90`:\n\n```javascript\nconst rotatePerpendicular = (props) => {\n  const { angle } = props;\n  return {\n    rotate: radiansToDegrees(angle) + 90,\n    ...props\n  };\n};\n```\n\nApplying this new function is as easy as modifying `pipe` to read:\n\n```javascript\n.pipe(rotatePerpendicular, polarToCartesian)\n```\n\n<CodePen id=\"PEWWmG\" />\n\n## Conclusion\n\nCircular motion is much easier to reason about in polar coordinates, and mapping these to cartesian is simple with `pipe`.\n\nWe can animate `angle` and `radius` with separate animations by using the `composite` composition function.\n\nAnd finally, we can make the element rotate along with the direction of travel by converting `angle` into degrees and then adding an extra `90` degrees.\n"
  },
  {
    "path": "packages/popmotion/docs/learn/how-to/constrain-motion.md",
    "content": "---\ntitle: Constrain motion\ndescription: How to constrain motion to within ranges using clamping and springs.\ncategory: how-to\n---\n\n# Constrain motion\n\nWhen creating UIs, there's plenty of instances when we want to constrain motion to within a specific range.\n\nFor instance, if we're making an input slider, we want to constrain its sliding motion to within the slider's visible boundaries.\n\nOtherwise, the illusion of a coherent piece of UI is broken, and the input is useless:\n\n<CodePen id=\"KZzWdz\" height={200} />\n\nIn this tutorial, we'll look at a functional approach to solving this problem. We'll handle out-of-range motion with 1) a hard clamp, and 2) a static spring.\n\nYou can follow along by forking [this CodePen](https://codepen.io/popmotion/pen/KZzWdz?editors=0010).\n\n## Clamp\n\nThe easiest way to restrict motion to within a range is by clamping it. Clamping is simply the process of restricting a number within a range.\n\nJavaScript includes two commonly-used clamping functions, `Math.min` and `Math.max`.\n\nWe can change the dragging action from:\n\n```javascript\npointerX(handleX.get())\n  .start(handleX)\n```\n\nTo:\n\n```javascript\npointerX(handleX.get())\n  .pipe(v => Math.max(0, v))\n  .start(handleX)\n```\n\nBy using `Math.max` to clamp the lower range to `0`, you'll notice you can't drag the handle beyond the left boundary:\n\n<CodePen id=\"ppyeGW\" height={200 />\n\nWe could add the right boundary like this:\n\n```javascript\npointerX(handleX.get())\n  .pipe(\n    v => Math.max(0, v),\n    v => Math.min(250, v)\n  )\n  .start(handleX)\n```\n\nPopmotion provides a clearer way of expressing this via the `clamp` [transformer](/api/transformers). This function accepts a range and returns a function that will clamp any provided number to within that range:\n\n```javascript\nclamp(0, 250)(-50) // 0\n```\n\nSo our `pointerX` function becomes:\n\n```javascript\npointerX(handleX.get())\n  .pipe(clamp(0, 250))\n  .start(handleX)\n```\n\n<CodePen id=\"eyZvar\" height={200} />\n\nWe now have a functional input slider! But we don't have a **delightful** one.\n\nThink of iOS, when you scroll a view beyond its boundaries. It doesn't stop dead, it tugs back. It's a visceral and satisfying experience.\n\nWe can replicate this experience with Popmotion using static springs.\n\n## Static springs\n\nPopmotion has so many springs you could use it as a mattress. It's not a point of pride, it can be confusing. But, different springs are useful in different situations:\n\n- [Spring](/api/spring) is a highly-accurate simulation, but immutable. Most appropriate for **spring animations**.\n- [Physics](/api/physics) is a lightweight integrated simulation that can change over time. Most appropriate for **spring interactions**.\n\nOf the two, `physics`, in theory, could be used to restrain motion to a range. But it's overkill. You'd have to set conditional statements to start and stop animations, grab the velocity from `handleX`, set this and that. It'd be an imperative soup.\n\nInstead, Popmotion provides two transformers that can be used in a purely functional manner: `linearSpring` and `nonlinearSpring`.\n\nThey both share an API. Provide a `strength` and a `target`, and they'll return a function. This function, when given a numerical value, will return a new number \"pulled\" towards the target.\n\n```javascript\nlinearSpring(0.25, 0)(4) // 1\n```\n\n`linearSpring` applies a **constant force**, whereas `nonlinearSpring` applies a **greater force the further the given number is away from `target`**.\n\nIn tandem with the `conditional` transformer, we can apply these springs only when the number output by `pointerX` exceeds the defined boundaries:\n\n```javascript\nconditional(\n  v => v < 0, // If less than 0\n  linearSpring(0.25, 0) // Apply spring\n)\n```\n\nLet's compose a new function using `pipe`, `conditional` and `linearSpring` that will restrict a range of motion using springs:\n\n```javascript\nconst springRange = (from, to, strength) => pipe(\n  conditional(\n    v => v < from,\n    linearSpring(strength, from)\n  ),\n  conditional(\n    v => v > to,\n    linearSpring(strength, to)\n  )\n);\n```\n\nThis can be passed to our `pipe`:\n\n```javascript\npointerX(handleX.get())\n  .pipe(springRange(0, 200, 0.2))\n  .start(handleX)\n```\n\nTo create spring-restricted motion that feels like this:\n\n<CodePen id=\"jYqmEa\" height={200} />\n\nTry replacing `linearSpring` with `nonlinearSpring` and adjust the `strength` to see how that changes the behaviour of the handle.\n\n### Spring back\n\nYou'll notice that if you release the handle outside the slider's boundaries, it just sits still. This is at odds with the perceived spring that binds the handle to the slider.\n\nFor this, we can start a `spring` animation on the mouseup/touchend event.\n\nCurrently, we just call `() => handleX.stop()` which ungracefully stops any action driving `handleX`, which in this example is `pointerX`.\n\nLet's replace this reaction with:\n\n```javascript\n() => {\n  const x = handleX.get()\n\n  if (x < 0 || x > 250) {\n    // Start spring animation\n  } else {\n    handleX.stop();\n  }\n}\n```\n\nNow the function will only stop motion abruptly if the handle is **within** the slider's range.\n\nTo handle cases when the handle is **outside** the range, replace the commented line with this:\n\n```javascript\nspring({\n  from: x,\n  to: x < 0 ? 0 : 250,\n  velocity: handleX.getVelocity(),\n  stiffness: 900,\n  damping: 30\n}).start(handleX);\n```\n\n<CodePen id=\"xpVdLv\" height={200} />\n\nYou can play around with the settings of both the static spring and the `spring` animation until you find something that feels responsive, satisfying and in-keeping with your brand.\n\n## Conclusion\n\nWe can declaratively implement motion constraints using functional composition.\n\nClamping is the most basic approach, but static springs can yield more satisfying results when paired with user input.\n\n`pipe` and `conditional` allow you the freedom to devise and compose your own strategies for imposing motion constraints.\n\nA couple ideas for next steps:\n\n- Replace the `stop` call in our mouseup event with a `decay` animation that allows the user to throw the handle. It could include a little bump animation when it hits a slider limit.\n- Generate your own static springs using the `generateStaticSpring` transformer.\n"
  },
  {
    "path": "packages/popmotion/docs/learn/how-to/input-smoothing.md",
    "content": "---\ntitle: Input smoothing\ndescription: How to apply input smoothing to mouse and touch input\ncategory: how-to\n---\n\n# Input smoothing\n\nYou can easily add input smoothing to pointer tracking using some light functional composition.\n\nDrag this ball to see pointer tracking without smoothing:\n\n```marksy\n<Example template=\"Ball\" id=\"a\" autostart={true}>{`\nconst ball = document.querySelector('#a .ball');\nconst ballStyler = styler(ball);\nconst ballXY = value({ x: 0, y: 0 }, ballStyler.set);\n\nlet pointerTracker;\n\nconst startTracking = () => {\n  pointerTracker = pointer(ballXY.get())\n    .start(ballXY);\n};\n\nconst stopTracking = () => {\n  if (pointerTracker) pointerTracker.stop();\n};\n\nlisten(ball, 'mousedown touchstart').start(startTracking);\nlisten(document, 'mouseup touchend').start(stopTracking);\n`}</Example>\n```\n\nAnd now with smoothing applied:\n\n```marksy\n<Example template=\"Ball\" id=\"b\" autostart={true}>{`\nconst ball = document.querySelector('#b .ball');\nconst ballStyler = styler(ball);\nconst ballXY = value({ x: 0, y: 0 }, ballStyler.set);\n\nconst { transformMap, smooth } = transform;\nlet pointerTracker;\n\nconst startTracking = () => {\n  pointerTracker = pointer(ballXY.get())\n    .pipe(transformMap({\n      x: smooth(200),\n      y: smooth(200)\n    }))\n    .start(ballXY);\n};\n\nconst stopTracking = () => {\n  if (pointerTracker) pointerTracker.stop();\n};\n\nlisten(ball, 'mousedown touchstart').start(startTracking);\nlisten(document, 'mouseup touchend').start(stopTracking);\n`}</Example>\n```\n\n## Add smoothing\n\nWe can use the `smooth` [transformer](/api/transformers#smooth) to apply smoothing to any numerical value.\n\n`smooth` works by passing a smoothing amount, in milliseconds. This is the duration over which movement will be averaged. So, high numbers equal greater smoothing.\n\n```javascript\nsmooth(200)\n```\n\n**Importantly**, a new instance of `smooth` must be created for each value we want to smooth. This is because the returned function refers to an internal average value. If we pass it multiple values from different sources, it can't work!\n\n### Multi-axis smoothing\n\nSo, our `pointer` might originally look like this:\n\n```javascript\npointer({ x: 0, y: 0 })\n  .start(({ x, y }) => /* unsmoothed output */)\n```\n\nTo apply smoothing on both `x` and `y`, we can use the `transformMap` transformer along with `smooth`:\n\n```javascript\nimport { pointer, transform } from 'popmotion';\nconst { transformMap, smooth } = transform;\n\npointer({ x: 0, y: 0 })\n  .pipe(transformMap({\n    x: smooth(200),\n    y: smooth(200)\n  }))\n  .start(({ x, y }) => /* smoothed! */)\n```\n\n### Single-axis smoothing\n\nIf we're just tracking a single axis, we don't even need `transformMap`:\n\n```javascript\npointer({ x: 0, y: 0 })\n  .pipe(\n    ({ x }) => x,\n    smooth(200)\n  ).start((x) => /* smoothed x axis */)\n```\n\n## Conclusion\n\nBy using `smooth`, we can apply smoothing to not just `pointer` output, but that of any action.\n\nMore examples of `pipe` and functional composition can be found in the [value pipelines](/api/value-pipelines) tutorial.\n"
  },
  {
    "path": "packages/popmotion/docs/learn/how-to/morph-svg.md",
    "content": "---\ntitle: Morph SVG\ndescription: How to animate between two SVG shapes with Popmotion.\ncategory: how-to\n---\n\n# Morph SVG\n\nPopmotion animations can be used to morph between any two SVG `path` shapes.\n\nSVG-morphing libraries [Flubber](https://github.com/veltman/flubber) and [Polymorph](https://github.com/notoriousb1t/polymorph) both functions that accept a value between 0 and 1 to blend between two shapes. This works great with Popmotion's functional API, and animating the morph is as simple as this:\n\n```javascript\ntween()\n  .pipe(morph)\n  .start(styler(pathElement).set('d'));\n```\n\nIn this quick tutorial we'll define this `morph` function with both Flubber and Polymorph and animate it with a `tween`.\n\n## Set up\n\nFirst, we need an SVG with a `path` element to render into.\n\n```html\n<svg viewBox=\"0 0 400 400\">\n  <path id=\"target\" />\n</svg>\n```\n\nAs we're going to animate the `path`'s verbosely-named `d` attribute, which defines the shape of the path, we can use Popmotion's [`styler` function](/api/styler) to create an optimised setter:\n\n```javascript\nconst path = document.getElementById('#target');\nconst setPathAttr = styler(path).set('d');\n```\n\nNow we simply need a path definition string to provide to `setPathAttr`.\n\n## Flubber\n\n<CodePen id=\"yProEp\" />\n\n[Flubber](https://github.com/veltman/flubber) is a fully-featured morphing library that yields very accurate and pleasing results. The drawback being its filesize: A whopping 53kb!\n\nOnce you've installed and imported Flubber according to the docs, you can make the `morph` function using `flubber.interpolate`.\n\nThis function accepts two strings, one of each path you want to morph between:\n\n```javascript\nconst star = \"M103.04 162.52L39.36 196l12.16-70.9L0 74.86 71.2 64.5 103.04 0l31.85 64.52 71.2 10.35-51.57 50.22L166.7 196z\";\nconst circle = \"M86,171.5 C38.7796539,171.5 0.5,133.220346 0.5,86 C0.5,38.7796539 38.7796539,0.5 86,0.5 C133.220346,0.5 171.5,38.7796539 171.5,86 C171.5,133.220346 133.220346,171.5 86,171.5 Z\";\n\nconst morph = flubber.interpolate(circle, star);\n```\n\nBy default, the blending of the two shapes is pretty rough. We can pass `interpolate` a third options argument `{ maxSegmentLength: 2 }` to output more accurate shapes, though this might have performance impacts with more complex blends.\n\nThe generated `morph` function accepts a number between `0` and `1` and outputs a path definition string generated from a blend of `circle` and `star`.\n\nSo to animate our target `path`, we simply need to write an animation that outputs a number between `0` and `1` and provide `morph` to its `pipe` method so its output is the new path:\n\n```javascript\ntween()\n  .pipe(morph)\n  .start(setPathAttr);\n```\n\n## Polymorph\n\n<CodePen id=\"dZLRLq\" />\n\n[Polymorph](https://github.com/notoriousb1t/polymorph) is a much lighter library clocking in at just 6kb! For complex shapes it works just as well as Flubber, though results may vary for simpler shapes. \n\nSetup works a little differently as it takes `path` definitions from existing elements, so we'll need to add those:\n\n```html\n<svg>\n  <path id=\"Oval\" d=\"M86,171.5 C38.7796539,171.5 0.5,133.220346 0.5,86 C0.5,38.7796539 38.7796539,0.5 86,0.5 C133.220346,0.5 171.5,38.7796539 171.5,86 C171.5,133.220346 133.220346,171.5 86,171.5 Z\" />\n  <path id=\"Star\" d=\"M103.04 162.52L39.36 196l12.16-70.9L0 74.86 71.2 64.5 103.04 0l31.85 64.52 71.2 10.35-51.57 50.22L166.7 196z\" />\n</svg>\n```\n\nWe simply provide the element ids to `polymorph.interpolate`, along with an optional `precision` setting:\n\n```javascript\nconst morph = polymorph.interpolate(['#Star', '#Oval'], { precision: 4 });\n\ntween()\n  .pipe(morph)\n  .start(setPathAttr);\n```\n\n## Next steps\n\nPopmotion, Flubber and Polymorph's functional approach gives you the freedom to combine whichever libraries suit your project.\n\nIn this article, we've shown how simple it is to animate between shapes using `tween`. You could play around with other animations like `pointer`, which would make the blending scrubbable:\n\n```javascript\npointer()\n  .pipe(\n    ({ x }) => x,\n    interpolate([0, window.innerWidth], [0, 1])\n  )\n  .start()\n```\n\nOne caveat, however, is neither library accepts numbers outside of `0` and `1`, which entails the following:\n\n- `spring` needs to be overdamped by choosing a `damping` property high enough to prevent overshoot.\n- Easing functions that generate overshoot, like `backOut`, will lead to stunted animations.\n\nYou can of course `pipe` animations through the `clamp` [transformer](/api/transformers) for safety, but ideally you'll want to create animations that don't exceed these limits.\n"
  },
  {
    "path": "packages/popmotion/docs/learn/how-to/rounded-values.md",
    "content": "---\ntitle: Rounded values\ndescription: How to output rounded values from any action\ncategory: how-to\n---\n\n# Rounded values\n\nPopmotion's emphasis on functional composition means actions don't offer explicit support via properties like `rounded: true`.\n\nInstead, we can round the output of any [action](/api/action) by providing JavaScript's native `Math.round` to `pipe`. For instance:\n\n## Round a single value\n\nIf we have a `tween` that outputs a single value, we can round it like this:\n\n```javascript\ntween({ to: 1000 }).pipe(Math.round)\n```\n\n```marksy\n<Example template=\"Counter\" id=\"a\" autostart={false}>{`\nconst counter = document.querySelector('#a .counter');\nconst updateCounter = (v) => counter.innerHTML = v;\n\ntween({ to: 1000, duration: 2000 })\n  .pipe(Math.round)\n  .start(updateCounter);\n`}</Example>\n```\n\nEvery animation is an action, so this applies to animations like `physics` too:\n\n```javascript\nphysics({ velocity: 100 }).pipe(Math.round)\n```\n\n```marksy\n<Example template=\"Counter\" id=\"b\" autostart={false}>{`\nconst counter = document.querySelector('#b .counter');\nconst updateCounter = (v) => counter.innerHTML = v;\n\nphysics({ velocity: 100 })\n  .pipe(Math.round)\n  .start(updateCounter);\n`}</Example>\n```\n\n## Round a complex value\n\nIf we're animating an object, we can apply rounding to specific values using the `transformMap` [transformer](/api/transformers#transformmap):\n\n```javascript\nimport { tween, transform } from 'popmotion';\nconst { transformMap } = transform;\n\ntween({\n  to: { x: 100, y: 100 }\n}).pipe(transformMap({\n  x: Math.round\n}));\n```\n\nMore examples of `pipe` and functional composition can be found in the [value pipelines](/api/value-pipelines) tutorial.\n"
  },
  {
    "path": "packages/popmotion/docs/learn/projects/spring-loaded-characters-remaining.md",
    "content": "---\ntitle: \"Spring-loaded 'characters remaining' counter\"\ndescription: Inject some fun into your text fields with a spring-loaded characters remaining counter.\ncategory: projects\n---\n\n# Spring-loaded \"characters remaining\" counter\n\nForms are, by nature, dreary. From a user's perspective, there's nothing fun about them: Non-zero friction, mental effort, the cold exchange of info for goods.\n\nIt doesn't have to be this way! By adding thoughtful little touches, we can soften the negative form experience and maybe even make something a little bit delightful.\n\nIn this tutorial we're going to take a traditionally mundane part of form, the remaining character counter, and increase its functionality by adding a little playfulness.\n\nWe're going to attach a spring that fires on every keypress that goes over the character count limit, drawing attention to the counter. We're also going to slowly change the counter color to red as we approach the limit.\n\nHave a play by typing in this box:\n\n<CodePen id=\"JOeemQ\" />\n\nTo begin, you can use [this CodePen template](https://codepen.io/popmotion/pen/XzyypY?editors=0010) to follow along.\n\n## The counter\n\nOur first job is to get the counter to actually count down as a user enters characters.\n\nThe input field's `maxlength` is set to `10`. We can read this with JavaScript:\n\n```javascript\nconst charLimit = parseInt(input.getAttribute('maxlength'));\n```\n\nNow, let's create a function that takes a string and updates the character counter with the remaining number of characters, which will be calculated by measuring the string and subtracting that from the `charLimit`:\n\n```javascript\nfunction updateRemainingCharsCounter(val) {\n  counter.innerHTML = charLimit - val.length;\n}\n```\n\nWe can test that this function works by, on the following line, writing:\n\n```javascript\nupdateRemainingCharsCounter('test');\n```\n\n`'test'` is four characters long, so our counter displays `6`.\n\nWe want this function to fire on every `keyup` event, as this event carries the `input` field's latest value.\n\nWe're going to use the [`listen` action](/api/listen) to bind the event. `listen` converts DOM events into reactive streams. As an action, we can use `pipe` to pick the latest value out of the event before passing it on to `updateRemainingCharsCounter`:\n\n```javascript\nlisten(input, 'keyup')\n  .pipe(e => e.target.value)\n  .start(updateRemainingCharsCounter);\n```\n\nNow when you type, the character counter updates!\n\nWe have a functional counter, but not a delightful one. Let's attach a `spring`.\n\n## The spring\n\nWe're going to use the spring to increase the counter's `scale` property.\n\nThis isn't just going to look playful. By rapidly enlarging the counter, it'll draw the user's attention. You could use a little shake, or another effect. It's the movement itself that will distract the user to make sure they understand that there's no space for new characters.\n\nUnlike a simple `tween`, spring physics can take into account a pre-existing velocity. This will make the animation interactive and playful: I haven't seen many people resist hammering away at the keyboard once they realise rapid keypresses builds momentum!\n\n### Rendering the counter's `scale` prop\n\nFirst, we need to import the [`value`](/api/value) and [`styler`](/api/styler) functions.\n\n`value` will help us track and measure the velocity of `scale`, and `styler` will enable us to render it performantly.\n\n```javascript\nconst { listen, value, styler } = window.popmotion;\n```\n\nWe make our styler by simply passing the `counter`'s DOM node to `styler`:\n\n```javascript\nconst counterStyler = styler(counter);\n```\n\nAnd we can initialise the `counterScale` value by passing it an initial value (`1`), and create a setter function with `counterStyler.set`: \n\n```javascript\nconst counterScale = value(1, counterStyler.set('scale'));\n```\n\nNow, whenever `counterScale` updates, the `counter` DOM node will be updated too.\n\n### Listening to `keydown`\n\nWe also need to listen for a new event, `keydown`.\n\nThis event the moment the user presses down on the key, which is the moment they're imparting their physical energy into the UI.\n\nIt feels very responsive - try putting the following code under a `keyup` event instead and you'll immediately notice how disconnected the animation feels from your physical actions.\n\nWe'll use `listen` again, this time chained with a different method, `filter`. \n\n`filter`, as the name implies, filters out values that don't meet the provided criteria. In this case, we want to create an event listener that only fires when the number of entered characters is the same as the `chatLimit`:\n\n```javascript\nlisten(input, 'keydown')\n  .filter(e => e.target.value.length === charLimit)\n  .start(fireSpring);\n```\n\n### The `spring` function\n\nNow, we're ready to add our `spring`.\n\n```javascript\nconst { listen, value, styler, spring } = window.popmotion;\n```\n\nBefore this event listener, create a new function called `fireSpring` that'll start a new `spring` animation:\n\n```javascript\nfunction fireSpring() {\n  spring({\n    // Start the animation from the current scale:\n    from: counterScale.get()\n\n    // We want the spring to rest on 1\n    to: 1,\n\n    // We set the initial velocity to whichever the smallest is:\n    // a) counterScale's current velocity, or\n    // b) an arbitrary minimum. You can experiment.\n    velocity: Math.max(counterScale.getVelocity(), 100),\n\n    // This ratio of stiffness to damping gives a nice, tight spring. Experiment!\n    stiffness: 700,\n    damping: 80\n  }).start(counterScale);\n}\n```\n\nBy tweaking the properties of `spring`, you can make springs with wildly different feelings. Some can be playful, some can be terse. Try to find one appropriate for your brand or website.\n\nThere's one final modification to make. Currently, the spring says \"Hey! You've reached the character count!\" in a loud and abrupt way. By slowly changing the color of the counter we can also quietly inform the user that they're **approaching** the limit.\n\n## The warning color\n\nWe're going to compose a very simple [value pipeline](/learn/value-pipelines) function that will convert our remaining character count into a color.\n\nWe can use three of Popmotion's [transformers](/api/transformers) to achieve this: `pipe`, `blendColor`, and `interpolate`.\n\nWe'll use `pipe` to make a new function. This new function will accept a character count and map that to a value between `0` and `1`. That new number is then used to blend between the `counter`'s text color and red:\n\nImport:\n\n```javascript\nconst { listen, value, styler, spring, transform } = window.popmotion;\nconst { blendColor, interpolate, pipe } = transform;\n```\n\nAnd then, after we define `charLimit` and `counterStyler`, create our new function:\n\n```javascript\nconst convertCountToColor = pipe(\n  // The input range starts at half the charLimit and ends at the\n  // charLimit itself. This means the color will start changing, in this\n  // instance, when the counter hits 5\n  interpolate([charLimit * 0.5, charLimit], [0, 1]),\n  blendColor(counterStyler.get('color'), '#f00')\n);\n```\n\nNow we just need to amend our `updateRemainingCharsCounter` function to set `counterStyler`'s `'color'` property with the output of this function:\n\n```javascript\nfunction updateRemainingCharsCounter(val) {\n  // Measure char count\n  const charCount = val.length;\n\n  // Set remaining chars\n  counter.innerHTML = charLimit - charCount;\n\n  // Set counter color\n  counterStyler.set('color', convertCharCountToColor(charCount));\n}\n```\n\nNow when you type, the counter will begin to change color as your reach the character limit.\n\n## Further optimisations\n\nThat's all for this tutorial, but there's plenty of ways in which we can go on to improve this form field counter:\n\n- Visual `focus` state - maybe only show the character remaining count while the input has focus.\n- Allow extra characters to be entered, and allow the \"characters remaining\" counter to run into the negatives.\n- Not firing the spring on backspace.\n- Only show the counter if JavaScript has loaded.\n"
  },
  {
    "path": "packages/popmotion/package.json",
    "content": "{\n    \"name\": \"popmotion\",\n    \"version\": \"11.0.5\",\n    \"description\": \"The animator's toolbox\",\n    \"author\": \"Matt Perry\",\n    \"homepage\": \"https://popmotion.io\",\n    \"main\": \"dist/popmotion.cjs.js\",\n    \"types\": \"lib/index.d.ts\",\n    \"module\": \"dist/es/index.mjs\",\n    \"jsnext:main\": \"dist/es/index.mjs\",\n    \"unpkg\": \"./dist/popmotion.min.js\",\n    \"exports\": {\n        \".\": {\n            \"types\": \"./lib/index.d.ts\",\n            \"import\": \"./dist/es/index.mjs\",\n            \"require\": \"./dist/popmotion.cjs.js\",\n            \"default\": \"./dist/popmotion.cjs.js\"\n        },\n        \"./package.json\": \"./package.json\"\n    },\n    \"sideEffects\": false,\n    \"repository\": {\n        \"type\": \"git\",\n        \"url\": \"https://github.com/Popmotion/popmotion/tree/master/packages/popmotion\"\n    },\n    \"bugs\": {\n        \"url\": \"https://github.com/Popmotion/popmotion/issues\"\n    },\n    \"keywords\": [\n        \"animation\",\n        \"ux\",\n        \"ui\",\n        \"popmotion\",\n        \"canvas animation\",\n        \"dom animation\",\n        \"dom\",\n        \"pointer tracking\",\n        \"mouse\",\n        \"mouse tracking\",\n        \"touch\",\n        \"touch tracking\",\n        \"physics\",\n        \"interaction\",\n        \"interface\",\n        \"svg\"\n    ],\n    \"analyze\": true,\n    \"license\": \"MIT\",\n    \"scripts\": {\n        \"build\": \"tsc -p . && rollup -c && yarn measure\",\n        \"postbuild\": \"yarn babel $npm_package_module --out-file $npm_package_module --no-babelrc --plugins annotate-pure-calls\",\n        \"dev\": \"rollup -c -w\",\n        \"prepublishOnly\": \"yarn test && yarn build\",\n        \"measure\": \"gzip -c $npm_package_unpkg | wc -c\",\n        \"test\": \"jest --coverage --maxWorkers=2\",\n        \"publish-beta\": \"npm publish --tag beta\"\n    },\n    \"dependencies\": {\n        \"framesync\": \"6.1.2\",\n        \"hey-listen\": \"^1.0.8\",\n        \"style-value-types\": \"5.1.2\",\n        \"tslib\": \"2.4.0\"\n    },\n    \"devDependencies\": {\n        \"@rollup/plugin-commonjs\": \"^11.0.1\",\n        \"tslint-circular-dependencies\": \"^0.1.0\",\n        \"typescript\": \"^4.2.3\"\n    },\n    \"prettier\": {\n        \"printWidth\": 80,\n        \"tabWidth\": 4,\n        \"semi\": false,\n        \"trailingComma\": \"es5\"\n    },\n    \"jest\": {\n        \"moduleFileExtensions\": [\n            \"ts\",\n            \"js\"\n        ],\n        \"moduleNameMapper\": {\n            \"style-value-types\": \"<rootDir>/../../style-value-types/src\",\n            \"framesync\": \"<rootDir>/../../framesync/src\"\n        },\n        \"transform\": {\n            \"\\\\.(ts)$\": \"../../../node_modules/ts-jest/preprocessor.js\"\n        },\n        \"testRegex\": \"/__tests__/.*\\\\.test.(ts|js)$\",\n        \"rootDir\": \"src\",\n        \"collectCoverageFrom\": [\n            \"**/*.{js,jsx,ts,tsx}\",\n            \"!**/node_modules/**\",\n            \"!**/__tests__/**\",\n            \"!**/worklet/**\"\n        ],\n        \"coverageDirectory\": \"<rootDir>/../coverage\"\n    }\n}\n"
  },
  {
    "path": "packages/popmotion/rollup.config.js",
    "content": "import typescript from 'rollup-plugin-typescript2';\nimport generateConfig from '../../rollup-generate-config';\nimport replace from '@rollup/plugin-replace';\nimport resolve from '@rollup/plugin-node-resolve';\nimport commonJS from '@rollup/plugin-commonjs';\nimport pkg from './package.json';\n\nconst worklet = {\n  input: 'src/worklet/index.ts',\n  output: [\n    {\n      // TODO: Make this not git-ignored\n      file: `dist/popmotion-worklet.js`,\n      format: 'umd'\n    },\n    {\n      file: `../../playground/public/popmotion-worklet.js`,\n      format: 'umd'\n    }\n  ],\n  plugins: [\n    resolve(),\n    commonJS({\n      include: 'node_modules/**'\n    }),\n    typescript(),\n    replace({\n      'process.env.NODE_ENV': JSON.stringify('production')\n    })\n  ]\n};\n\nexport default [...generateConfig(pkg)]; //, worklet];\n"
  },
  {
    "path": "packages/popmotion/src/animations/__tests__/animate.test.ts",
    "content": "import { animate } from \"..\"\nimport { linear, easeOut } from \"../..\"\nimport { AnimationOptions } from \"../types\"\nimport { syncDriver } from \"./utils\"\n\nfunction testAnimate<V>(\n    options: AnimationOptions<V>,\n    expected: V[],\n    resolve: () => void\n) {\n    const output: V[] = []\n    animate({\n        driver: syncDriver(20),\n        duration: 100,\n        ease: linear,\n        onUpdate: (v) => output.push(v),\n        onComplete: () => {\n            expect(output).toEqual(expected)\n            resolve()\n        },\n        ...options,\n    })\n}\n\ndescribe(\"animate\", () => {\n    test(\"Correctly performs an animation with default settings\", async (resolve) => {\n        await testAnimate({ to: 100 }, [0, 20, 40, 60, 80, 100], resolve)\n    })\n    test(\"Correctly uses a keyframes animation if to is an array\", async (resolve) => {\n        await testAnimate(\n            { to: [0, 100], type: \"spring\" },\n            [0, 20, 40, 60, 80, 100],\n            resolve\n        )\n    })\n\n    test(\"Correctly stops an animation\", async (resolve) => {\n        const output: number[] = []\n        const animation = animate({\n            to: 100,\n            driver: syncDriver(20),\n            duration: 100,\n            ease: linear,\n            onUpdate: (v) => {\n                output.push(v)\n                if (v === 40) {\n                    animation.stop()\n                }\n            },\n            onStop: () => {\n                expect(output).toEqual([0, 20, 40])\n                resolve()\n            },\n        })\n    })\n\n    test(\"Correctly interpolates a string-based keyframes\", async (resolve) => {\n        const numeric: number[] = []\n        const string: number[] = []\n        animate({\n            driver: syncDriver(20),\n            duration: 100,\n            ease: linear,\n            from: 0,\n            to: 200,\n            onUpdate: (v) => numeric.push(v),\n            onComplete: () => {\n                expect(numeric).toEqual([0, 40, 80, 120, 160, 200])\n\n                animate({\n                    driver: syncDriver(20),\n                    duration: 100,\n                    ease: linear,\n                    from: \"0%\",\n                    to: \"200%\",\n                    onUpdate: (v) => numeric.push(parseFloat(v)),\n                    onComplete: () => {\n                        expect(string).not.toEqual(numeric)\n                        resolve()\n                    },\n                })\n            },\n        })\n    })\n\n    test(\"Correctly interpolates a string-based spring\", async (resolve) => {\n        const numeric: number[] = []\n        const string: number[] = []\n        animate({\n            type: \"spring\",\n            driver: syncDriver(50),\n            from: 0,\n            to: 200,\n            restSpeed: 10,\n            restDelta: 0.5,\n            onUpdate: (v) => numeric.push(Math.round(v)),\n            onComplete: () => {\n                expect(numeric).toEqual([\n                    0,\n                    21,\n                    68,\n                    122,\n                    170,\n                    205,\n                    225,\n                    232,\n                    231,\n                    224,\n                    215,\n                    207,\n                    200,\n                    197,\n                    195,\n                    195,\n                    196,\n                    197,\n                    199,\n                    200,\n                    200,\n                    201,\n                    201,\n                    201,\n                    201,\n                    200,\n                ])\n\n                animate({\n                    driver: syncDriver(50),\n                    duration: 100,\n                    ease: linear,\n                    from: \"0%\",\n                    to: \"200%\",\n                    type: \"spring\",\n                    onUpdate: (v) => numeric.push(Math.round(parseFloat(v))),\n                    onComplete: () => {\n                        expect(string).not.toEqual(numeric)\n                        resolve()\n                    },\n                })\n            },\n        })\n    })\n\n    test(\"Correctly uses a spring if type is defined explicitly\", async (resolve) => {\n        const output: unknown[] = []\n        animate({\n            driver: syncDriver(20),\n            duration: 100,\n            ease: linear,\n            onUpdate: (v) => output.push(v),\n            onComplete: () => {\n                expect(output).not.toEqual([0, 20, 40, 60, 80, 100])\n                resolve()\n            },\n            type: \"spring\",\n        })\n    })\n\n    test(\"Performs a keyframes animations when to is an array\", async (resolve) => {\n        testAnimate(\n            { to: [0, 50, -20], duration: 200 },\n            [0, 10, 20, 30, 40, 50, 36, 22, 8, -6, -20],\n            resolve\n        )\n    })\n\n    test(\"Performs a keyframes animations when to is an array of strings\", async (resolve) => {\n        testAnimate(\n            { to: [\"#f00\", \"#0f0\", \"#00f\"] },\n            [\n                \"rgba(255, 0, 0, 1)\",\n                \"rgba(198, 161, 0, 1)\",\n                \"rgba(114, 228, 0, 1)\",\n                \"rgba(0, 228, 114, 1)\",\n                \"rgba(0, 161, 198, 1)\",\n                \"rgba(0, 0, 255, 1)\",\n            ],\n            resolve\n        )\n    })\n\n    test(\"Correctly animates from/to with a keyframes animation by default\", async (resolve) => {\n        testAnimate({ from: 50, to: 150 }, [50, 70, 90, 110, 130, 150], resolve)\n    })\n\n    test(\"Correctly animates from/to strings with a keyframes animation by default\", async (resolve) => {\n        testAnimate(\n            { from: \"#f00\", to: \"#00f\" },\n            [\n                \"rgba(255, 0, 0, 1)\",\n                \"rgba(228, 0, 114, 1)\",\n                \"rgba(198, 0, 161, 1)\",\n                \"rgba(161, 0, 198, 1)\",\n                \"rgba(114, 0, 228, 1)\",\n                \"rgba(0, 0, 255, 1)\",\n            ],\n            resolve\n        )\n    })\n\n    test(\"Accepts a negative elapsed as delay\", async (resolve) => {\n        testAnimate(\n            { to: 100, elapsed: -100 },\n            [0, 0, 0, 0, 0, 0, 20, 40, 60, 80, 100],\n            resolve\n        )\n    })\n\n    test(\"Correctly repeats\", async (resolve) => {\n        testAnimate(\n            { to: 100, repeat: 1 },\n            [0, 20, 40, 60, 80, 100, 20, 40, 60, 80, 100],\n            resolve\n        )\n    })\n\n    test(\"Correctly applies repeat type 'reverse'\", async (resolve) => {\n        testAnimate(\n            { to: 100, repeat: 1, repeatType: \"reverse\" },\n            [0, 20, 40, 60, 80, 100, 80, 60, 40, 20, 0],\n            resolve\n        )\n    })\n\n    test(\"Correctly applies repeat type 'mirror'\", async (resolve) => {\n        testAnimate(\n            { to: 100, repeat: 1, ease: easeOut, repeatType: \"mirror\" },\n            [\n                0,\n                35.999999999999986,\n                64,\n                84,\n                96,\n                100,\n                64.00000000000001,\n                36,\n                16,\n                4,\n                0,\n            ],\n            resolve\n        )\n    })\n\n    test(\"Correctly applies repeatDelay\", async (resolve) => {\n        testAnimate(\n            { to: 100, repeat: 2, repeatDelay: 100 },\n            [\n                0,\n                20,\n                40,\n                60,\n                80,\n                100,\n                100,\n                100,\n                100,\n                100,\n                100,\n                20,\n                40,\n                60,\n                80,\n                100,\n                100,\n                100,\n                100,\n                100,\n                100,\n                20,\n                40,\n                60,\n                80,\n                100,\n            ],\n            resolve\n        )\n    })\n\n    test(\"Correctly applies repeatDelay to reverse\", async (resolve) => {\n        testAnimate(\n            { to: 100, repeat: 2, repeatDelay: 100, repeatType: \"reverse\" },\n            [\n                0,\n                20,\n                40,\n                60,\n                80,\n                100,\n                100,\n                100,\n                100,\n                100,\n                100,\n                80,\n                60,\n                40,\n                20,\n                0,\n                0,\n                0,\n                0,\n                0,\n                0,\n                20,\n                40,\n                60,\n                80,\n                100,\n            ],\n            resolve\n        )\n    })\n\n    test(\"Correctly applies repeatDelay to mirror\", async (resolve) => {\n        testAnimate(\n            {\n                to: 100,\n                ease: easeOut,\n                repeat: 2,\n                repeatDelay: 100,\n                repeatType: \"mirror\",\n            },\n            [\n                0,\n                35.999999999999986,\n                64,\n                84,\n                96,\n                100,\n                100,\n                100,\n                100,\n                100,\n                100,\n                64.00000000000001,\n                36,\n                16,\n                4,\n                0,\n                0,\n                0,\n                0,\n                0,\n                0,\n                35.999999999999986,\n                64,\n                84,\n                96,\n                100,\n            ],\n            resolve\n        )\n    })\n\n    test(\"Runs animations as an underdamped spring\", async (resolve) => {\n        const output: number[] = []\n        const expected = [\n            100,\n            371,\n            884,\n            1259,\n            1343,\n            1204,\n            1006,\n            883,\n            873,\n            937,\n            1011,\n            1050,\n            1046,\n            1018,\n            991,\n            980,\n            984,\n            996,\n            1005,\n            1008,\n            1005,\n            1001,\n            998,\n            997,\n            998,\n            1000,\n            1001,\n            1001,\n            1001,\n            1000,\n            1000,\n        ]\n        animate({\n            from: 100,\n            to: 1000,\n            stiffness: 300,\n            restSpeed: 10,\n            restDelta: 0.5,\n            driver: syncDriver(50),\n            onUpdate: (v) => output.push(Math.round(v)),\n            onComplete: () => {\n                expect(output).toEqual(expected)\n                resolve()\n            },\n        })\n    })\n\n    test(\"Runs animations as an overdamped spring\", async (resolve) => {\n        const output: number[] = []\n        const expected = [\n            100,\n            571,\n            802,\n            909,\n            958,\n            981,\n            991,\n            996,\n            998,\n            999,\n            1000,\n        ]\n        animate({\n            from: 100,\n            to: 1000,\n            stiffness: 300,\n            damping: 100,\n            restSpeed: 10,\n            restDelta: 0.5,\n            driver: syncDriver(250),\n            onUpdate: (v) => output.push(Math.round(v)),\n            onComplete: () => {\n                expect(output).toEqual(expected)\n                resolve()\n            },\n        })\n    })\n\n    test(\"Runs animations as a critically damped spring\", async (resolve) => {\n        const output: number[] = []\n        const expected = [\n            100,\n            181,\n            338,\n            498,\n            635,\n            741,\n            821,\n            878,\n            918,\n            945,\n            964,\n            976,\n            984,\n            990,\n            993,\n            996,\n            997,\n            998,\n            999,\n            999,\n            1000,\n        ]\n        animate({\n            from: 100,\n            to: 1000,\n            stiffness: 100,\n            damping: 20,\n            restSpeed: 10,\n            restDelta: 0.5,\n            driver: syncDriver(50),\n            onUpdate: (v) => output.push(Math.round(v)),\n            onComplete: () => {\n                expect(output).toEqual(expected)\n                resolve()\n            },\n        })\n    })\n\n    test(\"Runs spring animations on strings\", async (resolve) => {\n        const output: string[] = []\n        const expected = [\n            \"rgba(255, 0, 0, 1)\",\n            \"rgba(213, 0, 140, 1)\",\n            \"rgba(92, 0, 238, 1)\",\n            \"rgba(0, 0, 255, 1)\",\n            \"rgba(0, 0, 255, 1)\",\n            \"rgba(0, 0, 255, 1)\",\n            \"rgba(0, 0, 255, 1)\",\n            \"rgba(92, 0, 238, 1)\",\n            \"rgba(96, 0, 236, 1)\",\n            \"rgba(67, 0, 246, 1)\",\n            \"rgba(0, 0, 255, 1)\",\n            \"rgba(0, 0, 255, 1)\",\n            \"rgba(0, 0, 255, 1)\",\n            \"rgba(0, 0, 255, 1)\",\n            \"rgba(25, 0, 254, 1)\",\n            \"rgba(38, 0, 252, 1)\",\n            \"rgba(34, 0, 253, 1)\",\n            \"rgba(18, 0, 254, 1)\",\n            \"rgba(0, 0, 255, 1)\",\n            \"rgba(0, 0, 255, 1)\",\n            \"rgba(0, 0, 255, 1)\",\n            \"rgba(0, 0, 255, 1)\",\n        ]\n        animate({\n            from: \"#f00\",\n            to: \"#00f\",\n            stiffness: 300,\n            driver: syncDriver(50),\n            restSpeed: 10,\n            restDelta: 0.5,\n            onUpdate: (v) => output.push(v),\n            onComplete: () => {\n                expect(output).toEqual(expected)\n                resolve()\n            },\n        })\n    })\n\n    test(\"Repeats springs\", async (resolve) => {\n        const output: number[] = []\n        const expected = [\n            100,\n            371,\n            884,\n            1259,\n            1343,\n            1204,\n            1006,\n            883,\n            873,\n            937,\n            1011,\n            1050,\n            1046,\n            1018,\n            991,\n            980,\n            984,\n            996,\n            1005,\n            1008,\n            1005,\n            1001,\n            998,\n            997,\n            998,\n            1000,\n            1001,\n            1001,\n            1001,\n            1000,\n            1000,\n            371,\n            884,\n            1259,\n            1343,\n            1204,\n            1006,\n            883,\n            873,\n            937,\n            1011,\n            1050,\n            1046,\n            1018,\n            991,\n            980,\n            984,\n            996,\n            1005,\n            1008,\n            1005,\n            1001,\n            998,\n            997,\n            998,\n            1000,\n            1001,\n            1001,\n            1001,\n            1000,\n            1000,\n        ]\n        animate({\n            from: 100,\n            to: 1000,\n            stiffness: 300,\n            driver: syncDriver(50),\n            repeat: 1,\n            restSpeed: 10,\n            restDelta: 0.5,\n            onUpdate: (v) => output.push(Math.round(v)),\n            onComplete: () => {\n                expect(output).toEqual(expected)\n                resolve()\n            },\n        })\n    })\n\n    test(\"Repeats springs with repeat delay\", async (resolve) => {\n        const output: number[] = []\n        const expected = [\n            100,\n            371,\n            884,\n            1259,\n            1343,\n            1204,\n            1006,\n            883,\n            873,\n            937,\n            1011,\n            1050,\n            1046,\n            1018,\n            991,\n            980,\n            984,\n            996,\n            1005,\n            1008,\n            1005,\n            1001,\n            998,\n            997,\n            998,\n            1000,\n            1001,\n            1001,\n            1001,\n            1000,\n            1000,\n            1000,\n            1000,\n            1000,\n            1000,\n            1000,\n            1000,\n            371,\n            884,\n            1259,\n            1343,\n            1204,\n            1006,\n            883,\n            873,\n            937,\n            1011,\n            1050,\n            1046,\n            1018,\n            991,\n            980,\n            984,\n            996,\n            1005,\n            1008,\n            1005,\n            1001,\n            998,\n            997,\n            998,\n            1000,\n            1001,\n            1001,\n            1001,\n            1000,\n            1000,\n            1000,\n            1000,\n            1000,\n            1000,\n            1000,\n            1000,\n            371,\n            884,\n            1259,\n            1343,\n            1204,\n            1006,\n            883,\n            873,\n            937,\n            1011,\n            1050,\n            1046,\n            1018,\n            991,\n            980,\n            984,\n            996,\n            1005,\n            1008,\n            1005,\n            1001,\n            998,\n            997,\n            998,\n            1000,\n            1001,\n            1001,\n            1001,\n            1000,\n            1000,\n        ]\n        animate({\n            from: 100,\n            to: 1000,\n            stiffness: 300,\n            driver: syncDriver(50),\n            repeat: 2,\n            repeatDelay: 300,\n            restSpeed: 10,\n            restDelta: 0.5,\n            onUpdate: (v) => output.push(Math.round(v)),\n            onComplete: () => {\n                expect(output).toEqual(expected)\n                resolve()\n            },\n        })\n    })\n\n    test(\"Repeats springs as 'reverse'\", async (resolve) => {\n        const output: number[] = []\n        const expected = [\n            100,\n            371,\n            884,\n            1259,\n            1343,\n            1204,\n            1006,\n            883,\n            873,\n            937,\n            1011,\n            1050,\n            1046,\n            1018,\n            991,\n            980,\n            984,\n            996,\n            1005,\n            1008,\n            1005,\n            1001,\n            998,\n            997,\n            998,\n            1000,\n            1001,\n            1001,\n            1001,\n            1000,\n            1000,\n            1000,\n            1001,\n            1001,\n            1001,\n            1000,\n            998,\n            997,\n            998,\n            1001,\n            1005,\n            1008,\n            1005,\n            996,\n            984,\n            980,\n            991,\n            1018,\n            1046,\n            1050,\n            1011,\n            937,\n            873,\n            883,\n            1006,\n            1204,\n            1343,\n            1259,\n            884,\n            371,\n            100,\n        ]\n        animate({\n            from: 100,\n            to: 1000,\n            stiffness: 300,\n            driver: syncDriver(50),\n            repeat: 1,\n            repeatType: \"reverse\",\n            restSpeed: 10,\n            restDelta: 0.5,\n            onUpdate: (v) => output.push(Math.round(v)),\n            onComplete: () => {\n                expect(output).toEqual(expected)\n                resolve()\n            },\n        })\n    })\n\n    test(\"Repeats springs as 'reverse' with repeatDelay\", async (resolve) => {\n        const output: number[] = []\n        const expected = [\n            100,\n            884,\n            1343,\n            1006,\n            873,\n            1011,\n            1046,\n            991,\n            984,\n            1005,\n            1005,\n            998,\n            998,\n            1001,\n            1001,\n            1000,\n            1000,\n            1000,\n            1000,\n            1001,\n            1001,\n            998,\n            998,\n            1005,\n            1005,\n            984,\n            991,\n            1046,\n            1011,\n            873,\n            1006,\n            1343,\n            884,\n            100,\n            100,\n            100,\n            100,\n            884,\n            1343,\n            1006,\n            873,\n            1011,\n            1046,\n            991,\n            984,\n            1005,\n            1005,\n            998,\n            998,\n            1001,\n            1001,\n            1000,\n        ]\n        animate({\n            from: 100,\n            to: 1000,\n            stiffness: 300,\n            driver: syncDriver(100),\n            repeat: 2,\n            repeatType: \"reverse\",\n            repeatDelay: 300,\n            restSpeed: 10,\n            restDelta: 0.5,\n            onUpdate: (v) => output.push(Math.round(v)),\n            onComplete: () => {\n                expect(output).toEqual(expected)\n                resolve()\n            },\n        })\n    })\n\n    test(\"Repeats springs as 'mirror'\", async (resolve) => {\n        const output: number[] = []\n        const expected = [\n            100,\n            371,\n            884,\n            1259,\n            1343,\n            1204,\n            1006,\n            883,\n            873,\n            937,\n            1011,\n            1050,\n            1046,\n            1018,\n            991,\n            980,\n            984,\n            996,\n            1005,\n            1008,\n            1005,\n            1001,\n            998,\n            997,\n            998,\n            1000,\n            1001,\n            1001,\n            1001,\n            1000,\n            1000,\n            729,\n            216,\n            -159,\n            -243,\n            -104,\n            94,\n            217,\n            227,\n            163,\n            89,\n            50,\n            54,\n            82,\n            109,\n            120,\n            116,\n            104,\n            95,\n            92,\n            95,\n            99,\n            102,\n            103,\n            102,\n            100,\n            99,\n            99,\n            99,\n            100,\n            100,\n        ]\n        animate({\n            from: 100,\n            to: 1000,\n            stiffness: 300,\n            driver: syncDriver(50),\n            repeat: 1,\n            restSpeed: 10,\n            restDelta: 0.5,\n            repeatType: \"mirror\",\n            onUpdate: (v) => output.push(Math.round(v)),\n            onComplete: () => {\n                expect(output).toEqual(expected)\n                resolve()\n            },\n        })\n    })\n\n    test(\"Repeats springs as 'mirror' with repeatDelay\", async (resolve) => {\n        const output: number[] = []\n        const expected = [\n            100,\n            884,\n            1343,\n            1006,\n            873,\n            1011,\n            1046,\n            991,\n            984,\n            1005,\n            1005,\n            998,\n            998,\n            1001,\n            1001,\n            1000,\n            1000,\n            1000,\n            1000,\n            216,\n            -243,\n            94,\n            227,\n            89,\n            54,\n            109,\n            116,\n            95,\n            95,\n            102,\n            102,\n            99,\n            99,\n            100,\n            100,\n            100,\n            100,\n            884,\n            1343,\n            1006,\n            873,\n            1011,\n            1046,\n            991,\n            984,\n            1005,\n            1005,\n            998,\n            998,\n            1001,\n            1001,\n            1000,\n        ]\n        animate({\n            from: 100,\n            to: 1000,\n            stiffness: 300,\n            driver: syncDriver(100),\n            repeat: 2,\n            repeatType: \"mirror\",\n            repeatDelay: 300,\n            restSpeed: 10,\n            restDelta: 0.5,\n            onUpdate: (v) => output.push(Math.round(v)),\n            onComplete: () => {\n                expect(output).toEqual(expected)\n                resolve()\n            },\n        })\n    })\n\n    test(\"Finishes springs with explicit velocity\", async (resolve) => {\n        animate({\n            from: 100,\n            to: 1000,\n            stiffness: 300,\n            velocity: 200,\n            driver: syncDriver(100),\n            repeat: 2,\n            repeatType: \"mirror\",\n            repeatDelay: 300,\n            onComplete: () => {\n                expect(true).toEqual(true)\n                resolve()\n            },\n        })\n    })\n\n    test(\"Decay stays still with no velocity\", async (resolve) => {\n        const output: number[] = []\n        const expected = [100]\n        animate({\n            from: 100,\n            velocity: 0,\n            power: 0.8,\n            timeConstant: 750,\n            type: \"decay\",\n            driver: syncDriver(200),\n            onUpdate: (v) => output.push(Math.round(v)),\n            onComplete: () => {\n                expect(output).toEqual(expected)\n                resolve()\n            },\n        })\n    })\n\n    test(\"Runs animations as a decay\", async (resolve) => {\n        const output: number[] = []\n        const expected = [100, 135, 154, 166, 172, 175, 177, 179, 179, 180]\n        animate({\n            from: 100,\n            velocity: 100,\n            power: 0.8,\n            type: \"decay\",\n            driver: syncDriver(200),\n            onUpdate: (v) => output.push(Math.round(v)),\n            onComplete: () => {\n                expect(output).toEqual(expected)\n                resolve()\n            },\n        })\n    })\n\n    test(\"Runs animations as a decay with modifyTarget\", async (resolve) => {\n        const output: number[] = []\n        const expected = [\n            100,\n            213,\n            277,\n            313,\n            334,\n            345,\n            352,\n            355,\n            357,\n            358,\n            359,\n            360,\n        ]\n\n        animate({\n            from: 100,\n            velocity: 100,\n            power: 0.8,\n            modifyTarget: (v) => v * 2,\n            driver: syncDriver(200),\n            type: \"decay\",\n            onUpdate: (v) => output.push(Math.round(v)),\n            onComplete: () => {\n                expect(output).toEqual(expected)\n                resolve()\n            },\n        })\n    })\n\n    test(\"Repeats decay\", async (resolve) => {\n        const output: number[] = []\n        const expected = [135, 154, 166, 172, 175, 177, 179, 179, 180]\n        animate({\n            from: 100,\n            velocity: 100,\n            power: 0.8,\n            repeat: 1,\n            type: \"decay\",\n            driver: syncDriver(200),\n            onUpdate: (v) => output.push(Math.round(v)),\n            onComplete: () => {\n                expect(output).toEqual([100, ...expected, ...expected])\n                resolve()\n            },\n        })\n    })\n})\n"
  },
  {
    "path": "packages/popmotion/src/animations/__tests__/inertia.test.ts",
    "content": "import { syncDriver } from \"./utils\"\nimport { inertia } from \"../inertia\"\nimport { InertiaOptions } from \"../types\"\n\nasync function testInertia(\n    options: InertiaOptions,\n    expectation: number[],\n    resolve: () => void\n) {\n    const output: number[] = []\n\n    inertia({\n        driver: syncDriver(200),\n        ...options,\n        onUpdate: (v) => output.push(Math.round(v)),\n        onComplete: () => {\n            expect(output).toEqual(expectation)\n            resolve()\n        },\n    })\n}\n\ndescribe(\"inertia\", () => {\n    // test(\"Stays still without velocity\", async (resolve) => {\n    //     await testInertia({ from: 50 }, [50], resolve)\n    // })\n\n    // test(\"Decays upwards with positive velocity\", async (resolve) => {\n    //     await testInertia(\n    //         { from: 50, velocity: 100 },\n    //         [\n    //             50,\n    //             69,\n    //             83,\n    //             94,\n    //             102,\n    //             109,\n    //             114,\n    //             118,\n    //             121,\n    //             123,\n    //             124,\n    //             126,\n    //             127,\n    //             128,\n    //             128,\n    //             129,\n    //             129,\n    //             130,\n    //         ],\n    //         resolve\n    //     )\n    // })\n\n    // test(\"Decays downwards with negative velocity\", async (resolve) => {\n    //     await testInertia(\n    //         { from: 50, velocity: -100 },\n    //         [\n    //             50,\n    //             31,\n    //             17,\n    //             6,\n    //             -2,\n    //             -9,\n    //             -14,\n    //             -18,\n    //             -21,\n    //             -23,\n    //             -24,\n    //             -26,\n    //             -27,\n    //             -28,\n    //             -28,\n    //             -29,\n    //             -29,\n    //             -30,\n    //         ],\n    //         resolve\n    //     )\n    // })\n\n    // test(\"Inverse is same as absolute\", async (resolve) => {\n    //     const positive: number[] = []\n    //     const negative: number[] = []\n\n    //     inertia({\n    //         bounceDamping: 40,\n    //         bounceStiffness: 200,\n    //         max: 1221,\n    //         min: 0,\n    //         restDelta: 1,\n    //         restSpeed: 10,\n    //         timeConstant: 750,\n    //         velocity: 2970,\n    //         driver: syncDriver(20),\n    //         onUpdate: (v) => positive.push(Math.round(v)),\n    //         onComplete: () => {\n    //             inertia({\n    //                 bounceDamping: 40,\n    //                 bounceStiffness: 200,\n    //                 max: 0,\n    //                 min: -1221,\n    //                 restDelta: 1,\n    //                 restSpeed: 10,\n    //                 timeConstant: 750,\n    //                 velocity: -2970,\n    //                 driver: syncDriver(20),\n    //                 onUpdate: (v) => negative.push(Math.round(v)),\n    //                 onComplete: () => {\n    //                     expect(negative.map(Math.abs)).toEqual(positive)\n    //                     resolve()\n    //                 },\n    //             })\n    //         },\n    //     })\n    // })\n\n    test(\"Springs towards min if encountered\", async (resolve) => {\n        await testInertia(\n            { from: 50, min: 0, velocity: -100 },\n            [50, 31, 17, 6, -2, -2, 1, 0, 0],\n            resolve\n        )\n    })\n\n    test(\"Springs towards max if encountered\", async (resolve) => {\n        await testInertia(\n            { from: 50, max: 100, velocity: 100 },\n            [50, 69, 83, 94, 102, 102, 99, 100, 100],\n            resolve\n        )\n    })\n\n    // test(\"Springs towards min if starts outside of boundary\", async (resolve) => {\n    //     await testInertia(\n    //         {\n    //             from: -100,\n    //             bounceStiffness: 200,\n    //             min: 0,\n    //         },\n    //         [-100, 26, -3, -1, 1, -1, 0],\n    //         resolve\n    //     )\n    // })\n\n    // test(\"Springs towards max if starts outside of boundary\", async (resolve) => {\n    //     await testInertia(\n    //         {\n    //             from: 200,\n    //             bounceStiffness: 200,\n    //             max: 100,\n    //         },\n    //         [200, 74, 103, 101, 99, 101, 100],\n    //         resolve\n    //     )\n    // })\n\n    // test(\"Decays towards target returned from modifyTarget\", async (resolve) => {\n    //     await testInertia(\n    //         { from: 50, velocity: 100, modifyTarget: () => 100 },\n    //         [50, 62, 71, 78, 83, 87, 90, 92, 94, 95, 97, 97, 98, 98, 99, 100],\n    //         resolve\n    //     )\n    // })\n\n    // test(\"Can be stopped as spring\", async (resolve) => {\n    //     const output = []\n\n    //     const controls = inertia({\n    //         driver: syncDriver(200),\n    //         from: 200,\n    //         bounceStiffness: 200,\n    //         max: 100,\n    //         onUpdate: (v) => {\n    //             output.push(Math.round(v))\n    //             controls.stop()\n    //         },\n    //     })\n\n    //     setTimeout(() => {\n    //         expect(output.length).toEqual(1)\n    //         resolve()\n    //     }, 20)\n    // })\n\n    // test(\"Can be stopped as decay\", async (resolve) => {\n    //     const output = []\n\n    //     const controls = inertia({\n    //         driver: syncDriver(200),\n    //         from: 200,\n    //         bounceStiffness: 200,\n    //         onUpdate: (v) => {\n    //             output.push(Math.round(v))\n    //             controls.stop()\n    //         },\n    //     })\n\n    //     setTimeout(() => {\n    //         expect(output.length).toEqual(1)\n    //         resolve()\n    //     }, 20)\n    // })\n})\n"
  },
  {
    "path": "packages/popmotion/src/animations/__tests__/utils.ts",
    "content": "export const syncDriver = (interval = 10) => (update: (v: number) => void) => {\n    let isRunning = true\n    return {\n        start: () => {\n            setTimeout(() => {\n                update(0)\n                while (isRunning) update(interval)\n            }, 0)\n        },\n        stop: () => (isRunning = false),\n    }\n}\n"
  },
  {
    "path": "packages/popmotion/src/animations/generators/__tests__/decay.test.ts",
    "content": "import { decay } from \"../decay\"\nimport { animateSync } from \"./utils\"\n\ndescribe(\"decay\", () => {\n    test(\"Runs animations with default values \", () => {\n        expect(animateSync(decay({}), 200)).toEqual([0])\n    })\n\n    test(\"Runs animations as a decay\", () => {\n        expect(\n            animateSync(\n                decay({\n                    from: 100,\n                    velocity: 100,\n                    power: 0.8,\n                    timeConstant: 350,\n                    restDelta: 0.5,\n                }),\n                200\n            )\n        ).toEqual([100, 135, 154, 166, 172, 175, 177, 179, 179, 180])\n    })\n\n    test(\"Runs animations as a decay with modifyTarget\", () => {\n        expect(\n            animateSync(\n                decay({\n                    from: 100,\n                    velocity: 100,\n                    power: 0.8,\n                    modifyTarget: (v) => v * 2,\n                }),\n                200\n            )\n        ).toEqual([100, 213, 277, 313, 334, 345, 352, 355, 357, 358, 359, 360])\n    })\n\n    test(\"Output of animations with negative velocity is inverse of absolute velocity\", () => {\n        const absolute = animateSync(\n            decay({ from: 0, velocity: 100 }),\n            20,\n            false\n        )\n        const negative = animateSync(\n            decay({ from: 0, velocity: -100 }),\n            20,\n            false\n        )\n\n        expect(negative.map(Math.abs)).toEqual(absolute)\n    })\n})\n"
  },
  {
    "path": "packages/popmotion/src/animations/generators/__tests__/keyframes.test.ts",
    "content": "import {\n    keyframes,\n    defaultEasing,\n    defaultOffset,\n    convertOffsetToTimes,\n} from \"../keyframes\"\nimport { linear, easeInOut } from \"../../../easing\"\nimport { animateSync } from \"./utils\"\n\ndescribe(\"defaultEasing\", () => {\n    test(\"returns a default easing array\", () => {\n        expect(defaultEasing([0, 1], linear)).toEqual([linear])\n        expect(defaultEasing([0, 1, 2], linear)).toEqual([linear, linear])\n        expect(defaultEasing([0, 1, 2])).toEqual([easeInOut, easeInOut])\n    })\n})\n\ndescribe(\"defaultOffset\", () => {\n    test(\"returns a default times array\", () => {\n        expect(defaultOffset([0, 1])).toEqual([0, 1])\n        expect(defaultOffset([0, 1, 2])).toEqual([0, 0.5, 1])\n        expect(defaultOffset([0, 1, 2, 3])).toEqual([0, 1 / 3, (1 / 3) * 2, 1])\n    })\n})\n\ndescribe(\"convertOffsetToTimes\", () => {\n    test(\"converts offsets to times\", () => {\n        expect(convertOffsetToTimes([0, 0.5, 1], 500)).toEqual([0, 250, 500])\n    })\n})\n\ndescribe(\"keyframes\", () => {\n    test(\"runs a default animation\", () => {\n        expect(animateSync(keyframes({ to: 100 }), 20)).toEqual([\n            0,\n            1,\n            4,\n            8,\n            14,\n            22,\n            32,\n            44,\n            56,\n            68,\n            78,\n            86,\n            92,\n            96,\n            99,\n            100,\n        ])\n    })\n\n    test(\"adjusts with duration defined\", () => {\n        expect(\n            animateSync(keyframes({ to: 100, duration: 100, ease: linear }), 20)\n        ).toEqual([0, 20, 40, 60, 80, 100])\n    })\n\n    test(\"animates through keyframes\", () => {\n        expect(\n            animateSync(\n                keyframes({ to: [50, 100, -100], duration: 200, ease: linear }),\n                20\n            )\n        ).toEqual([50, 60, 70, 80, 90, 100, 60, 20, -20, -60, -100])\n    })\n\n    test(\"animates colors\", () => {\n        expect(\n            animateSync(\n                keyframes({\n                    to: [\"#fff\", \"#000\"],\n                    duration: 100,\n                    ease: linear,\n                }),\n                20,\n                false\n            )\n        ).toEqual([\n            \"rgba(255, 255, 255, 1)\",\n            \"rgba(228, 228, 228, 1)\",\n            \"rgba(198, 198, 198, 1)\",\n            \"rgba(161, 161, 161, 1)\",\n            \"rgba(114, 114, 114, 1)\",\n            \"rgba(0, 0, 0, 1)\",\n        ])\n    })\n})\n"
  },
  {
    "path": "packages/popmotion/src/animations/generators/__tests__/spring.test.ts",
    "content": "import { spring } from \"../spring\"\nimport { animateSync } from \"./utils\"\n\ndescribe(\"spring\", () => {\n    test(\"Runs animations with default values \", () => {\n        expect(animateSync(spring({}), 200)).toEqual([0, 1, 1, 1])\n    })\n    test(\"Underdamped spring\", () => {\n        expect(\n            animateSync(\n                spring({\n                    from: 100,\n                    to: 1000,\n                    stiffness: 300,\n                    restSpeed: 10,\n                    restDelta: 0.5,\n                }),\n                200\n            )\n        ).toEqual([100, 1343, 873, 1046, 984, 1005, 998, 1001, 1000])\n    })\n\n    test(\"Velocity passed to underdamped spring\", () => {\n        const settings = {\n            from: 100,\n            to: 1000,\n            stiffness: 300,\n            restSpeed: 10,\n            restDelta: 0.5,\n        }\n\n        const noVelocity = animateSync(spring(settings), 200)\n        const velocity = animateSync(\n            spring({ ...settings, velocity: 1000 }),\n            200\n        )\n\n        expect(noVelocity).not.toEqual(velocity)\n    })\n\n    test(\"Critically damped spring\", () => {\n        expect(\n            animateSync(\n                spring({\n                    from: 100,\n                    to: 1000,\n                    stiffness: 100,\n                    damping: 20,\n                    restSpeed: 10,\n                    restDelta: 0.5,\n                }),\n                200\n            )\n        ).toEqual([100, 635, 918, 984, 997, 1000])\n    })\n\n    test(\"Velocity passed to critically spring\", () => {\n        const settings = {\n            from: 100,\n            to: 1000,\n            stiffness: 100,\n            damping: 20,\n            restSpeed: 10,\n            restDelta: 0.5,\n        }\n\n        const noVelocity = animateSync(spring(settings), 200)\n        const velocity = animateSync(\n            spring({ ...settings, velocity: 1000 }),\n            200\n        )\n\n        expect(noVelocity).not.toEqual(velocity)\n    })\n\n    test(\"Overdamped spring\", () => {\n        expect(\n            animateSync(\n                spring({\n                    from: 100,\n                    to: 1000,\n                    stiffness: 300,\n                    damping: 100,\n                    restSpeed: 10,\n                    restDelta: 0.5,\n                }),\n                200\n            )\n        ).toEqual([\n            100,\n            499,\n            731,\n            855,\n            922,\n            958,\n            977,\n            988,\n            993,\n            996,\n            998,\n            999,\n            999,\n            1000,\n        ])\n    })\n    test(\"Overdamped spring with very high stiffness/damping\", () => {\n        expect(\n            animateSync(\n                spring({\n                    from: 100,\n                    to: 1000,\n                    stiffness: 1000000,\n                    damping: 10000000,\n                    restDelta: 1,\n                    restSpeed: 10,\n                }),\n                200\n            )\n        ).toEqual([100, 1000])\n    })\n\n    test(\"Velocity passed to overdamped spring\", () => {\n        const settings = {\n            from: 100,\n            to: 1000,\n            stiffness: 300,\n            damping: 100,\n            restSpeed: 10,\n            restDelta: 0.5,\n        }\n\n        const noVelocity = animateSync(spring(settings), 200)\n        const velocity = animateSync(\n            spring({ ...settings, velocity: 1000 }),\n            200\n        )\n\n        expect(noVelocity).not.toEqual(velocity)\n    })\n\n    test(\"Spring defined with bounce and duration is same as just bounce\", () => {\n        const settings = {\n            from: 100,\n            to: 1000,\n            bounce: 0.1,\n        }\n\n        const withoutDuration = animateSync(spring(settings), 200)\n        const withDuration = animateSync(\n            spring({ ...settings, duration: 800 }),\n            200\n        )\n\n        expect(withoutDuration).toEqual(withDuration)\n        // Check duration order of magnitude is correct\n        expect(withoutDuration.length).toBeGreaterThan(4)\n    })\n})\n"
  },
  {
    "path": "packages/popmotion/src/animations/generators/__tests__/utils.ts",
    "content": "import { Animation } from \"../../types\"\n\nexport function animateSync(\n    animation: Animation<number>,\n    timeStep = 200,\n    round = true\n) {\n    const output = []\n    let step = 0\n    let done = false\n\n    while (!done) {\n        const latest = animation.next(step * timeStep)\n        output.push(round ? Math.round(latest.value) : latest.value)\n        done = latest.done\n        step++\n    }\n\n    return output\n}\n"
  },
  {
    "path": "packages/popmotion/src/animations/generators/decay.ts",
    "content": "import { Animation, AnimationState, DecayOptions } from \"../types\"\n\nexport function decay({\n    velocity = 0,\n    from = 0,\n    power = 0.8,\n    timeConstant = 350,\n    restDelta = 0.5,\n    modifyTarget,\n}: DecayOptions): Animation<number> {\n    /**\n     * This is the Iterator-spec return value. We ensure it's mutable rather than using a generator\n     * to reduce GC during animation.\n     */\n    const state: AnimationState<number> = { done: false, value: from }\n\n    let amplitude = power * velocity\n    const ideal = from + amplitude\n\n    const target = modifyTarget === undefined ? ideal : modifyTarget(ideal)\n\n    /**\n     * If the target has changed we need to re-calculate the amplitude, otherwise\n     * the animation will start from the wrong position.\n     */\n    if (target !== ideal) amplitude = target - from\n\n    return {\n        next: (t: number) => {\n            const delta = -amplitude * Math.exp(-t / timeConstant)\n            state.done = !(delta > restDelta || delta < -restDelta)\n            state.value = state.done ? target : target + delta\n            return state\n        },\n        flipTarget: () => {},\n    }\n}\n"
  },
  {
    "path": "packages/popmotion/src/animations/generators/keyframes.ts",
    "content": "import { Animation, AnimationState, KeyframeOptions } from \"../types\"\nimport { interpolate } from \"../../utils/interpolate\"\nimport { Easing } from \"../../easing/types\"\nimport { easeInOut } from \"../../easing\"\n\nexport function defaultEasing(values: any[], easing?: Easing): Easing[] {\n    return values.map(() => easing || easeInOut).splice(0, values.length - 1)\n}\n\nexport function defaultOffset(values: any[]): number[] {\n    const numValues = values.length\n    return values.map((_value: number, i: number): number =>\n        i !== 0 ? i / (numValues - 1) : 0\n    )\n}\n\nexport function convertOffsetToTimes(offset: number[], duration: number) {\n    return offset.map((o) => o * duration)\n}\n\nexport function keyframes<V>({\n    from = 0,\n    to = 1,\n    ease,\n    offset,\n    duration = 300,\n}: KeyframeOptions): Animation<number | string> {\n    /**\n     * This is the Iterator-spec return value. We ensure it's mutable rather than using a generator\n     * to reduce GC during animation.\n     */\n    const state: AnimationState<typeof from> = { done: false, value: from }\n\n    /**\n     * Convert values to an array if they've been given as from/to options\n     */\n    const values = Array.isArray(to) ? to : [from, to]\n\n    /**\n     * Create a times array based on the provided 0-1 offsets\n     */\n    const times = convertOffsetToTimes(\n        // Only use the provided offsets if they're the correct length\n        // TODO Maybe we should warn here if there's a length mismatch\n        offset && offset.length === values.length\n            ? offset\n            : defaultOffset(values),\n        duration\n    )\n\n    function createInterpolator() {\n        return interpolate(times, values, {\n            ease: Array.isArray(ease) ? ease : defaultEasing(values, ease),\n        })\n    }\n\n    let interpolator = createInterpolator()\n\n    return {\n        next: (t: number) => {\n            state.value = interpolator(t)\n            state.done = t >= duration\n            return state\n        },\n        flipTarget: () => {\n            values.reverse()\n            interpolator = createInterpolator()\n        },\n    }\n}\n"
  },
  {
    "path": "packages/popmotion/src/animations/generators/spring.ts",
    "content": "import {\n    SpringOptions,\n    PhysicsSpringOptions,\n    Animation,\n    AnimationState,\n} from \"../types\"\nimport { calcAngularFreq, findSpring } from \"../utils/find-spring\"\n\nconst durationKeys = [\"duration\", \"bounce\"]\nconst physicsKeys = [\"stiffness\", \"damping\", \"mass\"]\n\nfunction isSpringType(options: SpringOptions, keys: string[]) {\n    return keys.some((key) => (options as any)[key] !== undefined)\n}\n\nfunction getSpringOptions(\n    options: SpringOptions\n): PhysicsSpringOptions & {\n    duration?: number\n    isResolvedFromDuration: boolean\n} {\n    let springOptions = {\n        velocity: 0.0,\n        stiffness: 100,\n        damping: 10,\n        mass: 1.0,\n        isResolvedFromDuration: false,\n        ...options,\n    }\n\n    // stiffness/damping/mass overrides duration/bounce\n    if (\n        !isSpringType(options, physicsKeys) &&\n        isSpringType(options, durationKeys)\n    ) {\n        const derived = findSpring(options)\n\n        springOptions = {\n            ...springOptions,\n            ...derived,\n            velocity: 0.0,\n            mass: 1.0,\n        }\n        springOptions.isResolvedFromDuration = true\n    }\n\n    return springOptions\n}\n\n/**\n * This is based on the spring implementation of Wobble https://github.com/skevy/wobble\n */\nexport function spring({\n    from = 0.0,\n    to = 1.0,\n    restSpeed = 2,\n    restDelta,\n    ...options\n}: SpringOptions): Animation<number> {\n    /**\n     * This is the Iterator-spec return value. We ensure it's mutable rather than using a generator\n     * to reduce GC during animation.\n     */\n    const state: AnimationState<number> = { done: false, value: from }\n\n    let {\n        stiffness,\n        damping,\n        mass,\n        velocity,\n        duration,\n        isResolvedFromDuration,\n    } = getSpringOptions(options)\n\n    let resolveSpring = zero\n    let resolveVelocity = zero\n\n    function createSpring() {\n        const initialVelocity = velocity ? -(velocity / 1000) : 0.0\n        const initialDelta = to - from\n        const dampingRatio = damping / (2 * Math.sqrt(stiffness * mass))\n        const undampedAngularFreq = Math.sqrt(stiffness / mass) / 1000\n\n        /**\n         * If we're working within what looks like a 0-1 range, change the default restDelta\n         * to 0.01\n         */\n        if (restDelta === undefined) {\n            restDelta = Math.min(Math.abs(to - from) / 100, 0.4)\n        }\n\n        if (dampingRatio < 1) {\n            const angularFreq = calcAngularFreq(\n                undampedAngularFreq,\n                dampingRatio\n            )\n\n            // Underdamped spring\n            resolveSpring = (t: number) => {\n                const envelope = Math.exp(\n                    -dampingRatio * undampedAngularFreq * t\n                )\n\n                return (\n                    to -\n                    envelope *\n                        (((initialVelocity +\n                            dampingRatio * undampedAngularFreq * initialDelta) /\n                            angularFreq) *\n                            Math.sin(angularFreq * t) +\n                            initialDelta * Math.cos(angularFreq * t))\n                )\n            }\n\n            resolveVelocity = (t: number) => {\n                // TODO Resolve these calculations with the above\n                const envelope = Math.exp(\n                    -dampingRatio * undampedAngularFreq * t\n                )\n\n                return (\n                    dampingRatio *\n                        undampedAngularFreq *\n                        envelope *\n                        ((Math.sin(angularFreq * t) *\n                            (initialVelocity +\n                                dampingRatio *\n                                    undampedAngularFreq *\n                                    initialDelta)) /\n                            angularFreq +\n                            initialDelta * Math.cos(angularFreq * t)) -\n                    envelope *\n                        (Math.cos(angularFreq * t) *\n                            (initialVelocity +\n                                dampingRatio *\n                                    undampedAngularFreq *\n                                    initialDelta) -\n                            angularFreq *\n                                initialDelta *\n                                Math.sin(angularFreq * t))\n                )\n            }\n        } else if (dampingRatio === 1) {\n            // Critically damped spring\n            resolveSpring = (t: number) =>\n                to -\n                Math.exp(-undampedAngularFreq * t) *\n                    (initialDelta +\n                        (initialVelocity + undampedAngularFreq * initialDelta) *\n                            t)\n        } else {\n            // Overdamped spring\n            const dampedAngularFreq =\n                undampedAngularFreq * Math.sqrt(dampingRatio * dampingRatio - 1)\n\n            resolveSpring = (t: number) => {\n                const envelope = Math.exp(\n                    -dampingRatio * undampedAngularFreq * t\n                )\n\n                // When performing sinh or cosh values can hit Infinity so we cap them here\n                const freqForT = Math.min(dampedAngularFreq * t, 300)\n\n                return (\n                    to -\n                    (envelope *\n                        ((initialVelocity +\n                            dampingRatio * undampedAngularFreq * initialDelta) *\n                            Math.sinh(freqForT) +\n                            dampedAngularFreq *\n                                initialDelta *\n                                Math.cosh(freqForT))) /\n                        dampedAngularFreq\n                )\n            }\n        }\n    }\n\n    createSpring()\n\n    return {\n        next: (t: number) => {\n            const current = resolveSpring(t)\n\n            if (!isResolvedFromDuration) {\n                const currentVelocity = resolveVelocity(t) * 1000\n                const isBelowVelocityThreshold =\n                    Math.abs(currentVelocity) <= restSpeed\n                const isBelowDisplacementThreshold =\n                    Math.abs(to - current) <= restDelta\n                state.done =\n                    isBelowVelocityThreshold && isBelowDisplacementThreshold\n            } else {\n                state.done = t >= duration\n            }\n\n            state.value = state.done ? to : current\n            return state\n        },\n        flipTarget: () => {\n            velocity = -velocity\n            ;[from, to] = [to, from]\n            createSpring()\n        },\n    }\n}\n\nspring.needsInterpolation = (a: any, b: any) =>\n    typeof a === \"string\" || typeof b === \"string\"\n\nconst zero = (_t: number) => 0\n"
  },
  {
    "path": "packages/popmotion/src/animations/index.ts",
    "content": "import {\n    AnimationOptions,\n    Driver,\n    DriverControls,\n    KeyframeOptions,\n} from \"./types\"\nimport { detectAnimationFromOptions } from \"./utils/detect-animation-from-options\"\nimport sync, { cancelSync, FrameData } from \"framesync\"\nimport { interpolate } from \"../utils/interpolate\"\nimport {\n    loopElapsed,\n    reverseElapsed,\n    hasRepeatDelayElapsed,\n} from \"./utils/elapsed\"\n\nconst framesync: Driver = (update) => {\n    const passTimestamp = ({ delta }: FrameData) => update(delta)\n\n    return {\n        start: () => sync.update(passTimestamp, true),\n        stop: () => cancelSync.update(passTimestamp),\n    }\n}\n\nexport function animate<V = number>({\n    from,\n    autoplay = true,\n    driver = framesync,\n    elapsed = 0,\n    repeat: repeatMax = 0,\n    repeatType = \"loop\",\n    repeatDelay = 0,\n    onPlay,\n    onStop,\n    onComplete,\n    onRepeat,\n    onUpdate,\n    ...options\n}: AnimationOptions<V>) {\n    let { to } = options\n    let driverControls: DriverControls\n    let repeatCount = 0\n    let computedDuration = (options as KeyframeOptions<V>).duration\n    let latest: V\n    let isComplete = false\n    let isForwardPlayback = true\n\n    let interpolateFromNumber: (t: number) => V\n\n    const animator = detectAnimationFromOptions(options)\n\n    if ((animator as any).needsInterpolation?.(from, to)) {\n        interpolateFromNumber = interpolate([0, 100], [from, to], {\n            clamp: false,\n        }) as (t: number) => V\n        from = 0 as any\n        to = 100 as any\n    }\n\n    const animation = animator({ ...options, from, to } as any)\n\n    function repeat() {\n        repeatCount++\n\n        if (repeatType === \"reverse\") {\n            isForwardPlayback = repeatCount % 2 === 0\n            elapsed = reverseElapsed(\n                elapsed,\n                computedDuration,\n                repeatDelay,\n                isForwardPlayback\n            )\n        } else {\n            elapsed = loopElapsed(elapsed, computedDuration, repeatDelay)\n            if (repeatType === \"mirror\") animation.flipTarget()\n        }\n\n        isComplete = false\n        onRepeat && onRepeat()\n    }\n\n    function complete() {\n        driverControls.stop()\n        onComplete && onComplete()\n    }\n\n    function update(delta: number) {\n        if (!isForwardPlayback) delta = -delta\n\n        elapsed += delta\n\n        if (!isComplete) {\n            const state = animation.next(Math.max(0, elapsed))\n            latest = state.value as any\n\n            if (interpolateFromNumber)\n                latest = interpolateFromNumber(latest as any)\n\n            isComplete = isForwardPlayback ? state.done : elapsed <= 0\n        }\n\n        onUpdate?.(latest)\n\n        if (isComplete) {\n            if (repeatCount === 0) computedDuration ??= elapsed\n\n            if (repeatCount < repeatMax) {\n                hasRepeatDelayElapsed(\n                    elapsed,\n                    computedDuration,\n                    repeatDelay,\n                    isForwardPlayback\n                ) && repeat()\n            } else {\n                complete()\n            }\n        }\n    }\n\n    function play() {\n        onPlay?.()\n        driverControls = driver(update)\n        driverControls.start()\n    }\n\n    autoplay && play()\n\n    return {\n        stop: () => {\n            onStop?.()\n            driverControls.stop()\n        },\n    }\n}\n"
  },
  {
    "path": "packages/popmotion/src/animations/inertia.ts",
    "content": "import {\n    InertiaOptions,\n    PlaybackControls,\n    AnimationOptions,\n    SpringOptions,\n} from \"./types\"\nimport { animate } from \".\"\nimport { velocityPerSecond } from \"../utils/velocity-per-second\"\nimport { getFrameData } from \"framesync\"\n\nexport function inertia({\n    from = 0,\n    velocity = 0,\n    min,\n    max,\n    power = 0.8,\n    timeConstant = 750,\n    bounceStiffness = 500,\n    bounceDamping = 10,\n    restDelta = 1,\n    modifyTarget,\n    driver,\n    onUpdate,\n    onComplete,\n    onStop,\n}: InertiaOptions) {\n    let currentAnimation: PlaybackControls\n\n    function isOutOfBounds(v: number) {\n        return (min !== undefined && v < min) || (max !== undefined && v > max)\n    }\n\n    function boundaryNearest(v: number) {\n        if (min === undefined) return max\n        if (max === undefined) return min\n\n        return Math.abs(min - v) < Math.abs(max - v) ? min : max\n    }\n\n    function startAnimation(options: AnimationOptions<number>) {\n        currentAnimation?.stop()\n\n        currentAnimation = animate({\n            ...options,\n            driver,\n            onUpdate: (v: number) => {\n                onUpdate?.(v)\n                options.onUpdate?.(v)\n            },\n            onComplete,\n            onStop,\n        })\n    }\n\n    function startSpring(options: SpringOptions) {\n        startAnimation({\n            type: \"spring\",\n            stiffness: bounceStiffness,\n            damping: bounceDamping,\n            restDelta,\n            ...options,\n        })\n    }\n\n    if (isOutOfBounds(from)) {\n        // Start the animation with spring if outside the defined boundaries\n        startSpring({ from, velocity, to: boundaryNearest(from) })\n    } else {\n        /**\n         * Or if the value is out of bounds, simulate the inertia movement\n         * with the decay animation.\n         *\n         * Pre-calculate the target so we can detect if it's out-of-bounds.\n         * If it is, we want to check per frame when to switch to a spring\n         * animation\n         */\n        let target = power * velocity + from\n        if (typeof modifyTarget !== \"undefined\") target = modifyTarget(target)\n        const boundary = boundaryNearest(target)\n        const heading = boundary === min ? -1 : 1\n        let prev: number\n        let current: number\n\n        const checkBoundary = (v: number) => {\n            prev = current\n            current = v\n            velocity = velocityPerSecond(v - prev, getFrameData().delta)\n\n            if (\n                (heading === 1 && v > boundary) ||\n                (heading === -1 && v < boundary)\n            ) {\n                startSpring({ from: v, to: boundary, velocity })\n            }\n        }\n\n        startAnimation({\n            type: \"decay\",\n            from,\n            velocity,\n            timeConstant,\n            power,\n            restDelta,\n            modifyTarget,\n            onUpdate: isOutOfBounds(target) ? checkBoundary : undefined,\n        })\n    }\n\n    return {\n        stop: () => currentAnimation?.stop(),\n    }\n}\n"
  },
  {
    "path": "packages/popmotion/src/animations/types.ts",
    "content": "import { Easing } from \"../easing/types\"\n\nexport interface Animation<V> {\n    next: (\n        t: number\n    ) => {\n        value: V\n        done: boolean\n    }\n    // TODO Change this mutative approach for a factory\n    flipTarget: () => void\n}\n\nexport interface AnimationState<V> {\n    value: V\n    done: boolean\n}\n\nexport interface PlaybackControls {\n    stop: () => void\n}\n\n/**\n * An update function. It accepts a timestamp used to advance the animation.\n */\ntype Update = (timestamp: number) => void\n\n/**\n * Drivers accept a update function and call it at an interval. This interval\n * could be a synchronous loop, a setInterval, or tied to the device's framerate.\n */\nexport interface DriverControls {\n    start: () => void\n    stop: () => void\n}\nexport type Driver = (update: Update) => DriverControls\n\n/**\n * Playback options common to all animations.\n */\nexport interface PlaybackOptions<V> {\n    /**\n     * Whether to autoplay the animation when animate is called. If\n     * set to false, the animation must be started manually via the returned\n     * play method.\n     */\n    autoplay?: boolean\n\n    driver?: Driver\n    elapsed?: number\n    from?: V\n    repeat?: number\n    repeatType?: \"loop\" | \"reverse\" | \"mirror\"\n    repeatDelay?: number\n    type?: \"spring\" | \"decay\" | \"keyframes\"\n    onUpdate?: (latest: V) => void\n    onPlay?: () => void\n    onComplete?: () => void\n    onRepeat?: () => void\n    onStop?: () => void\n}\n\nexport interface KeyframeOptions<V = number> {\n    to: V | V[]\n    from?: V\n    duration?: number\n    ease?: Easing | Easing[]\n    offset?: number[]\n}\n\nexport interface DecayOptions {\n    from?: number\n    to?: number\n    velocity?: number\n    power?: number\n    timeConstant?: number\n    modifyTarget?: (target: number) => number\n    restDelta?: number\n}\n\nexport interface PhysicsSpringOptions {\n    velocity?: number\n    stiffness?: number\n    damping?: number\n    mass?: number\n}\n\nexport interface SpringOptions extends PhysicsSpringOptions {\n    from?: number\n    to?: number\n    duration?: number\n    bounce?: number\n    restSpeed?: number\n    restDelta?: number\n}\n\nexport interface InertiaOptions extends DecayOptions {\n    bounceStiffness?: number\n    bounceDamping?: number\n    min?: number\n    max?: number\n    restSpeed?: number\n    restDelta?: number\n    driver?: Driver\n    onUpdate?: (v: number) => void\n    onComplete?: () => void\n    onStop?: () => void\n}\n\nexport type AnimationOptions<V> = PlaybackOptions<V> &\n    (DecayOptions | KeyframeOptions<V> | SpringOptions)\n\n// /**\n//  * TODO: Implement\n//  */\n// export interface SpringDurationOptions<V> extends PlaybackOptions<V> {\n//   ratio?: number;\n//   duration?: number;\n// }\n"
  },
  {
    "path": "packages/popmotion/src/animations/utils/__tests__/detect-animation-from-config.test.ts",
    "content": "import { detectAnimationFromOptions } from \"../detect-animation-from-options\"\nimport { decay } from \"../../generators/decay\"\nimport { spring } from \"../../generators/spring\"\nimport { keyframes } from \"../../generators/keyframes\"\n\ndescribe(\"detectAnimationFromOptions\", () => {\n    test(\"it selects the correct animation effect from any given config\", () => {\n        expect(detectAnimationFromOptions({ stiffness: 300 } as any)).toBe(\n            spring\n        )\n        expect(detectAnimationFromOptions({ duration: 2 } as any)).toBe(\n            keyframes\n        )\n        expect(\n            detectAnimationFromOptions({ duration: 2, dampingRatio: 1 } as any)\n        ).toBe(spring)\n        expect(detectAnimationFromOptions({ a: 2 } as any)).toBe(keyframes)\n        expect(detectAnimationFromOptions({ type: \"keyframes\" })).toBe(\n            keyframes\n        )\n        expect(detectAnimationFromOptions({ type: \"decay\" })).toBe(decay)\n        expect(detectAnimationFromOptions({ type: \"spring\" })).toBe(spring)\n\n        expect(detectAnimationFromOptions({ to: [0, 1] })).toBe(keyframes)\n\n        expect(detectAnimationFromOptions({ type: \"spring\", to: [0, 1] })).toBe(\n            keyframes\n        )\n    })\n})\n"
  },
  {
    "path": "packages/popmotion/src/animations/utils/__tests__/elapsed.test.ts",
    "content": "import { loopElapsed, reverseElapsed, hasRepeatDelayElapsed } from \"../elapsed\"\n\ndescribe(\"loopElapsed\", () => {\n    test(\"Correctly loops the provided elapsed\", () => {\n        expect(loopElapsed(1100, 1000)).toBe(100)\n        expect(loopElapsed(1100, 1000, 300)).toBe(-200)\n    })\n})\n\ndescribe(\"reverseElapsed\", () => {\n    test(\"Correctly reverses the provided elapsed forwards -> backwards\", () => {\n        expect(reverseElapsed(1100, 1000, 0, false)).toBe(900)\n        expect(reverseElapsed(1100, 1000, 300, false)).toBe(1200)\n    })\n    test(\"Correctly reverses the provided elapsed backwards -> forwards\", () => {\n        expect(reverseElapsed(-100, 1000, 0, true)).toBe(100)\n        expect(reverseElapsed(-100, 1000, 300, true)).toBe(-200)\n    })\n})\n\ndescribe(\"hasRepeatDelayElapsed\", () => {\n    test(\"Correctly determines if repeatDelay has elapsed during forward playback\", () => {\n        expect(hasRepeatDelayElapsed(1100, 1000, 50, true)).toBe(true)\n        expect(hasRepeatDelayElapsed(1100, 1000, 101, true)).toBe(false)\n        expect(hasRepeatDelayElapsed(1100, 1000, 100, true)).toBe(true)\n    })\n    test(\"Correctly determines if repeatDelay has elapsed during reverse playback\", () => {\n        expect(hasRepeatDelayElapsed(-100, 1000, 50, false)).toBe(true)\n        expect(hasRepeatDelayElapsed(-100, 1000, 101, false)).toBe(false)\n        expect(hasRepeatDelayElapsed(-100, 1000, 100, false)).toBe(true)\n    })\n})\n"
  },
  {
    "path": "packages/popmotion/src/animations/utils/__tests__/find-spring.test.ts",
    "content": "import { findSpring, minDamping, minDuration } from \"../find-spring\"\n\ntest(\"findSpring\", () => {\n    // let time = performance.now()\n    let searchedSprings = 0\n    const ratioResolution = 0.05\n    const ratioIterations = 49\n    const durationResolution = 50\n    const durationIterations = 199\n    const output = []\n    for (let ratioIndex = 0; ratioIndex < ratioIterations; ratioIndex++) {\n        for (\n            let durationIndex = 0;\n            durationIndex < durationIterations;\n            durationIndex++\n        ) {\n            searchedSprings += 1\n\n            const settings = findSpring({\n                duration: minDuration + durationIndex * durationResolution,\n                bounce: 1 - minDamping + ratioIndex * ratioResolution,\n            })\n            expect(settings.stiffness).not.toBe(100)\n            expect(settings.damping).not.toBe(10)\n\n            output.push(settings)\n        }\n    }\n\n    // console.log(\n    //     `Finding ${searchedSprings} springs took ${Math.round(\n    //         performance.now() - time\n    //     )}ms`\n    // )\n\n    // console.log(output[2])\n\n    // let average = (array: number[]) =>\n    //     array.reduce((a, b) => a + b) / array.length\n    // console.log(average(output.map((o) => o.stiffness)))\n})\n// 150 / 2.4\n// avg 7041\n"
  },
  {
    "path": "packages/popmotion/src/animations/utils/detect-animation-from-options.ts",
    "content": "import { spring } from \"../generators/spring\"\nimport { keyframes } from \"../generators/keyframes\"\nimport { decay } from \"../generators/decay\"\n\n/**\n * These are the default types of animation included with animate.\n * TODO: Consider removing decay\n */\nconst types = { keyframes, spring, decay }\n\ninterface Options {\n    to?: any\n    type?: \"decay\" | \"keyframes\" | \"spring\"\n}\n\nexport function detectAnimationFromOptions<T extends Options>(config: T) {\n    if (Array.isArray(config.to)) {\n        /**\n         * If to is defined as a keyframes array we want to force this to be a keyframes\n         * animation. In the future it might be possible to allow spring keyframes.\n         */\n        return keyframes\n    } else if (types[config.type]) {\n        /**\n         * Or if the user has explicity defined their own animation type, return that.\n         */\n        return types[config.type]\n    }\n\n    /**\n     * Attempt to detect which animation to use based on the options provided\n     */\n    const keys = new Set(Object.keys(config))\n    if (\n        keys.has(\"ease\") ||\n        (keys.has(\"duration\") && !keys.has(\"dampingRatio\"))\n    ) {\n        return keyframes\n    } else if (\n        keys.has(\"dampingRatio\") ||\n        keys.has(\"stiffness\") ||\n        keys.has(\"mass\") ||\n        keys.has(\"damping\") ||\n        keys.has(\"restSpeed\") ||\n        keys.has(\"restDelta\")\n    ) {\n        return spring\n    }\n\n    return keyframes\n}\n"
  },
  {
    "path": "packages/popmotion/src/animations/utils/elapsed.ts",
    "content": "export function loopElapsed(elapsed: number, duration: number, delay = 0) {\n    return elapsed - duration - delay\n}\n\nexport function reverseElapsed(\n    elapsed: number,\n    duration: number,\n    delay = 0,\n    isForwardPlayback = true\n) {\n    return isForwardPlayback\n        ? loopElapsed(duration + -elapsed, duration, delay)\n        : duration - (elapsed - duration) + delay\n}\n\nexport function hasRepeatDelayElapsed(\n    elapsed: number,\n    duration: number,\n    delay: number,\n    isForwardPlayback: boolean\n) {\n    return isForwardPlayback ? elapsed >= duration + delay : elapsed <= -delay\n}\n"
  },
  {
    "path": "packages/popmotion/src/animations/utils/find-spring.ts",
    "content": "import { warning } from \"hey-listen\"\nimport { clamp } from \"../../utils/clamp\"\nimport { SpringOptions } from \"../types\"\n\n/**\n * This is ported from the Framer implementation of duration-based spring resolution.\n */\n\ntype Resolver = (num: number) => number\n\nconst safeMin = 0.001\nexport const minDuration = 0.01\nexport const maxDuration = 10.0\nexport const minDamping = 0.05\nexport const maxDamping = 1\n\nexport function findSpring({\n    duration = 800,\n    bounce = 0.25,\n    velocity = 0,\n    mass = 1,\n}: SpringOptions) {\n    let envelope: Resolver\n    let derivative: Resolver\n\n    warning(\n        duration <= maxDuration * 1000,\n        \"Spring duration must be 10 seconds or less\"\n    )\n\n    let dampingRatio = 1 - bounce\n\n    /**\n     * Restrict dampingRatio and duration to within acceptable ranges.\n     */\n    dampingRatio = clamp(minDamping, maxDamping, dampingRatio)\n    duration = clamp(minDuration, maxDuration, duration / 1000)\n\n    if (dampingRatio < 1) {\n        /**\n         * Underdamped spring\n         */\n        envelope = (undampedFreq) => {\n            const exponentialDecay = undampedFreq * dampingRatio\n            const delta = exponentialDecay * duration\n            const a = exponentialDecay - velocity\n            const b = calcAngularFreq(undampedFreq, dampingRatio)\n            const c = Math.exp(-delta)\n            return safeMin - (a / b) * c\n        }\n\n        derivative = (undampedFreq) => {\n            const exponentialDecay = undampedFreq * dampingRatio\n            const delta = exponentialDecay * duration\n            const d = delta * velocity + velocity\n            const e =\n                Math.pow(dampingRatio, 2) * Math.pow(undampedFreq, 2) * duration\n            const f = Math.exp(-delta)\n            const g = calcAngularFreq(Math.pow(undampedFreq, 2), dampingRatio)\n            const factor = -envelope(undampedFreq) + safeMin > 0 ? -1 : 1\n            return (factor * ((d - e) * f)) / g\n        }\n    } else {\n        /**\n         * Critically-damped spring\n         */\n        envelope = (undampedFreq) => {\n            const a = Math.exp(-undampedFreq * duration)\n            const b = (undampedFreq - velocity) * duration + 1\n            return -safeMin + a * b\n        }\n\n        derivative = (undampedFreq) => {\n            const a = Math.exp(-undampedFreq * duration)\n            const b = (velocity - undampedFreq) * (duration * duration)\n            return a * b\n        }\n    }\n\n    const initialGuess = 5 / duration\n    const undampedFreq = approximateRoot(envelope, derivative, initialGuess)\n\n    duration = duration * 1000\n    if (isNaN(undampedFreq)) {\n        return {\n            stiffness: 100,\n            damping: 10,\n            duration,\n        }\n    } else {\n        const stiffness = Math.pow(undampedFreq, 2) * mass\n        return {\n            stiffness,\n            damping: dampingRatio * 2 * Math.sqrt(mass * stiffness),\n            duration,\n        }\n    }\n}\n\nconst rootIterations = 12\nfunction approximateRoot(\n    envelope: Resolver,\n    derivative: Resolver,\n    initialGuess: number\n): number {\n    let result = initialGuess\n    for (let i = 1; i < rootIterations; i++) {\n        result = result - envelope(result) / derivative(result)\n    }\n    return result\n}\n\nexport function calcAngularFreq(undampedFreq: number, dampingRatio: number) {\n    return undampedFreq * Math.sqrt(1 - dampingRatio * dampingRatio)\n}\n"
  },
  {
    "path": "packages/popmotion/src/easing/__tests__/cubic-bezier.test.ts",
    "content": "import { cubicBezier } from \"../cubic-bezier\"\n\ndescribe(\"cubicBezier\", () => {\n    test(\"correctly generates easing functions from curve definitions\", () => {\n        const linear = cubicBezier(0, 0, 1, 1)\n        expect(linear(0)).toBe(0)\n        expect(linear(1)).toBe(1)\n        expect(linear(0.5)).toBe(0.5)\n\n        const curve = cubicBezier(0.5, 0.1, 0.31, 0.96)\n        expect(curve(0)).toBe(0)\n        expect(curve(0.01)).toBeCloseTo(0.002, 2)\n        expect(curve(0.25)).toBeCloseTo(0.164, 2)\n        expect(curve(0.75)).toBeCloseTo(0.935, 2)\n        expect(curve(0.99)).toBeCloseTo(0.999, 2)\n        expect(curve(1)).toBe(1)\n    })\n})\n"
  },
  {
    "path": "packages/popmotion/src/easing/__tests__/index.test.ts",
    "content": "import { circIn, bounceOut, bounceInOut } from \"../\"\n\ndescribe(\"circIn\", () => {\n    test(\"correctly eases\", () => {\n        expect(circIn(0)).toEqual(0)\n        expect(circIn(0.25)).toBeCloseTo(0.0317)\n        expect(circIn(0.75)).toBeCloseTo(0.3385)\n        expect(circIn(1)).toEqual(1)\n    })\n})\n\ndescribe(\"bounceOut\", () => {\n    test(\"correctly eases\", () => {\n        expect(bounceOut(0)).toEqual(0)\n        expect(bounceOut(0.25)).toBeCloseTo(0.472)\n        expect(bounceOut(0.75)).toBeCloseTo(0.9588)\n        expect(bounceOut(1)).toEqual(1)\n    })\n})\n\ndescribe(\"bounceInOut\", () => {\n    test(\"correctly eases\", () => {\n        expect(bounceInOut(0)).toEqual(0)\n        expect(bounceInOut(0.25)).toBeCloseTo(0.1406)\n        expect(bounceInOut(0.75)).toBeCloseTo(0.85937)\n        expect(bounceInOut(1)).toEqual(1)\n    })\n})\n"
  },
  {
    "path": "packages/popmotion/src/easing/__tests__/steps.test.ts",
    "content": "import { steps } from \"../steps\"\n\ntest(\"steps\", () => {\n    const stepEnd = steps(4)\n\n    expect(stepEnd(0)).toBe(0)\n    expect(stepEnd(0.2)).toBe(0)\n    expect(stepEnd(0.249)).toBe(0)\n    expect(stepEnd(0.25)).toBe(0.25)\n    expect(stepEnd(0.49)).toBe(0.25)\n    expect(stepEnd(0.5)).toBe(0.5)\n    expect(stepEnd(0.99)).toBe(0.75)\n    expect(stepEnd(1)).toBe(0.75)\n\n    const stepStart = steps(4, \"start\")\n    expect(stepStart(0)).toBe(0.25)\n    expect(stepStart(0.2)).toBe(0.25)\n    expect(stepStart(0.249)).toBe(0.25)\n    expect(stepStart(0.25)).toBe(0.25)\n    expect(stepStart(0.49)).toBe(0.5)\n    expect(stepStart(0.5)).toBe(0.5)\n    expect(stepStart(0.51)).toBe(0.75)\n    expect(stepStart(0.99)).toBe(1)\n    expect(stepStart(1)).toBe(1)\n    expect(stepStart(2)).toBe(1)\n})\n"
  },
  {
    "path": "packages/popmotion/src/easing/__tests__/utils.test.ts",
    "content": "import {\n    reverseEasing,\n    mirrorEasing,\n    createExpoIn,\n    createBackIn,\n    createAnticipate,\n} from \"../utils\"\nimport { easeOut, easeIn, easeInOut } from \"../\"\n\ndescribe(\"reverseEasing\", () => {\n    test(\"correctly reverses an easing curve\", () => {\n        expect(reverseEasing(easeOut)(0.25)).toEqual(1 - easeOut(0.75))\n    })\n})\n\ndescribe(\"mirrorEasing\", () => {\n    test(\"correctly mirrors an easing curve\", () => {\n        expect(mirrorEasing(easeIn)(0.25)).toEqual(easeInOut(0.25))\n        expect(mirrorEasing(easeIn)(0.75)).toEqual(easeInOut(0.75))\n    })\n})\n\ndescribe(\"createExpoIn\", () => {\n    test(\"creates an expoIn curve according to the provided power\", () => {\n        expect(createExpoIn(2)(0.5)).toEqual(0.25)\n        expect(createExpoIn(3)(0.5)).toEqual(0.25 / 2)\n        expect(createExpoIn(4)(0.5)).toEqual(0.25 / 4)\n    })\n})\n\ndescribe(\"createBackIn\", () => {\n    test(\"creates an backIn curve according to the provided power\", () => {\n        expect(createBackIn(2)(0.5)).toEqual(-0.125)\n        expect(createBackIn(3)(0.5)).toEqual(-0.25)\n        expect(createBackIn(4)(0.5)).toEqual(-0.375)\n    })\n})\n\ndescribe(\"createAnticipate\", () => {\n    test(\"creates an createAnticipate curve according to the provided power\", () => {\n        expect(createAnticipate(2)(0.25)).toEqual(-0.0625)\n        expect(createAnticipate(3)(0.25)).toEqual(-0.125)\n        expect(createAnticipate(4)(0.25)).toEqual(-0.1875)\n    })\n})\n"
  },
  {
    "path": "packages/popmotion/src/easing/cubic-bezier.ts",
    "content": "/*\n  Bezier function generator\n\n  Gaëtan Renaudeau's BezierEasing\n  https://github.com/gre/bezier-easing/blob/master/src/index.js\n  https://github.com/gre/bezier-easing/blob/master/LICENSE\n  You're a hero\n\n  Use\n\n    const easeOut = cubicBezier(.17,.67,.83,.67);\n    const x = easeOut(0.5); // returns 0.627...\n*/\n\nimport { linear } from \".\"\n\nconst a = (a1: number, a2: number) => 1.0 - 3.0 * a2 + 3.0 * a1\nconst b = (a1: number, a2: number) => 3.0 * a2 - 6.0 * a1\nconst c = (a1: number) => 3.0 * a1\n\n// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.\nconst calcBezier = (t: number, a1: number, a2: number) =>\n    ((a(a1, a2) * t + b(a1, a2)) * t + c(a1)) * t\n\n// Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.\nconst getSlope = (t: number, a1: number, a2: number) =>\n    3.0 * a(a1, a2) * t * t + 2.0 * b(a1, a2) * t + c(a1)\n\nconst subdivisionPrecision = 0.0000001\nconst subdivisionMaxIterations = 10\n\nfunction binarySubdivide(\n    aX: number,\n    aA: number,\n    aB: number,\n    mX1: number,\n    mX2: number\n) {\n    let currentX: number\n    let currentT: number\n    let i: number = 0\n\n    do {\n        currentT = aA + (aB - aA) / 2.0\n        currentX = calcBezier(currentT, mX1, mX2) - aX\n        if (currentX > 0.0) {\n            aB = currentT\n        } else {\n            aA = currentT\n        }\n    } while (\n        Math.abs(currentX) > subdivisionPrecision &&\n        ++i < subdivisionMaxIterations\n    )\n\n    return currentT\n}\n\nconst newtonIterations = 8\nconst newtonMinSlope = 0.001\nfunction newtonRaphsonIterate(\n    aX: number,\n    aGuessT: number,\n    mX1: number,\n    mX2: number\n) {\n    for (let i = 0; i < newtonIterations; ++i) {\n        const currentSlope = getSlope(aGuessT, mX1, mX2)\n        if (currentSlope === 0.0) {\n            return aGuessT\n        }\n        const currentX = calcBezier(aGuessT, mX1, mX2) - aX\n        aGuessT -= currentX / currentSlope\n    }\n    return aGuessT\n}\n\nconst kSplineTableSize = 11\nconst kSampleStepSize = 1.0 / (kSplineTableSize - 1.0)\n\nexport function cubicBezier(\n    mX1: number,\n    mY1: number,\n    mX2: number,\n    mY2: number\n) {\n    // If this is a linear gradient, return linear easing\n    if (mX1 === mY1 && mX2 === mY2) return linear\n\n    // Precompute samples table\n    const sampleValues = new Float32Array(kSplineTableSize)\n\n    for (let i = 0; i < kSplineTableSize; ++i) {\n        sampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2)\n    }\n\n    function getTForX(aX: number) {\n        let intervalStart = 0.0\n        let currentSample = 1\n        const lastSample = kSplineTableSize - 1\n\n        for (\n            ;\n            currentSample !== lastSample && sampleValues[currentSample] <= aX;\n            ++currentSample\n        ) {\n            intervalStart += kSampleStepSize\n        }\n        --currentSample\n\n        // Interpolate to provide an initial guess for t\n        const dist =\n            (aX - sampleValues[currentSample]) /\n            (sampleValues[currentSample + 1] - sampleValues[currentSample])\n        const guessForT = intervalStart + dist * kSampleStepSize\n\n        const initialSlope = getSlope(guessForT, mX1, mX2)\n        if (initialSlope >= newtonMinSlope) {\n            return newtonRaphsonIterate(aX, guessForT, mX1, mX2)\n        } else if (initialSlope === 0.0) {\n            return guessForT\n        } else {\n            return binarySubdivide(\n                aX,\n                intervalStart,\n                intervalStart + kSampleStepSize,\n                mX1,\n                mX2\n            )\n        }\n    }\n\n    // If animation is at start/end, return t without easing\n    return (t: number) =>\n        t === 0 || t === 1 ? t : calcBezier(getTForX(t), mY1, mY2)\n}\n"
  },
  {
    "path": "packages/popmotion/src/easing/index.ts",
    "content": "import {\n    createExpoIn,\n    reverseEasing,\n    mirrorEasing,\n    createBackIn,\n    createAnticipate,\n} from \"./utils\"\nimport { Easing } from \"./types\"\n\nconst DEFAULT_OVERSHOOT_STRENGTH = 1.525\nconst BOUNCE_FIRST_THRESHOLD = 4.0 / 11.0\nconst BOUNCE_SECOND_THRESHOLD = 8.0 / 11.0\nconst BOUNCE_THIRD_THRESHOLD = 9.0 / 10.0\n\nexport const linear: Easing = p => p\n\nexport const easeIn = createExpoIn(2)\nexport const easeOut = reverseEasing(easeIn)\nexport const easeInOut = mirrorEasing(easeIn)\n\nexport const circIn: Easing = p => 1 - Math.sin(Math.acos(p))\nexport const circOut = reverseEasing(circIn)\nexport const circInOut = mirrorEasing(circOut)\n\nexport const backIn = createBackIn(DEFAULT_OVERSHOOT_STRENGTH)\nexport const backOut = reverseEasing(backIn)\nexport const backInOut = mirrorEasing(backIn)\n\nexport const anticipate = createAnticipate(DEFAULT_OVERSHOOT_STRENGTH)\n\n// helper constants\nconst ca = 4356.0 / 361.0\nconst cb = 35442.0 / 1805.0\nconst cc = 16061.0 / 1805.0\n\nexport const bounceOut = (p: number) => {\n    if (p === 1 || p === 0) return p\n    const p2 = p * p\n\n    return p < BOUNCE_FIRST_THRESHOLD\n        ? 7.5625 * p2\n        : p < BOUNCE_SECOND_THRESHOLD\n        ? 9.075 * p2 - 9.9 * p + 3.4\n        : p < BOUNCE_THIRD_THRESHOLD\n        ? ca * p2 - cb * p + cc\n        : 10.8 * p * p - 20.52 * p + 10.72\n}\n\nexport const bounceIn = reverseEasing(bounceOut)\n\nexport const bounceInOut = (p: number) =>\n    p < 0.5\n        ? 0.5 * (1.0 - bounceOut(1.0 - p * 2.0))\n        : 0.5 * bounceOut(p * 2.0 - 1.0) + 0.5\n"
  },
  {
    "path": "packages/popmotion/src/easing/steps.ts",
    "content": "import { clamp } from '../utils/clamp';\nimport { Easing } from './types';\n/*\n  Create stepped version of 0-1 progress\n\n  @param [int]: Number of steps\n  @param [number]: Current value\n  @return [number]: Stepped value\n*/\nexport type Direction = 'start' | 'end';\n\nexport const steps = (steps: number, direction: Direction = 'end'): Easing => (\n  progress: number\n) => {\n  progress =\n    direction === 'end' ? Math.min(progress, 0.999) : Math.max(progress, 0.001);\n  const expanded = progress * steps;\n  const rounded =\n    direction === 'end' ? Math.floor(expanded) : Math.ceil(expanded);\n\n  return clamp(0, 1, rounded / steps);\n};\n"
  },
  {
    "path": "packages/popmotion/src/easing/types.ts",
    "content": "export type Easing = (v: number) => number;\nexport type EasingModifier = (easing: Easing) => Easing;\n"
  },
  {
    "path": "packages/popmotion/src/easing/utils.ts",
    "content": "import { Easing, EasingModifier } from \"./types\"\n\n// Accepts an easing function and returns a new one that outputs reversed values.\n// Turns easeIn into easeOut.\nexport const reverseEasing: EasingModifier = easing => p => 1 - easing(1 - p)\n\n// Accepts an easing function and returns a new one that outputs mirrored values for\n// the second half of the animation. Turns easeIn into easeInOut.\nexport const mirrorEasing: EasingModifier = easing => p =>\n    p <= 0.5 ? easing(2 * p) / 2 : (2 - easing(2 * (1 - p))) / 2\n\n// Creates an easing function that is based on the exponent of the provided `power`.\n// The higher the `power`, the stronger the easing.\nexport const createExpoIn = (power: number): Easing => p => p ** power\n\n// Creates an easing function that has a stronger overshoot the higher the provided `power`.\nexport const createBackIn = (power: number): Easing => p =>\n    p * p * ((power + 1) * p - power)\n\n// Creates an easing function that pulls back a little before moving, and then\n// has a `createBackIn`-based overshoot\nexport const createAnticipate = (power: number): Easing => {\n    const backEasing = createBackIn(power)\n    return p =>\n        (p *= 2) < 1\n            ? 0.5 * backEasing(p)\n            : 0.5 * (2 - Math.pow(2, -10 * (p - 1)))\n}\n"
  },
  {
    "path": "packages/popmotion/src/index.ts",
    "content": "export { animate } from \"./animations\"\nexport { inertia } from \"./animations/inertia\"\n\n// Animators\nexport { decay } from \"./animations/generators/decay\"\nexport { spring } from \"./animations/generators/spring\"\nexport { keyframes } from \"./animations/generators/keyframes\"\n\n// Utilities\nexport { angle } from \"./utils/angle\"\nexport { applyOffset } from \"./utils/apply-offset\"\nexport { createAttractor, attract, attractExpo } from \"./utils/attract\"\nexport { clamp } from \"./utils/clamp\"\nexport { degreesToRadians } from \"./utils/degrees-to-radians\"\nexport { distance } from \"./utils/distance\"\nexport { interpolate } from \"./utils/interpolate\"\nexport { isPoint3D } from \"./utils/is-point-3d\"\nexport { isPoint } from \"./utils/is-point\"\nexport { mixColor } from \"./utils/mix-color\"\nexport { mixComplex } from \"./utils/mix-complex\"\nexport { mix } from \"./utils/mix\"\nexport { pipe } from \"./utils/pipe\"\nexport { pointFromVector } from \"./utils/point-from-vector\"\nexport { progress } from \"./utils/progress\"\nexport { radiansToDegrees } from \"./utils/radians-to-degrees\"\nexport { smoothFrame } from \"./utils/smooth-frame\"\nexport { smooth } from \"./utils/smooth\"\nexport { snap } from \"./utils/snap\"\nexport { toDecimal } from \"./utils/to-decimal\"\nexport { velocityPerFrame } from \"./utils/velocity-per-frame\"\nexport { velocityPerSecond } from \"./utils/velocity-per-second\"\nexport { wrap } from \"./utils/wrap\"\n\n// Easing\nexport {\n    linear,\n    easeIn,\n    easeInOut,\n    easeOut,\n    circIn,\n    circInOut,\n    circOut,\n    backIn,\n    backInOut,\n    backOut,\n    anticipate,\n    bounceIn,\n    bounceInOut,\n    bounceOut,\n} from \"./easing\"\nexport { cubicBezier } from \"./easing/cubic-bezier\"\nexport { steps } from \"./easing/steps\"\nexport {\n    mirrorEasing,\n    reverseEasing,\n    createExpoIn,\n    createBackIn,\n    createAnticipate,\n} from \"./easing/utils\"\n\n// Types\nexport * from \"./animations/types\"\nexport * from \"./easing/types\"\n\n// // Worklet\n// export { animate } from './worklet/animate';\n// export { workletReady } from './worklet/load-worklet';\n"
  },
  {
    "path": "packages/popmotion/src/types.ts",
    "content": "export type Point2D = {\n  x: number;\n  y: number;\n};\n\nexport type Point3D = Point2D & {\n  z: number;\n};\n\nexport type Point = Point2D | Point3D;\n"
  },
  {
    "path": "packages/popmotion/src/utils/__tests__/angle.test.ts",
    "content": "import { angle } from \"../angle\"\n\nconst a = { x: 0, y: 0 }\nconst b = { x: 1, y: 0 }\nconst c = { x: 1, y: 1 }\nconst d = { x: 0, y: 1 }\n\ntest(\"angle\", () => {\n    expect(angle(a, a)).toBe(0)\n    expect(angle(a, d)).toBe(90)\n    expect(angle(d, a)).toBe(-90)\n    expect(angle(d, b)).toBe(-45)\n    expect(angle(a, c)).toBe(45)\n    expect(angle(c)).toBe(-135)\n})\n"
  },
  {
    "path": "packages/popmotion/src/utils/__tests__/apply-offset.test.ts",
    "content": "import { applyOffset } from \"../apply-offset\"\n\ntest(\"applyOffset\", () => {\n    const withInitialOffset = applyOffset(10, 20)\n    expect(withInitialOffset(15)).toBe(25)\n\n    const withoutInitialOffset = applyOffset(20)\n    expect(withoutInitialOffset(10)).toBe(20)\n    expect(withoutInitialOffset(15)).toBe(25)\n})\n"
  },
  {
    "path": "packages/popmotion/src/utils/__tests__/attract.test.ts",
    "content": "import { createAttractor, attract, attractExpo } from \"../attract\"\n\ndescribe(\"createAttractor\", () => {\n    test(\"Will create an attractor\", () => {\n        const attractor = createAttractor()\n        expect(attractor(0.5, 10, 5)).toEqual(7.5)\n    })\n})\n\ndescribe(\"attract\", () => {\n    test(\"Attracts to origin with a linear curve\", () => {\n        expect(attract(0.5, 10, 5)).toEqual(7.5)\n        expect(attract(0.5, 10, 15)).toEqual(12.5)\n        expect(attract(1, 10, 5)).toEqual(10)\n        expect(attract(0, 10, 5)).toEqual(5)\n    })\n})\n\ndescribe(\"attractExpo\", () => {\n    test(\"Attracts to origin with an exponential curve\", () => {\n        expect(attractExpo(0.5, 10, 5)).toBeCloseTo(8.9, 1)\n        expect(attractExpo(0.5, 10, 15)).toBeCloseTo(11.1, 1)\n        expect(attractExpo(1, 10, 5)).toEqual(10)\n        expect(attractExpo(0, 10, 5)).toBeCloseTo(7.8, 1)\n    })\n})\n"
  },
  {
    "path": "packages/popmotion/src/utils/__tests__/clamp.test.ts",
    "content": "import { clamp } from \"../clamp\"\n\ntest(\"clamp\", () => {\n    expect(clamp(100, 200, 99)).toBe(100)\n    expect(clamp(100, 200, 201)).toBe(200)\n    expect(clamp(100, 200, 150)).toBe(150)\n})\n"
  },
  {
    "path": "packages/popmotion/src/utils/__tests__/degrees-to-radians.test.ts",
    "content": "import { degreesToRadians } from \"../degrees-to-radians\"\n\ntest(\"degreesToRadians\", () => {\n    expect(degreesToRadians(45)).toBe(0.7853981633974483)\n})\n"
  },
  {
    "path": "packages/popmotion/src/utils/__tests__/distance.test.ts",
    "content": "import { distance } from \"../distance\"\n\ntest(\"distance\", () => {\n    expect(distance(-100, 100)).toBe(200)\n    expect(distance(100, -100)).toBe(200)\n})\n\ntest(\"should return the correct distance between two 2D points\", () => {\n    expect(\n        distance(\n            {\n                x: 0,\n                y: 0,\n            },\n            {\n                x: 1,\n                y: 1,\n            }\n        )\n    ).toBe(1.4142135623730951)\n})\n\ntest(\"should return the correct distance between two 3D points\", () => {\n    expect(distance({ x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 10 })).toBe(10)\n})\n"
  },
  {
    "path": "packages/popmotion/src/utils/__tests__/hsla-to-rgba.test.ts",
    "content": "import { hslaToRgba } from \"../hsla-to-rgba\"\n\ndescribe(\"hslaToRgba\", () => {\n    test(\"Correctly converts hsla to rgba\", () => {\n        expect(\n            hslaToRgba({\n                hue: 190,\n                saturation: 100,\n                lightness: 80,\n                alpha: 1,\n            })\n        ).toEqual({ red: 153, green: 238, blue: 255, alpha: 1 })\n    })\n})\n"
  },
  {
    "path": "packages/popmotion/src/utils/__tests__/interpolate.test.ts",
    "content": "import { interpolate } from \"../interpolate\"\n\nconst invert = (v: number) => -v\n\ntest(\"interpolate numbers\", () => {\n    const f = interpolate([0, 100], [0, 1])\n    expect(f(50)).toBe(0.5)\n\n    const s = interpolate([-100, 100, 200], [0, 100, 0])\n    expect(s(-200)).toBe(0)\n    expect(s(0)).toBe(50)\n    expect(s(201)).toBe(0)\n})\n\ntest(\"interpolate - ease\", () => {\n    const f = interpolate([0, 100], [0, 100], { ease: invert })\n    expect(f(50)).toBe(-50)\n})\n\ntest(\"interpolate - negative\", () => {\n    const f = interpolate([-500, 500], [0, 1])\n    expect(f(-250)).toBe(0.25)\n    const s = interpolate([-500, 500, 600], [0, 1, 2])\n    expect(s(-250)).toBe(0.25)\n})\n\ntest(\"interpolate - out of range\", () => {\n    const f = interpolate([0, 100], [200, 100])\n    expect(f(50)).toBe(150)\n    expect(f(150)).toBe(100)\n    expect(f(0)).toBe(200)\n    expect(f(-100)).toBe(200)\n\n    const s = interpolate([0, 100, 200], [100, 200, 100])\n    expect(s(-50)).toBe(100)\n    expect(s(250)).toBe(100)\n})\n\ntest(\"interpolate - unclamped\", () => {\n    const f = interpolate([0, 100], [200, 100], { clamp: false })\n    expect(f(50)).toBe(150)\n    expect(f(150)).toBe(50)\n    expect(f(0)).toBe(200)\n    expect(f(-100)).toBe(300)\n\n    const s = interpolate([0, 100, 200], [1, 2, 3], { clamp: false })\n    expect(s(-100)).toBe(0)\n})\n\ntest(\"interpolate - complex\", () => {\n    const a = interpolate([0, 100, 200], [1000, 500, 1000])\n    expect(a(100)).toBe(500)\n})\n\ntest(\"interpolate - reverse\", () => {\n    const a = interpolate([1000, 0], [500, 600])\n    expect(a(500)).toBe(550)\n    expect(a(1000)).toBe(500)\n    expect(a(0)).toBe(600)\n})\n\ntest(\"interpolate - reverse complex\", () => {\n    const a = interpolate([0, 100, 200], [1000, 500, 1000])\n    expect(a(100)).toBe(500)\n    expect(a(0)).toBe(1000)\n    expect(a(200)).toBe(1000)\n})\n\ntest(\"interpolate complex strings\", () => {\n    const a = interpolate(\n        [0, 1, 2],\n        [\n            \"20px, rgba(0, 0, 0, 0)\",\n            \"10px, rgba(255, 255, 255, 1)\",\n            \"40px, rgba(100, 100, 100, 0.5)\",\n        ]\n    )\n\n    expect(a(0)).toBe(\"20px, rgba(0, 0, 0, 0)\")\n    expect(a(1.5)).toBe(\"25px, rgba(194, 194, 194, 0.75)\")\n\n    const b = interpolate([0, 1], [\"invert(0)\", \"invert(1)\"])\n    expect(b(0.5)).toBe(\"invert(0.5)\")\n})\n\ntest(\"interpolate colors\", () => {\n    const a = interpolate([0, 1], [\"#000\", \"#fff\"])\n    expect(a(0.5)).toBe(\"rgba(180, 180, 180, 1)\")\n})\n\ntest(\"interpolate objects\", () => {\n    const a = interpolate([0, 100], [{ opacity: 0 }, { opacity: 1 }])\n    expect(a(50)).toEqual({ opacity: 0.5 })\n})\n\ntest(\"interpolate arrays\", () => {\n    const a = interpolate(\n        [0, 100],\n        [\n            [100, 300],\n            [0, 600],\n        ]\n    )\n    expect(a(50)).toEqual([50, 450])\n})\n\ntest(\"custom mixer\", () => {\n    const a = interpolate([0, 1], [0, 1], {\n        mixer: (from: number, to: number) => (p: number) => 42,\n    })\n    expect(a(0.5)).toBe(42)\n})\n"
  },
  {
    "path": "packages/popmotion/src/utils/__tests__/is-point-3d.test.ts",
    "content": "import { isPoint3D } from \"../is-point-3d\"\n\ntest(\"isPoint3D\", () => {\n    expect(isPoint3D(9 as any)).toBe(false)\n    expect(isPoint3D({ x: 0, y: 0 })).toBe(false)\n    expect(isPoint3D({ x: 0, y: 0, z: 0 })).toBe(true)\n    expect(isPoint3D({ z: 0 } as any)).toBe(false)\n})\n"
  },
  {
    "path": "packages/popmotion/src/utils/__tests__/is-point.test.ts",
    "content": "import { isPoint } from \"../is-point\"\n\ntest(\"isPoint\", () => {\n    expect(isPoint(9)).toBe(false)\n    expect(isPoint({ x: 0, y: 0 })).toBe(true)\n    expect(isPoint({ x: 0, y: 0, z: 0 })).toBe(true)\n    expect(isPoint({ z: 0 })).toBe(false)\n})\n"
  },
  {
    "path": "packages/popmotion/src/utils/__tests__/mix-array.test.ts",
    "content": "import { mixArray } from \"../mix-complex\"\n\ntest(\"mixArray\", () => {\n    const a = [0, \"100px 0px\", \"#fff\"]\n    const b = [50, \"200px 100px\", \"#000\"]\n\n    const blender = mixArray(a, b)\n\n    expect(blender(0)).toEqual([0, \"100px 0px\", \"rgba(255, 255, 255, 1)\"])\n    expect(blender(1)).toEqual([50, \"200px 100px\", \"rgba(0, 0, 0, 1)\"])\n    expect(blender(0.5)).toEqual([25, \"150px 50px\", \"rgba(180, 180, 180, 1)\"])\n})\n"
  },
  {
    "path": "packages/popmotion/src/utils/__tests__/mix-color.test.ts",
    "content": "import { mixColor, mixLinearColor } from \"../mix-color\"\n\ntest(\"mixColor hex\", () => {\n    expect(mixColor(\"#fff\", \"#000\")(0.5)).toBe(\"rgba(180, 180, 180, 1)\")\n})\n\ntest(\"mixColor rgba\", () => {\n    expect(mixColor(\"rgba(0, 0, 0, 0)\", \"rgba(255, 255, 255, 1)\")(0.5)).toBe(\n        \"rgba(180, 180, 180, 0.5)\"\n    )\n})\n\ntest(\"mixColor rgba out of bounds\", () => {\n    expect(mixColor(\"rgba(0, 0, 0, 0)\", \"rgba(255, 255, 255, 1)\")(2)).toBe(\n        \"rgba(255, 255, 255, 1)\"\n    )\n    expect(mixColor(\"rgba(0, 0, 0, 0)\", \"rgba(255, 255, 255, 1)\")(-1)).toBe(\n        \"rgba(0, 0, 0, 0)\"\n    )\n})\n\ntest(\"mixColor rgb\", () => {\n    expect(mixColor(\"rgb(0, 0, 0)\", \"rgba(255, 255, 255)\")(0.5)).toBe(\n        \"rgba(180, 180, 180, 1)\"\n    )\n})\n\ntest(\"mixColor rgb out of bounds\", () => {\n    expect(mixColor(\"rgb(0, 0, 0)\", \"rgba(255, 255, 255)\")(2)).toBe(\n        \"rgba(255, 255, 255, 1)\"\n    )\n    expect(mixColor(\"rgb(0, 0, 0)\", \"rgba(255, 255, 255)\")(-1)).toBe(\n        \"rgba(0, 0, 0, 1)\"\n    )\n})\n\ntest(\"mixColor hsla\", () => {\n    expect(mixColor(\"hsla(0, 0%, 0%, 0)\", \"hsla(0, 0%, 100%, 1)\")(0.5)).toBe(\n        \"rgba(180, 180, 180, 0.5)\"\n    )\n\n    expect(\n        mixColor(\n            \"hsla(177, 37.4978%, 76.66804%, 1)\",\n            \"hsla(0, 0%, 100%, 1)\"\n        )(0.5)\n    ).toBe(\"rgba(218, 237, 236, 1)\")\n})\n\ntest(\"mixColor hsla out of bounds\", () => {\n    expect(mixColor(\"hsla(120, 0%, 0%, 0)\", \"hsla(360, 100%, 50%, 1)\")(2)).toBe(\n        \"rgba(255, 0, 0, 1)\"\n    )\n    expect(\n        mixColor(\"hsla(120, 0%, 0%, 0)\", \"hsla(360, 100%, 50%, 1)\")(-1)\n    ).toBe(\"rgba(0, 0, 0, 0)\")\n})\n\ntest(\"mixColor hsl\", () => {\n    expect(mixColor(\"hsl(120, 0%, 0%)\", \"hsl(360, 100%, 50%)\")(0.5)).toBe(\n        \"rgba(180, 0, 0, 1)\"\n    )\n})\n\ntest(\"mixColor hsl out of bounds\", () => {\n    expect(mixColor(\"hsl(120, 0%, 0%)\", \"hsl(360, 100%, 50%)\")(2)).toBe(\n        \"rgba(255, 0, 0, 1)\"\n    )\n    expect(mixColor(\"hsl(120, 0%, 0%)\", \"hsl(360, 100%, 50%)\")(-1)).toBe(\n        \"rgba(0, 0, 0, 1)\"\n    )\n})\n\ntest(\"mixColor rgb to hex\", () => {\n    expect(mixColor(\"rgb(255, 255, 255)\", \"#000\")(0.5)).toBe(\n        \"rgba(180, 180, 180, 1)\"\n    )\n})\n\ntest(\"mixColor hsla to rgba\", () => {\n    expect(mixColor(\"hsla(0, 0, 0, 0)\", \"rgba(255, 255, 255, 1)\")(0.5)).toBe(\n        \"rgba(180, 180, 180, 0.5)\"\n    )\n})\n\ntest(\"mixColor hsla to hex\", () => {\n    expect(mixColor(\"hsla(0, 0, 0, 0)\", \"#fff\")(0.5)).toBe(\n        \"rgba(180, 180, 180, 0.5)\"\n    )\n})\n\ntest(\"mixColor hex to hsla\", () => {\n    expect(mixColor(\"#fff\", \"hsla(0, 0, 0, 0)\")(0.5)).toBe(\n        \"rgba(180, 180, 180, 0.5)\"\n    )\n})\n\ntest(\"mixColor rgba to hsla\", () => {\n    expect(mixColor(\"rgba(255, 255, 255, 1)\", \"hsla(0, 0, 0, 0)\")(0.5)).toBe(\n        \"rgba(180, 180, 180, 0.5)\"\n    )\n})\n\ntest(\"mixColor rgba with slash to rgba without\", () => {\n    expect(mixColor(\"rgb(255, 255, 255 / 1)\", \"rgba(0, 0, 0, 0)\")(0.5)).toBe(\n        \"rgba(180, 180, 180, 0.5)\"\n    )\n})\n\ntest(\"mixColor rgba with slash (without slash spaces) to rgba without\", () => {\n    expect(mixColor(\"rgb(255 255 255/1)\", \"rgba(0, 0, 0, 0)\")(0.5)).toBe(\n        \"rgba(180, 180, 180, 0.5)\"\n    )\n})\n\ntest(\"doesn't return NaN\", () => {\n    expect(mixLinearColor(255, 0, 2)).not.toBeNaN()\n})\n"
  },
  {
    "path": "packages/popmotion/src/utils/__tests__/mix-complex.test.ts",
    "content": "import { mixComplex } from \"../mix-complex\"\n\ntest(\"mixComplex\", () => {\n    expect(mixComplex(\"20px\", \"10px\")(0.5)).toBe(\"15px\")\n    expect(\n        mixComplex(\n            \"20px, rgba(0, 0, 0, 0)\",\n            \"10px, rgba(255, 255, 255, 1)\"\n        )(0.5)\n    ).toBe(\"15px, rgba(180, 180, 180, 0.5)\")\n})\n\ntest(\"mixComplex gracefully handles numbers\", () => {\n    expect(mixComplex(20, \"10\")(0.5)).toBe(\"15\")\n})\n\ntest(\"mixComplex errors\", () => {\n    expect(mixComplex(\"hsla(100%, 100, 100, 1)\", \"#fff\")(0)).toBe(\n        \"hsla(100%, 100, 100, 1)\"\n    )\n    expect(mixComplex(\"hsla(100%, 100, 100, 1)\", \"#fff\")(0.1)).toBe(\"#fff\")\n})\n\ntest(\"mixComplex can interpolate out-of-order values\", () => {\n    expect(mixComplex(\"#fff 0px 0px\", \"20px 0px #000\")(0.5)).toBe(\n        \"10px 0px rgba(180, 180, 180, 1)\"\n    )\n})\n\ntest(\"mixComplex can animate from a value-less prop\", () => {\n    expect(mixComplex(\"#fff 0 0px\", \"20px 0px #000\")(0.5)).toBe(\n        \"10px 0px rgba(180, 180, 180, 1)\"\n    )\n})\n\ntest(\"mixComplex can animate from a value with extra zeros\", () => {\n    expect(mixComplex(\"#fff 0 0px 0px\", \"20px 0px #000\")(0.5)).toBe(\n        \"10px 0px rgba(180, 180, 180, 1)\"\n    )\n})\n"
  },
  {
    "path": "packages/popmotion/src/utils/__tests__/mix-object.test.ts",
    "content": "import { mixObject } from \"../mix-complex\"\n\ntest(\"mixObject\", () => {\n    expect(\n        mixObject(\n            {\n                x: 0,\n                y: \"0px\",\n                color: \"#fff\",\n                shadow: \"#000 0px 20px 0px\",\n            },\n            {\n                x: 100,\n                y: \"100px\",\n                color: \"#000\",\n                shadow: \"0px 10px #fff\",\n            }\n        )(0.5)\n    ).toEqual({\n        x: 50,\n        y: \"50px\",\n        color: \"rgba(180, 180, 180, 1)\",\n        shadow: \"0px 15px rgba(180, 180, 180, 1)\",\n    })\n})\n"
  },
  {
    "path": "packages/popmotion/src/utils/__tests__/mix.test.ts",
    "content": "import { mix } from \"../mix\"\n\ntest(\"mix\", () => {\n    expect(mix(0, 1, 0.5)).toBe(0.5)\n    expect(mix(-100, 100, 2)).toBe(300)\n    expect(mix(10, 20, 0.5)).toBe(15)\n    expect(mix(-10, -20, 0.5)).toBe(-15)\n    expect(mix(0, 80, 0.5)).toBe(40)\n    expect(mix(100, 200, 2)).toBe(300)\n    expect(mix(-100, 100, 2)).toBe(300)\n})\n"
  },
  {
    "path": "packages/popmotion/src/utils/__tests__/point-from-vector.test.ts",
    "content": "import { pointFromVector } from \"../point-from-vector\"\n\ntest(\"pointFromVector\", () => {\n    expect(pointFromVector({ x: 0, y: 0 }, 45, 100)).toEqual({\n        x: 70.71067811865476,\n        y: 70.71067811865474,\n    })\n})\n"
  },
  {
    "path": "packages/popmotion/src/utils/__tests__/progress.test.ts",
    "content": "import { progress } from \"../progress\"\n\ntest(\"progress\", () => {\n    expect(progress(0, 100, 50)).toBe(0.5)\n    expect(progress(100, -100, 50)).toBe(0.25)\n    expect(progress(100, -100, -300)).toBe(2)\n})\n"
  },
  {
    "path": "packages/popmotion/src/utils/__tests__/radians-to-degrees.test.ts",
    "content": "import { radiansToDegrees } from \"../radians-to-degrees\"\n\ntest(\"radiansToDegrees\", () => {\n    expect(radiansToDegrees(0.7853981633974483)).toBe(45)\n})\n"
  },
  {
    "path": "packages/popmotion/src/utils/__tests__/smooth-frame.test.ts",
    "content": "import { smoothFrame } from \"../smooth-frame\"\n\ntest(\"smoothFrame\", () => {\n    expect(smoothFrame(0, 100, 16.7, 0)).toBe(100)\n    expect(smoothFrame(0, 100, 16.7, 50)).toBe(33.4)\n})\n"
  },
  {
    "path": "packages/popmotion/src/utils/__tests__/smooth.test.ts",
    "content": "import { smooth } from \"../smooth\"\nimport sync from \"framesync\"\n\ntest(\"smooth\", () => {\n    const smoother = smooth()\n\n    return new Promise(resolve => {\n        sync.update(() => {\n            expect(smoother(100)).toBe(100)\n\n            sync.update(() => {\n                expect(smoother(200)).toBeGreaterThan(100)\n                resolve()\n            })\n        })\n    })\n})\n"
  },
  {
    "path": "packages/popmotion/src/utils/__tests__/snap.test.ts",
    "content": "import { snap } from \"../snap\"\n\nit(\"should snap a number to the nearest in the provided array\", () => {\n    const snapTo = snap([-100, -50, 100, 200])\n\n    expect(snapTo(-200)).toBe(-100)\n    expect(snapTo(-100)).toBe(-100)\n    expect(snapTo(-76)).toBe(-100)\n    expect(snapTo(-74)).toBe(-50)\n    expect(snapTo(0)).toBe(-50)\n    expect(snapTo(99)).toBe(100)\n    expect(snapTo(150)).toBe(200)\n    expect(snapTo(200)).toBe(200)\n    expect(snapTo(300)).toBe(200)\n})\n\nit(\"should snap a number to a regular interval\", () => {\n    const snapTo = snap(45)\n\n    expect(snapTo(1)).toBe(0)\n    expect(snapTo(44)).toBe(45)\n    expect(snapTo(45)).toBe(45)\n    expect(snapTo(46)).toBe(45)\n    expect(snapTo(89)).toBe(90)\n    expect(snapTo(-44)).toBe(-45)\n})\n"
  },
  {
    "path": "packages/popmotion/src/utils/__tests__/to-decimal.test.ts",
    "content": "import { toDecimal } from \"../to-decimal\"\n\ntest(\"toDecimal\", () => {\n    expect(toDecimal(3.33333)).toBe(3.33)\n    expect(toDecimal(3.3)).toBe(3.3)\n    expect(toDecimal(6.66666, 3)).toBe(6.667)\n})\n"
  },
  {
    "path": "packages/popmotion/src/utils/__tests__/velocity-per-frame.test.ts",
    "content": "import { velocityPerFrame } from \"../velocity-per-frame\"\n\ntest(\"velocityPerFrame\", () => {\n    expect(velocityPerFrame(50, 16.7)).toBe(0.835)\n})\n"
  },
  {
    "path": "packages/popmotion/src/utils/__tests__/velocity-per-second.test.ts",
    "content": "import { velocityPerSecond } from \"../velocity-per-second\"\n\ntest(\"velocityPerSecond\", () => {\n    expect(velocityPerSecond(0.835, 16.7)).toBe(50)\n    expect(velocityPerSecond(0.835, 0)).toBe(0)\n})\n"
  },
  {
    "path": "packages/popmotion/src/utils/__tests__/wrap.test.ts",
    "content": "import { wrap } from \"../wrap\"\n\ntest(\"wrap\", () => {\n    expect(wrap(-100, 100, -100)).toBe(-100)\n    expect(wrap(-100, 100, 0)).toBe(0)\n    expect(wrap(-100, 100, -200)).toBe(0)\n    expect(wrap(-100, 100, 101)).toBe(-99)\n})\n"
  },
  {
    "path": "packages/popmotion/src/utils/angle.ts",
    "content": "import { Point } from '../types';\nimport { radiansToDegrees } from './radians-to-degrees';\nimport { zeroPoint } from './inc';\n\n/*\n  Angle between points\n\n  @param [object]: X and Y coordinates of from point\n  @param [object]: X and Y coordinates of to point\n  @return [radian]: Angle between the two points in radians\n*/\nexport const angle = (a: Point, b: Point = zeroPoint) =>\n  radiansToDegrees(Math.atan2(b.y - a.y, b.x - a.x));\n"
  },
  {
    "path": "packages/popmotion/src/utils/apply-offset.ts",
    "content": "/**\n * Apply offset\n * A function that, given a value, will get the offset from `from`\n * and apply it to `to`\n * @param  {number} from\n * @param  {number} to\n * @return {function}\n */\nexport const applyOffset = (from: number, to?: number) => {\n  let hasReceivedFrom = true;\n  if (to === undefined) {\n    to = from;\n    hasReceivedFrom = false;\n  }\n\n  return (v: number) => {\n    if (hasReceivedFrom) {\n      return v - from + to;\n    } else {\n      from = v;\n      hasReceivedFrom = true;\n      return to;\n    }\n  };\n};\n"
  },
  {
    "path": "packages/popmotion/src/utils/attract.ts",
    "content": "const identity = (v: any): any => v\n\n/**\n * Creates an attractor that, given a strength constant, origin and value,\n * will calculate value as attracted to origin.\n */\nexport const createAttractor = (alterDisplacement: Function = identity) => (\n    constant: number,\n    origin: number,\n    v: number\n) => {\n    const displacement = origin - v\n    const springModifiedDisplacement =\n        -(0 - constant + 1) * (0 - alterDisplacement(Math.abs(displacement)))\n    return displacement <= 0\n        ? origin + springModifiedDisplacement\n        : origin - springModifiedDisplacement\n}\n\nexport const attract = createAttractor()\nexport const attractExpo = createAttractor(Math.sqrt)\n"
  },
  {
    "path": "packages/popmotion/src/utils/clamp.ts",
    "content": "export const clamp = (min: number, max: number, v: number) =>\n  Math.min(Math.max(v, min), max);\n"
  },
  {
    "path": "packages/popmotion/src/utils/degrees-to-radians.ts",
    "content": "/*\n  Convert degrees to radians\n\n  @param [number]: Value in degrees\n  @return [number]: Value in radians\n*/\nexport const degreesToRadians = (degrees: number) => (degrees * Math.PI) / 180;\n"
  },
  {
    "path": "packages/popmotion/src/utils/distance.ts",
    "content": "import { Point } from \"../types\"\nimport { isPoint } from \"./is-point\"\nimport { isPoint3D } from \"./is-point-3d\"\nimport { isNum } from \"./inc\"\n\nconst distance1D = (a: number, b: number) => Math.abs(a - b)\n\n/*\n  Distance\n\n  Returns the distance between two n dimensional points.\n\n  @param [object/number]: x and y or just x of point A\n  @param [object/number]: (optional): x and y or just x of point B\n  @return [number]: The distance between the two points\n*/\n\nexport function distance<P extends Point | number>(a: P, b: P): number {\n    if (isNum(a) && isNum(b)) {\n        // 1D dimensions\n        return distance1D(a, b)\n    } else if (isPoint(a) && isPoint(b)) {\n        // Multi-dimensional\n        const xDelta = distance1D(a.x, b.x)\n        const yDelta = distance1D(a.y, b.y)\n        const zDelta = isPoint3D(a) && isPoint3D(b) ? distance1D(a.z, b.z) : 0\n\n        return Math.sqrt(xDelta ** 2 + yDelta ** 2 + zDelta ** 2)\n    }\n}\n"
  },
  {
    "path": "packages/popmotion/src/utils/hsla-to-rgba.ts",
    "content": "import { HSLA, RGBA } from \"style-value-types\"\n\n// Adapted from https://gist.github.com/mjackson/5311256\nfunction hueToRgb(p: number, q: number, t: number) {\n    if (t < 0) t += 1\n    if (t > 1) t -= 1\n    if (t < 1 / 6) return p + (q - p) * 6 * t\n    if (t < 1 / 2) return q\n    if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6\n    return p\n}\n\nexport function hslaToRgba({ hue, saturation, lightness, alpha }: HSLA): RGBA {\n    hue /= 360\n    saturation /= 100\n    lightness /= 100\n\n    let red = 0\n    let green = 0\n    let blue = 0\n\n    if (!saturation) {\n        red = green = blue = lightness\n    } else {\n        const q =\n            lightness < 0.5\n                ? lightness * (1 + saturation)\n                : lightness + saturation - lightness * saturation\n        const p = 2 * lightness - q\n\n        red = hueToRgb(p, q, hue + 1 / 3)\n        green = hueToRgb(p, q, hue)\n        blue = hueToRgb(p, q, hue - 1 / 3)\n    }\n\n    return {\n        red: Math.round(red * 255),\n        green: Math.round(green * 255),\n        blue: Math.round(blue * 255),\n        alpha,\n    }\n}\n"
  },
  {
    "path": "packages/popmotion/src/utils/inc.ts",
    "content": "import { Point } from '../types';\n\nexport const zeroPoint: Point = {\n  x: 0,\n  y: 0,\n  z: 0\n};\n\nexport const isNum = (v: any): v is number => typeof v === 'number';\n"
  },
  {
    "path": "packages/popmotion/src/utils/interpolate.ts",
    "content": "import { Easing } from '../easing/types';\nimport { progress } from './progress';\nimport { mix } from './mix';\nimport { mixColor } from './mix-color';\nimport { mixComplex, mixArray, mixObject } from './mix-complex';\nimport { color } from 'style-value-types';\nimport { clamp } from './clamp';\nimport { pipe } from './pipe';\nimport { invariant } from 'hey-listen';\n\ntype MixEasing = Easing | Easing[];\n\ntype InterpolateOptions<T> = {\n  clamp?: boolean;\n  ease?: MixEasing;\n  mixer?: MixerFactory<T>;\n};\n\ntype Mix<T> = (v: number) => T;\nexport type MixerFactory<T> = (from: T, to: T) => Mix<T>;\n\nconst mixNumber = (from: number, to: number) => (p: number) => mix(from, to, p);\n\nfunction detectMixerFactory<T>(v: T): MixerFactory<any> {\n  if (typeof v === 'number') {\n    return mixNumber;\n  } else if (typeof v === 'string') {\n    if (color.test(v)) {\n      return mixColor;\n    } else {\n      return mixComplex;\n    }\n  } else if (Array.isArray(v)) {\n    return mixArray;\n  } else if (typeof v === 'object') {\n    return mixObject;\n  }\n}\n\nfunction createMixers<T>(\n  output: T[],\n  ease?: MixEasing,\n  customMixer?: MixerFactory<T>\n) {\n  const mixers: Array<Mix<T>> = [];\n  const mixerFactory: MixerFactory<T> =\n    customMixer || detectMixerFactory(output[0]);\n  const numMixers = output.length - 1;\n\n  for (let i = 0; i < numMixers; i++) {\n    let mixer = mixerFactory(output[i], output[i + 1]);\n\n    if (ease) {\n      const easingFunction = Array.isArray(ease) ? ease[i] : ease;\n      mixer = pipe(easingFunction, mixer) as Mix<T>;\n    }\n\n    mixers.push(mixer);\n  }\n\n  return mixers;\n}\n\nfunction fastInterpolate<T>([from, to]: number[], [mixer]: Array<Mix<T>>) {\n  return (v: number) => mixer(progress(from, to, v));\n}\n\nfunction slowInterpolate<T>(input: number[], mixers: Array<Mix<T>>) {\n  const inputLength = input.length;\n  const lastInputIndex = inputLength - 1;\n\n  return (v: number) => {\n    let mixerIndex = 0;\n    let foundMixerIndex = false;\n\n    if (v <= input[0]) {\n      foundMixerIndex = true;\n    } else if (v >= input[lastInputIndex]) {\n      mixerIndex = lastInputIndex - 1;\n      foundMixerIndex = true;\n    }\n\n    if (!foundMixerIndex) {\n      let i = 1;\n      for (; i < inputLength; i++) {\n        if (input[i] > v || i === lastInputIndex) {\n          break;\n        }\n      }\n      mixerIndex = i - 1;\n    }\n\n    const progressInRange = progress(\n      input[mixerIndex],\n      input[mixerIndex + 1],\n      v\n    );\n    return mixers[mixerIndex](progressInRange);\n  };\n}\n\n/**\n * Create a function that maps from a numerical input array to a generic output array.\n *\n * Accepts:\n *   - Numbers\n *   - Colors (hex, hsl, hsla, rgb, rgba)\n *   - Complex (combinations of one or more numbers or strings)\n *\n * ```jsx\n * const mixColor = interpolate([0, 1], ['#fff', '#000'])\n *\n * mixColor(0.5) // 'rgba(128, 128, 128, 1)'\n * ```\n *\n * @public\n */\nexport function interpolate<T>(\n  input: number[],\n  output: T[],\n  { clamp: isClamp = true, ease, mixer }: InterpolateOptions<T> = {}\n) {\n  const inputLength = input.length;\n\n  invariant(\n    inputLength === output.length,\n    'Both input and output ranges must be the same length'\n  );\n\n  invariant(\n    !ease || !Array.isArray(ease) || ease.length === inputLength - 1,\n    'Array of easing functions must be of length `input.length - 1`, as it applies to the transitions **between** the defined values.'\n  );\n\n  // If input runs highest -> lowest, reverse both arrays\n  if (input[0] > input[inputLength - 1]) {\n    input = [].concat(input);\n    output = [].concat(output);\n    input.reverse();\n    output.reverse();\n  }\n\n  const mixers = createMixers(output, ease, mixer);\n\n  const interpolator =\n    inputLength === 2\n      ? fastInterpolate(input, mixers)\n      : slowInterpolate(input, mixers);\n\n  return isClamp\n    ? (v: number) => interpolator(clamp(input[0], input[inputLength - 1], v))\n    : interpolator;\n}\n"
  },
  {
    "path": "packages/popmotion/src/utils/is-point-3d.ts",
    "content": "import { isPoint } from './is-point';\nimport { Point, Point3D } from '../types';\n\nexport const isPoint3D = (point: Point): point is Point3D =>\n  isPoint(point) && point.hasOwnProperty('z');\n"
  },
  {
    "path": "packages/popmotion/src/utils/is-point.ts",
    "content": "import { Point } from '../types';\n\nexport const isPoint = (point: Object): point is Point =>\n  point.hasOwnProperty('x') && point.hasOwnProperty('y');\n"
  },
  {
    "path": "packages/popmotion/src/utils/mix-color.ts",
    "content": "import { mix } from \"./mix\"\nimport { hsla, rgba, hex, Color } from \"style-value-types\"\nimport { invariant } from \"hey-listen\"\nimport { hslaToRgba } from \"./hsla-to-rgba\"\n\n// Linear color space blending\n// Explained https://www.youtube.com/watch?v=LKnqECcg6Gw\n// Demonstrated http://codepen.io/osublake/pen/xGVVaN\nexport const mixLinearColor = (from: number, to: number, v: number) => {\n    const fromExpo = from * from\n    const toExpo = to * to\n    return Math.sqrt(Math.max(0, v * (toExpo - fromExpo) + fromExpo))\n}\n\nconst colorTypes = [hex, rgba, hsla]\nconst getColorType = (v: Color | string) =>\n    colorTypes.find((type) => type.test(v))\n\nconst notAnimatable = (color: Color | string) =>\n    `'${color}' is not an animatable color. Use the equivalent color code instead.`\n\nexport const mixColor = (from: Color | string, to: Color | string) => {\n    let fromColorType = getColorType(from)\n    let toColorType = getColorType(to)\n\n    invariant(!!fromColorType, notAnimatable(from))\n    invariant(!!toColorType, notAnimatable(to))\n\n    let fromColor = fromColorType.parse(from)\n    let toColor = toColorType.parse(to)\n\n    if (fromColorType === hsla) {\n        fromColor = hslaToRgba(fromColor)\n        fromColorType = rgba\n    }\n\n    if (toColorType === hsla) {\n        toColor = hslaToRgba(toColor)\n        toColorType = rgba\n    }\n\n    const blended = { ...fromColor }\n\n    return (v: number) => {\n        for (const key in blended) {\n            if (key !== \"alpha\") {\n                blended[key] = mixLinearColor(fromColor[key], toColor[key], v)\n            }\n        }\n\n        blended.alpha = mix(fromColor.alpha, toColor.alpha, v)\n        return fromColorType.transform(blended)\n    }\n}\n"
  },
  {
    "path": "packages/popmotion/src/utils/mix-complex.ts",
    "content": "import { color, complex, RGBA, HSLA } from \"style-value-types\"\nimport { mix } from \"./mix\"\nimport { mixColor } from \"./mix-color\"\nimport { isNum } from \"./inc\"\nimport { pipe } from \"./pipe\"\nimport { warning } from \"hey-listen\"\n\ntype MixComplex = (p: number) => string\n\ntype BlendableArray = Array<number | RGBA | HSLA | string>\ntype BlendableObject = {\n    [key: string]: string | number | RGBA | HSLA\n}\n\nfunction getMixer(origin: any, target: any) {\n    if (isNum(origin)) {\n        return (v: number) => mix(origin, target as number, v)\n    } else if (color.test(origin)) {\n        return mixColor(origin, target as HSLA | RGBA | string)\n    } else {\n        return mixComplex(origin as string, target as string)\n    }\n}\n\nexport const mixArray = (from: BlendableArray, to: BlendableArray) => {\n    const output = [...from]\n    const numValues = output.length\n\n    const blendValue = from.map((fromThis, i) => getMixer(fromThis, to[i]))\n\n    return (v: number) => {\n        for (let i = 0; i < numValues; i++) {\n            output[i] = blendValue[i](v)\n        }\n        return output\n    }\n}\n\nexport const mixObject = (origin: BlendableObject, target: BlendableObject) => {\n    const output = { ...origin, ...target }\n    const blendValue: { [key: string]: (v: number) => any } = {}\n\n    for (const key in output) {\n        if (origin[key] !== undefined && target[key] !== undefined) {\n            blendValue[key] = getMixer(origin[key], target[key])\n        }\n    }\n\n    return (v: number) => {\n        for (const key in blendValue) {\n            output[key] = blendValue[key](v)\n        }\n        return output\n    }\n}\n\nfunction analyse(value: string | number) {\n    const parsed = complex.parse(value)\n    const numValues = parsed.length\n    let numNumbers = 0\n    let numRGB = 0\n    let numHSL = 0\n\n    for (let i = 0; i < numValues; i++) {\n        // Parsed complex values return with colors first, so if we've seen any number\n        // we're already past that part of the array and don't need to continue running typeof\n        if (numNumbers || typeof parsed[i] === \"number\") {\n            numNumbers++\n        } else {\n            if ((parsed[i] as HSLA).hue !== undefined) {\n                numHSL++\n            } else {\n                numRGB++\n            }\n        }\n    }\n\n    return { parsed, numNumbers, numRGB, numHSL }\n}\n\nexport const mixComplex = (\n    origin: string | number,\n    target: string | number\n): MixComplex => {\n    const template = complex.createTransformer(target)\n    const originStats = analyse(origin)\n    const targetStats = analyse(target)\n\n    const canInterpolate =\n        originStats.numHSL === targetStats.numHSL &&\n        originStats.numRGB === targetStats.numRGB &&\n        originStats.numNumbers >= targetStats.numNumbers\n\n    if (canInterpolate) {\n        return pipe(\n            mixArray(originStats.parsed, targetStats.parsed),\n            template\n        ) as MixComplex\n    } else {\n        warning(\n            true,\n            `Complex values '${origin}' and '${target}' too different to mix. Ensure all colors are of the same type, and that each contains the same quantity of number and color values. Falling back to instant transition.`\n        )\n\n        return (p: number) => `${p > 0 ? target : origin}`\n    }\n}\n"
  },
  {
    "path": "packages/popmotion/src/utils/mix.ts",
    "content": "/*\n  Value in range from progress\n\n  Given a lower limit and an upper limit, we return the value within\n  that range as expressed by progress (usually a number from 0 to 1)\n\n  So progress = 0.5 would change\n\n  from -------- to\n\n  to\n\n  from ---- to\n\n  E.g. from = 10, to = 20, progress = 0.5 => 15\n\n  @param [number]: Lower limit of range\n  @param [number]: Upper limit of range\n  @param [number]: The progress between lower and upper limits expressed 0-1\n  @return [number]: Value as calculated from progress within range (not limited within range)\n*/\nexport const mix = (from: number, to: number, progress: number) =>\n  -progress * from + progress * to + from;\n"
  },
  {
    "path": "packages/popmotion/src/utils/pipe.ts",
    "content": "/**\n * Pipe\n * Compose other transformers to run linearily\n * pipe(min(20), max(40))\n * @param  {...functions} transformers\n * @return {function}\n */\nconst combineFunctions = (a: Function, b: Function) => (v: any) => b(a(v));\nexport const pipe = (...transformers: Function[]) =>\n  transformers.reduce(combineFunctions);\n"
  },
  {
    "path": "packages/popmotion/src/utils/point-from-vector.ts",
    "content": "import { Point2D } from '../types';\nimport { degreesToRadians } from './degrees-to-radians';\n\n/*\n  Point from angle and distance\n\n  @param [object]: 2D point of origin\n  @param [number]: Angle from origin\n  @param [number]: Distance from origin\n  @return [object]: Calculated 2D point\n*/\nexport const pointFromVector = (\n  origin: Point2D,\n  angle: number,\n  distance: number\n) => {\n  angle = degreesToRadians(angle);\n\n  return {\n    x: distance * Math.cos(angle) + origin.x,\n    y: distance * Math.sin(angle) + origin.y\n  };\n};\n"
  },
  {
    "path": "packages/popmotion/src/utils/progress.ts",
    "content": "/*\n  Progress within given range\n\n  Given a lower limit and an upper limit, we return the progress\n  (expressed as a number 0-1) represented by the given value, and\n  limit that progress to within 0-1.\n\n  @param [number]: Lower limit\n  @param [number]: Upper limit\n  @param [number]: Value to find progress within given range\n  @return [number]: Progress of value within range as expressed 0-1\n*/\nexport const progress = (from: number, to: number, value: number) => {\n  const toFromDifference = to - from;\n\n  return toFromDifference === 0 ? 1 : (value - from) / toFromDifference;\n};\n"
  },
  {
    "path": "packages/popmotion/src/utils/radians-to-degrees.ts",
    "content": "/*\n  Convert radians to degrees\n\n  @param [number]: Value in radians\n  @return [number]: Value in degrees\n*/\nexport const radiansToDegrees = (radians: number) => (radians * 180) / Math.PI;\n"
  },
  {
    "path": "packages/popmotion/src/utils/smooth-frame.ts",
    "content": "import { toDecimal } from './to-decimal';\n\n/*\n  Framerate-independent smoothing\n\n  @param [number]: New value\n  @param [number]: Old value\n  @param [number]: Frame duration\n  @param [number] (optional): Smoothing (0 is none)\n*/\nexport const smoothFrame = (\n  prevValue: number,\n  nextValue: number,\n  duration: number,\n  smoothing: number = 0\n) =>\n  toDecimal(\n    prevValue +\n      (duration * (nextValue - prevValue)) / Math.max(smoothing, duration)\n  );\n"
  },
  {
    "path": "packages/popmotion/src/utils/smooth.ts",
    "content": "import { smoothFrame } from './smooth-frame';\nimport { getFrameData } from 'framesync';\n\nexport const smooth = (strength: number = 50) => {\n  let previousValue = 0;\n  let lastUpdated = 0;\n\n  return (v: number) => {\n    const currentFramestamp = getFrameData().timestamp;\n    const timeDelta =\n      currentFramestamp !== lastUpdated ? currentFramestamp - lastUpdated : 0;\n    const newValue = timeDelta\n      ? smoothFrame(previousValue, v, timeDelta, strength)\n      : previousValue;\n    lastUpdated = currentFramestamp;\n    previousValue = newValue;\n    return newValue;\n  };\n};\n"
  },
  {
    "path": "packages/popmotion/src/utils/snap.ts",
    "content": "export const snap = (points: number | number[]) => {\n  if (typeof points === 'number') {\n    return (v: number) => Math.round(v / points) * points;\n  } else {\n    let i = 0;\n    const numPoints = points.length;\n\n    return (v: number) => {\n      let lastDistance = Math.abs(points[0] - v);\n\n      for (i = 1; i < numPoints; i++) {\n        const point = points[i];\n        const distance = Math.abs(point - v);\n\n        if (distance === 0) return point;\n\n        if (distance > lastDistance) return points[i - 1];\n\n        if (i === numPoints - 1) return point;\n\n        lastDistance = distance;\n      }\n    };\n  }\n};\n"
  },
  {
    "path": "packages/popmotion/src/utils/to-decimal.ts",
    "content": "export const toDecimal = (num: number, precision: number = 2) => {\n  precision = 10 ** precision;\n  return Math.round(num * precision) / precision;\n};\n"
  },
  {
    "path": "packages/popmotion/src/utils/velocity-per-frame.ts",
    "content": "/*\n  Convert x per second to per frame velocity based on fps\n\n  @param [number]: Unit per second\n  @param [number]: Frame duration in ms\n*/\nexport function velocityPerFrame(xps: number, frameDuration: number) {\n    return xps / (1000 / frameDuration)\n}\n"
  },
  {
    "path": "packages/popmotion/src/utils/velocity-per-second.ts",
    "content": "/*\n  Convert velocity into velocity per second\n\n  @param [number]: Unit per frame\n  @param [number]: Frame duration in ms\n*/\nexport function velocityPerSecond(velocity: number, frameDuration: number) {\n    return frameDuration ? velocity * (1000 / frameDuration) : 0\n}\n"
  },
  {
    "path": "packages/popmotion/src/utils/wrap.ts",
    "content": "export const wrap = (min: number, max: number, v: number) => {\n  const rangeSize = max - min;\n  return ((((v - min) % rangeSize) + rangeSize) % rangeSize) + min;\n};\n"
  },
  {
    "path": "packages/popmotion/src/worklet/animate.ts.wip",
    "content": "import { registerCustomProperties, namespace } from './custom-properties';\nimport { whenWorkletReady } from './load-worklet';\n\ntype Target = {\n  [key: string]: string | number;\n};\n\ninterface AnimationOptions {}\n\nregisterCustomProperties();\n\nexport async function animate(\n  element: HTMLElement | SVGElement,\n  values: Target,\n  options: AnimationOptions\n) {\n  await whenWorkletReady();\n\n  // TODO: Dynamically map transforms and filters to CSS variable name and type\n  const keyframes = [\n    {\n      [namespace('translate-x')]:\n        element.style.getPropertyValue(namespace('translate-x')) || '0px' // TODO: Read from element and fallback to defailt of not set\n    },\n    {\n      [namespace('translate-x')]: `${values.x}px` // TODO dynamically convert numbers to default type\n    }\n  ];\n\n  // TODO: Dynamically generate this based on the values set on this element potentially within a weakmap\n  element.style.transform = `translateX(var(${namespace('translate-x')}))`;\n\n  const effect = new KeyframeEffect(element, keyframes, options);\n  // TODO Replace ts ignore\n  // @ts-ignore\n  const animation = new WorkletAnimation('tween', effect, document.timeline, {\n    documentTimeline: new DocumentTimeline()\n  });\n\n  return animation.play();\n}\n\nexport async function parallax(\n  element: HTMLElement | SVGElement,\n  values: Target,\n  source: HTMLElement,\n  options: AnimationOptions\n) {\n  await whenWorkletReady();\n  const keyframes: any = [];\n  const effect = new KeyframeEffect(element, keyframes, options);\n  // @ts-ignore\n  const timeline = new ScrollTimeline({\n    scrollSource: source,\n    timeRange: 1000,\n    orientation: 'vertical'\n  });\n  // @ts-ignore\n  const animation = new WorkletAnimation('parallax', effect, timeline);\n\n  return animation.play();\n}\n"
  },
  {
    "path": "packages/popmotion/src/worklet/custom-properties.ts",
    "content": "interface CustomProperty {\n  name: string;\n  syntax: string;\n  initial: string | number;\n}\n\nconst transforms: CustomProperty[] = [\n  {\n    name: 'translate',\n    syntax: 'length-percentage',\n    initial: '0px'\n  },\n  {\n    name: 'scale',\n    syntax: 'number',\n    initial: 1\n  },\n  {\n    name: 'rotate',\n    syntax: 'angle',\n    initial: '0deg'\n  }\n];\n\nconst axes = ['x', 'y', 'z'];\nconst customProperties: CustomProperty[] = [];\n\ntransforms.forEach(({ name, syntax, initial }) => {\n  customProperties.push({ name, syntax, initial });\n\n  axes.forEach(axis =>\n    customProperties.push({\n      name: `${name}-${axis}`,\n      syntax,\n      initial\n    })\n  );\n});\n\nexport function namespace(name: string) {\n  return `--pm-${name}`;\n}\n\nexport function registerCustomProperties() {\n  // TODO we need to check for registerProperty's presence\n  customProperties.forEach(({ name, syntax, initial }) => {\n    // TODO declare this with types\n    (CSS as any).registerProperty({\n      name: namespace(name),\n      syntax: `<${syntax}>`,\n      inherits: false,\n      initialValue: initial\n    });\n  });\n}\n"
  },
  {
    "path": "packages/popmotion/src/worklet/index.ts.wip",
    "content": "//import { tween } from '../animations/tween';\nimport { ForT } from '../types';\nimport { spring } from '../animations/spring';\n\ninterface WorkletAnimationEffect {\n  localTime: number;\n}\n\n// extends StatelessAnimator when browsers implement the spec\nclass StatelessPopmotionAnimator {\n  animation: ForT;\n  a: any;\n  documentTimeline: DocumentTimeline;\n\n  constructor(animation: ForT) {\n    this.animation = animation;\n    // this.state = state;\n    //console.log('constructor');\n  }\n\n  animate(currentTime: number, effect: WorkletAnimationEffect) {\n    // TODO: Why does this snap back once the duration is reached?\n    effect.localTime = this.animation(currentTime);\n    // this.a = { velocity: 'localTime ' };\n  }\n\n  // state() {\n  //   return this.a;\n  // }\n}\n\n// interface TweenOptions {\n//   documentTimeline: DocumentTimeline;\n// }\n\n// class Tween extends StatelessPopmotionAnimator {\n//   constructor(options: TweenOptions) {\n//     super(tween({ from: 0, to: 3000, duration: 3000 }));\n//   }\n// }\n\ninterface SpringOptions {}\n\nclass Spring extends StatelessPopmotionAnimator {\n  constructor(options: SpringOptions) {\n    super(spring({}));\n  }\n}\n\n// @ts-ignore\nregisterAnimator(\n  'tween',\n  class {\n    constructor() {\n      console.log('made');\n    }\n\n    animate(currentTime: number, effect: WorkletAnimationEffect) {\n      effect.localTime = currentTime;\n    }\n  }\n);\n\n// @ts-ignore\nregisterAnimator('spring', Spring);\n\ninterface ParallaxOptions {\n  factor: number;\n}\n\nclass Parallax {\n  factor = 0.5;\n\n  constructor(options: ParallaxOptions) {\n    this.factor = options.factor;\n  }\n\n  animate(currentTime: number, effect: WorkletAnimationEffect) {\n    if (isNaN(currentTime)) return;\n    effect.localTime = this.factor * currentTime;\n  }\n}\n\n// @ts-ignore\nregisterAnimator('parallax', Parallax);\n"
  },
  {
    "path": "packages/popmotion/src/worklet/load-worklet.ts",
    "content": "type Resolve = () => void\n\nlet isReady = false\n\nconst awaitingReady: Resolve[] = []\n\nexport async function whenWorkletReady() {\n    if (!isReady) {\n        return new Promise<void>((resolve) => {\n            awaitingReady.push(resolve)\n        })\n    }\n}\n\nfunction flushAwaiting() {\n    awaitingReady.forEach((resolve) => resolve())\n}\n\nexport function workletReady() {\n    isReady = true\n    flushAwaiting()\n}\n"
  },
  {
    "path": "packages/popmotion/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"rootDir\": \"src\",\n    \"outDir\": \"lib\"\n  },\n  \"include\": [\"src/**/*\"]\n}"
  },
  {
    "path": "packages/popmotion/tslint.json",
    "content": "{\n  \"extends\": [\n    \"tslint-circular-dependencies\"\n  ]\n}"
  },
  {
    "path": "packages/popmotion-pose/docs/api/dom/config.md",
    "content": "---\ntitle: Config\ndescription: Configure a poser\ncategory: vanilla\n---\n\n# Config options\n\n<TOC />\n\n### init\n\n`init?: Pose`\n\nA [pose config](#config-options-pose-config) to default to if no `initialPose` is defined.\n\n### initialPose\n\n`initialPose?: string | string[] = 'init'`\n\nThe name of the initial pose (or poses if provided as an array).\n\n### draggable\n\n`draggable?: true | 'x' | 'y'`\n\nIf `true`, will make the element draggable on both axis. Setting to either `'x'` or `'y'` will restrict movement to that axis.\n\nIf defined, allows use of the special `drag` pose for styling the element while dragging is active.\n\nA `dragEnd` pose can be **optionally** set for animating on drag end.\n\n```javascript\nconst config = {\n  draggable: 'x',\n  init: { scale: 1 },\n  drag: { scale: 1.2 }\n}\n```\n\nThe `drag` and `dragEnd` poses will travel through any posed children.\n\n### dragBounds\n\n`dragBounds?: { [key: string]: number }`\n\nAn object that defines `top`, `right`, `bottom` and/or `left` drag boundaries in pixels.\n\nCurrently, these boundaries are enforced by a hard clamp.\n\n### onDragStart/onDragEnd\n\n`onDragStart/onDragEnd: (e: MouseEvent | TouchEvent) => any`\n\nLifecycle callbacks for drag events.\n\n## hoverable\n\n`hoverable?: boolean`\n\nIf `true`, this element will receive `hover` poses when a pointer hovers over it.\n\nThere's also an **optional** `hoverEnd` pose, for providing a different pose when hovering ends.\n\n```javascript\nconst config = {\n  hoverable: true,\n  init: { scale: 1 },\n  hover: { scale: 1.2 }\n}\n```\n\nThe `hover` and `hoverEnd` poses will travel through any posed children.\n\n### focusable\n\n`focusable?: boolean`\n\nIf `true`, this element will receive `focus` poses when the element receives focus, and `blur` poses when it loses focus.\n\n```javascript\nconst config = {\n  focusable: true,\n  init: { scale: 1 },\n  focus: { scale: 1.2 },\n  blur: {\n    scale: 1,\n    transition: {\n      type: 'spring',\n      stiffness: 800\n    }\n  }\n}\n```\n\n### pressable\n\n`pressable?: boolean`\n\nIf `true`, this element will receive `press` poses when the element is pressed, and **optionally** `pressEnd` when pressing stops.\n\n```javascript\nconst config = {\n  pressable: true,\n  init: { scale: 1 },\n  press: { scale: 0.8 }\n};\n```\n\n### onPressStart/onPressEnd\n\n`onPressStart/onPressEnd: (e: MouseEvent | TouchEvent) => any`\n\nLifecycle callbacks for press events.\n\n### passive\n\n`passive: { [key: string]: PassiveValue }`\n\n```typescript\ntype PassiveValue = [\n  subscribedKey: string,\n  transform: (subscribedValue: any) => any,\n  fromParent?: true | string\n]\n```\n\nMap of values that are passively changed when other values, either on this Poser or an ancestor, change.\n\n`fromParent` can be set either as `true` or as a `string`:\n  - `true`: Link to value from immediate parent.\n  - `string`: Link to the nearest ancestor with this `label` prop.\n\n#### Example\n\nThe `transform` function here is composed with Popmotion [transformers](/api/transformers):\n\n```javascript\nconst config = {\n  draggable: 'x',\n  passive: {\n    backgroundColor: ['x', pipe(\n      clamp(0, 300),\n      interpolate([0, 300], [0, 1]),\n      blendColor('#f00', '#0f0')\n    )]\n  }\n}\n```\n\n### label\n\n`label: string`\n\nSet a label on this poser. Currently, this allows a `passive` value on a child poser to refer to this ancestor value.\n\n### props\n\n`props: { [key: string]: any }`\n\nProperties to provide to entered pose `transition` methods and dynamic pose props. These can be updated with the `setProps` method or, in React Pose, by providing props to the posed component.\n\n### onChange\n\n`onChange?: { [key: string]: (v: any) => any }`\n\nMap of callbacks, one for each animated value, that will fire whenever that value changes.\n\n**Note:** For React Pose, instead use the `onValueChange` property on the posed component.\n\n#### Example\n\n```javascript\nconst config = {\n  draggable: 'x',\n  onChange: {\n    x: (x) => // you do you \n  }\n}\n```\n\n### ...poses\n\n`...poses: { [key: string]: Pose }`\n\nAny other config props will be treated as poses (see [Pose config](#pose-config)).\n\n## Pose config\n\nYou can call a pose anything, and animate to it by calling `poser.set('poseName')` or setting `<PosedComponent pose=\"poseName\" />`.\n\nA pose is defined by style attributes like `x` or `backgroundColor`, and the following optional props:\n\n### delay\n\n`delay?: number | (props: Props) => number`\n\nA duration, in milliseconds, to delay this transition. Does **not** affect children.\n\n### delayChildren\n\n`delayChildren?: number | (props: Props) => number`\n\nA duration, in milliseconds, to delay the transition of direct children.\n\n### flip\n\n`flip?: boolean = false`\n\nIf `true`, will convert this animation to a [FLIP animation](https://aerotwist.com/blog/flip-your-animations/).\n\n### staggerChildren\n\n`staggerChildren?: number | (props: Props) => number`\n\nA duration, in milliseconds, between transitioning each children.\n\n### staggerDirection\n\n`staggerDirection?: 1 | -1 | (props: Props) => 1 | -1`\n\nIf `1`, staggers from the first child to the last. If `-1`, from last to first.\n\n### beforeChildren\n\n`beforeChildren?: boolean | (props: Props) => boolean`\n\nIf `true`, will ensure this animation completes before firing any child animations.\n\n### afterChildren\n\n`afterChildren?: boolean | (props: Props) => boolean`\n\nIf `true`, will ensure this animation only fires after all child animations have completed.\n\n### applyAtStart/applyAtEnd\n\n`applyAtStart/applyAtEnd?: { [string]: any | (props: Props) => any }`\n\n`applyAtStart` and `applyAtEnd` accept style properties to apply either at the start or end of an animation.\n\nFor instance, you might have an element that you want to flip between `display: block` before it fades in, and `display: none` after it fades out:\n\n```javascript\nconst config = {\n  visible: {\n    applyAtStart: { display: 'block' },\n    opacity: 1\n  },\n  hidden: {\n    applyAtEnd: { display: 'none' },\n    opacity: 0\n  }\n};\n```\n\n### transition\n\n`transition?`\n\nThe `transition` prop can be used to create custom transitions.\n\nIt can be set as a transition definition:\n\n```javascript\ntransition: { type: 'spring' }\n```\n\nA function that returns a transition definition **or** a Popmotion animation:\n\n```javascript\ntransition: (props) => spring({...props})\ntransition: (props) => ({ type: 'spring' })\n```\n\nOr finally, a named map where each prop is either a transition definition, or a function returning a transition definition/Popmotion animation:\n\n```javascript\nvisible: {\n  x: 0,\n  opacity: 1,\n  transition: {\n    x: { type: 'spring' },\n    default: (props) => tween(props)\n  }\n}\n```\n\n#### Transition definitions\n\nA transition definition describes the type of animation Pose should use to move to the value defined in the Pose.\n\nThere are many types, and each has its own specific configuration props available.\n\n##### Tween (default)\n\nTransitions between one value and another over a set duration of time.\n\n- `duration?: number = 300`: Total duration of animation, in milliseconds.\n- `elapsed?: number = 0`: Duration of animation already elapsed, in milliseconds.\n- `ease?: string | number[] | Function`: The name of an easing function, a cubic bezier definition, or an easing function. The following easings are included with Pose:\n  - 'linear'\n  - 'easeIn', 'easeOut', 'easeInOut'\n  - 'circIn', 'circOut', 'circInOut'\n  - 'backIn', 'backOut', 'backInOut'\n  - 'anticipate'\n- `loop?: number = 0`: Number of times to loop animation.\n- `flip?: number = 0`: Number of times to flip animation.\n- `yoyo?: number = 0`: Number of times to reverse tween.\n\n##### Spring\n\nA spring animation based on `stiffness`, `damping` and `mass`.\n\n- `type: 'spring'`: Set transition to spring.\n- `stiffness?: number = 100`: Spring stiffness.\n- `damping?: number = 10`: Strength of opposing force.\n- `mass?: number = 1.0`: Mass of the moving object.\n- `restDelta?: number = 0.01`: End animation if distance to `to` is below this value **and** `restSpeed` is `true`.\n- `restSpeed?: number = 0.01`: End animation if speed drops below this value **and** `restDelta` is `true`.\n\n##### Physics\n\nIntegrated simulation of velocity, acceleration, friction and springs.\n\n- `type: 'physics'`: Set transition to physics.\n- `acceleration?: number = 0`: Increase `velocity` by this amount every second.\n- `restSpeed?: number = 0.001`: When absolute speed drops below this value, `complete` is fired.\n- `friction?: number = 0`: Amount of friction to apply per frame, from `0` to `1`.\n- `springStrength?: number = 0`: If set with `to`, will spring towards target with this strength.\n\n##### Keyframes\n\nKeyframes accepts an array of `values` and will animate between each in sequence.\n\nTiming is defined with a combination of `duration`, `easings` and `times` properties (see [Methods](#methods))\n\n- `type: 'keyframes'`: Set transition to keyframes.\n- `values: number[]`: An array of numbers to animate between. To use the value defined in the Pose as the final destination value, set `transition` as a function: `transition: ({ to }) => { type: 'keyframes', values: [0, to] }`\n- `duration?: number = 300`: Total duration of animation, in milliseconds.\n- `easings?: Easing | Easing[]`: An array of easing functions for each generated tween, or a single easing function applied to all tweens. This array should be `values.length - 1`. Defaults to `easeOut`. (This doesn't yet support named easings)\n- `times?: number[]`: An array of numbers between `0` and `1`, representing `0` to `duration`, that represent at which point each number should be hit. Defaults to an array of evenly-spread durations will be calculated.\n- `elapsed?: number = 0`: Duration of animation already elapsed, in milliseconds.\n- `ease?: Easing = easeOut`: A function, given a progress between `0` and `1`, that returns a new progress value. Used to affect the rate of playback across the duration of the animation. (This doesn't yet support named easings)\n- `loop?: number = 0`: Number of times to loop animation.\n- `flip?: number = 0`: Number of times to flip animation.\n- `yoyo?: number = 0`: Number of times to reverse tween.\n\n##### Decay\n\n`decay` exponentially decelerates a number and velocity to an automatically generated target value. This target can be modified by the user.\n\nThis animation is particularly useful for implementing momentum scrolling.\n\n- `type: 'decay'`: Set transition to decay.\n- `power?: number = 0.8`: A constant with which to calculate a target value. Higher power = further target. `0.8` should be okay.\n- `timeConstant?: number = 350`: Adjusting the time constant will change the duration of the deceleration, thereby affecting its feel.\n- `restDelta?: number = 0.5`: Automatically completes the action when the calculated value is this far away from the target.\n- `modifyTarget?: (v: number) => number`: A function that receives the calculated target and returns a new one. Useful for snapping the target to a grid, for example.\n\n##### General transition props\n\nThe following props can be set on any transition:\n\n- `from?: number | Color`: Start value of animation (overrides Pose-generated value).\n- `to?: number | Color`: End value of animation (overrides Pose-generated value).\n- `velocity?: number`: Initial velocity of animation (overrides Pose-generated value).\n- `delay?: number`: Delay the execution of the transition by this amount of time (in milliseconds).\n- `min?: number`: Restrict output to numbers larger than this.\n- `max?: number`: Restrict output to numbers smaller than this.\n- `round?: boolean`: If `true`, output numbers will be rounded.\n\n#### Transition props\n\nIf set as a function, `transition` received the same user-defined props as other dynamic pose properties, with some generated by Pose:\n\n```typescript\ntype TransitionsProps = {\n  from: any,\n  to: any,\n  velocity: number,\n  key: string,\n  prevPoseKey: string\n}\n```\n\n- `from`: The current state of the value\n- `velocity`: The current velocity of the value, if it's a number\n- `to`: The state we're animating to, as defined in the current pose. **Note:** You're under no obligation to actually animate to this value (for instance for non-deterministic animations)\n- `key`: The name of the value\n- `prevPoseKey`: The name of the pose this value was previously in.\n\n### ...values\n\n`...values: any | (props: Props) => any`\n\nAny remaining properties are treated as stylistic values and will be animated.\n"
  },
  {
    "path": "packages/popmotion-pose/docs/api/dom/dom-pose.md",
    "content": "---\ntitle: Poser\ndescription: Animate and HTML or SVG element with a poser.\ncategory: vanilla\n---\n\n# Poser\n\nA poser is used to animate an element and its poser children.\n\n**Note:** For React, use [posed components](/pose/api/posed).\n\n<TOC />\n\n## Import\n\n```javascript\nimport pose from 'popmotion-pose'\n```\n\n## Usage\n\n### Create\n\nPosers are created with the `pose` function.\n\n`pose` accepts two arguments: A HTML or SVG element, and an object of [pose config](/pose/api/config).\n\n```javascript\nconst poser = pose(element, config)\n```\n\n### Animate\n\nAnimating to a pose defined in the [pose config](/pose/api/config) is a matter of calling the poser's `set` method:\n\n```javascript\nposer.set('nameOfPose')\n```\n\n### Sequence\n\n`set` returns a Promise, which resolves once all animations, and animations of any child posers, are complete.\n\n```javascript\n// Promise\nposer.set('nameOfPose').then(() => /* Do other thing */)\n\n// Async\nawait poser.set('nameOfPose')\n/* Do other thing */\n```\n\n### Multiple animations\n\nWhen a pose is set on a poser, it is only set on the values defined **in that pose**. Which means, if we have two poses with different sets of properties, we can animate both at the same time:\n\n```javascript\nconst poser = pose(element, {\n  flash: {\n    backgroundColor: '#f00',\n    transition: ({ from, to }) => tween({ from, to, yoyo: Infinity })\n  },\n  shake: {\n    x: true, // We're not using `to` in the transition but want to animate x\n    transition: ({ from, velocity }) => spring({\n      from, velocity,\n      stiffness: 1000,\n      damping: 100\n    })\n  }\n})\n\nposer.set('flash')\nposer.set('shake')\n```\n\n### Transitions\n\nBy default, Pose will choose a transition depending on the property being animated:\n\n- `x`, `y`, `z`: [Spring](https://popmotion.io/api/spring)\n- `scale`, `scaleX`, `scaleY`: [Spring](https://popmotion.io/api/spring) (overdamped)\n- Other props: [Tween](https://popmotion.io/api/tween)\n\n**Note:** In a future release, these default animations will be configurable via `personality` settings.\n\n#### Custom transitions\n\nEvery pose has an optional `transition` property that allows you to define a custom transition:\n\n```javascript\nconst config = {\n  attention: {\n    scale: 1.2,\n    transition: ({ from, to }) => tween({ from, to, yoyo: Infinity })\n  },\n  rest: { scale: 1 }\n}\n```\n\nThis function is run **once for each animating property** and must return a [Popmotion animation](https://popmotion.io/api) (or `false` for no animation).\n\nThe `transition` function receives a single argument, an object containing:\n\n- Information about the current transition: `from`, `to`, `velocity`, `key` and `prevPoseKey` properties.\n- Transition props. These can be set statefully as `config.props` or via the `setProps` method. Or they can be set temporarily, as the second argument provided to `set`.\n- **React Pose:** All props set on the posed component.\n\nYou can use these props to create different animations for different values.\n\n### Dynamic values\n\nValues on a pose can be set as a function that returns the `to` property for a transition.\n\nThis function is passed all the same properties as the `transition` function **except** for `to`, which this function is responsible for returning.\n\n```javascript\nconst config = {\n  open: { x: 0 },\n  closed: {\n    x: ({ i }) => Math.sin(i * 0.5) * 100\n  }\n}\n\n// Vanilla\n// --------------------\nitemPosers = items.map((item, i) => pose(item, {\n  ...config,\n  props: { i }\n}))\n\n// React\n// --------------------\nconst Item = posed.li(config)\n\n// In component render\n{items.map((item, i) => <Item pose=\"closed\" i={i} />}\n```\n\n### Draggable\n\nAny element can be made draggable by passing the `draggable` property to `config`:\n\n```javascript\nconst config = { draggable: true };\n```\n\nDragging can be locked to a single axis by passing the name of that axis instead:\n\n```javascript\nconst config = { draggable: 'x' };\n```\n\n#### dragEnd pose\n\nWhen an element is draggable and a user stops dragging, a special pose called `dragEnd` is automatically set.\n\nYou can decide what animation fires by using the `transition` property:\n\n```javascript\nconst config = {\n  draggable: 'x',\n  dragEnd: {\n    transition: ({ from }) => // return custom animation\n  }\n};\n```\n\n#### Drag lifecycle events\n\n`onDragStart` and `onDragEnd` functions can be defined to fire when a user starts and stops dragging:\n\n```javascript\nconst config {\n  draggable: true,\n  onDragStart: (e) => // not our business!\n}\n```\n\n#### Bound drag movement\n\nWe can limit pointer-driven movement with the `dragBounds` object.\n\nIt can restrict movement in both dimensions with optional `left`, `right`, `top`, and `bottom` properties:\n\n```javascript\nconst config = {\n  draggable: 'x',\n  dragBounds: { left: 0, right: 500 }\n}\n```\n\n### onChange events\n\nWe can append `onChange` callbacks to any value with the `onChange` map:\n\n```javascript\nconst config = {\n  draggable: true,\n  onChange: {\n    x: v => // Do your thing!\n  }\n}\n```\n\n### Children\n\nWith a poser's `addChild` method, we can spawn a new poser as a child.\n\nWhen we call `set` on the parent poser, the same `set` will be passed down to its children. Like this, we can orchestrate multiple animations with a single call.\n\n#### Add children\n\n`addChild` is called exactly like `pose`:\n\n```javascript\nconst childPoser = parentPoser.addChild(element, childConfig)\n```\n\nNow, all `set` calls on `parentPoser` will be passed down to all of its children. It doesn't even need a pose with that label of its own to do so.\n\n```javascript\nparentPoser.set('open')\n```\n\nWe can still call set on the child posers without affecting the parent or its siblings:\n\n```javascript\nchildPoser.set('hover')\n```\n\n#### Delay and stagger children\n\nWe can delay the propagation of a set call `delayChildren` on the parent pose:\n\n```javascript\nconst parentConfig = {\n  initialPose: 'close',\n  open: {\n    x: '0%',\n    delayChildren: 200\n  },\n  close: { x: '100%' }\n}\n```\n\nOr if we wanted to stagger over the children, we can do so with `staggerChildren`, and **optionally** `staggerDirection`:\n\n```javascript\nconst sidebarConfig = {\n  initialPose: 'close',\n  open: {\n    x: '0%',\n    delayChildren: 200,\n    staggerChildren: 50,\n    staggerDirection: -1 // stagger from the last child\n  },\n  close: { x: '100%' }\n}\n```\n\n### Passive values\n\nNot all values have to be actively animated via a pose. The `passive` property can be used to define values that simply subscribe to actively animated values and update when they do.\n\nFor instance, we could update `y` when `x` updates like so:\n\n```javascript\nconst config = {\n  draggable: 'x',\n  passive: {\n    y: ['x', x => x]\n  }\n}\n```\n\nEach passive value is defined as a tuple:\n\n```javascript\n[subscribeKey: string, transform: v => v, fromParent?: boolean]\n```\n\n- `subscribeKey`: The key of the value we'll subscribe to.\n- `transform`: Receives the latest subscribed value and returns the passive value.\n- `fromParent`: If `true`, will subscribe to this value in the direct parent instead of the current poser.\n\n### FLIP\n\nAnimating positional and dimensional properties like `width` and `top` is tasking for browsers and can cause stuttering in animations.\n\nThe [FLIP technique](https://aerotwist.com/blog/flip-your-animations/) was developed to animate these performantly by replacing them with transforms.\n\nWhen animating these properties, `flip: true` can be set to use FLIP:\n\n```javascript\n// Pose will automatically measure the difference\n// in element size and animate `scaleX` instead:\nconst config = {\n  open: { width: 200, flip: true }, // Will FLIP\n  closed: { width: 0 } // Will not FLIP\n}\n```\n\n#### Explicit FLIP methods\n\nAlternatively, we might want to transition to a new state where we don't know the new position or size.\n\nFor instance, if we change the children of the element, we might change the height. We can smoothly transition to the new height with the `measure` and `flip` methods:\n\n```javascript\nconst poser = pose(element, config)\n\n// Measure the current bounding box\nposer.measure()\n\n// Do stuff, like swap the element's children\ndoStuff()\n\n// FLIP!\nposer.flip()\n```\n\nAlternatively, we can just pass a callback to `flip`:\n\n```javascript\nposer.flip(doStuff)\n```\n\n## Methods\n\n### set\n\n`set(poseName: string, props?: Object): Promise`\n\nSets the current pose to `poseName`. If `Poser` has children, this will get set on those, too. Returns a `Promise`.\n\nIf `props` is defined, these will be passed through to the selected pose's `transition` function.\n\n### setProps\n\n`setProps(props: Object)`\n\nSets props on the poser that will be passed to any functions set on a pose.\n\n### measure\n\n`measure()`\n\nMeasures the current bounding box. Use this before making a change to the element that will affect physical dimensions (like adding new children, or moving it in the DOM), and then use `flip` to animate it to the new size.\n\n### flip\n\n`flip()`\n\nPerforms a FLIP animation between the previously `measure`d bounding box and the latest one.\n\nYou can add `flip` as a custom pose use a custom transition for this:\n\n```javascript\nconst config = {\n  flip: {\n    transition: () => // your custom transition\n  }\n};\n```\n\n### addChild\n\n`addChild(element: HTMLElement | SVGElement, config: PoseConfig): Poser`\n\nCreates and returns a new `Poser` as a child.\n\n### removeChild\n\n`removeChild(poser: Poser)`\n\nRemoves a child.\n\n### clearChildren\n\n`clearChildren()`\n\nRemoves all child posers and destroys them.\n\n### destroy\n\n`destroy()`\n\nStops all active transitions of this `Poser` and its children.\n"
  },
  {
    "path": "packages/popmotion-pose/docs/api/faqs.md",
    "content": "---\ntitle: FAQs\ndescription: Pose frequently asked questions\n---\n\n# FAQs\n\n<TOC />\n\n## Browser support?\n\nPose and React Pose support all major browsers.\n\nFor legacy IE11 support, the following polyfills are required:\n\n- [String.endsWith](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith#Polyfill)\n- [Array.from](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from#Polyfill)\n- [WeakSet](https://github.com/dy/weakset)\n\n## Filesize?\n\nAs of version 3.0:\n\n- Pose is **15.7kb**\n- React Pose is **18.8kb**, or **17kb** for pre-existing users of Styled Components or Emotion due to shared modules.\n\n## Server-side rendering?\n\nCurrently React Pose doesn't apply any styles on the server, and you may need to apply initial styles via your CSS solution.\n"
  },
  {
    "path": "packages/popmotion-pose/docs/api/react/posed.md",
    "content": "---\ntitle: Posed\ndescription: Create a posed component\ncategory: react\n---\n\n> React Pose has been **deprecated** in favour of [Framer Motion](https://framer.com/motion). [Read the upgrade guide](https://www.framer.com/api/motion/migrate-from-pose/)\n\n# posed\n\n`posed` is used to create animated and interactive components that you can reuse throughout your React site.\n\n<TOC />\n\n## Import\n\n```javascript\nimport posed from 'react-pose'\n```\n\n## Usage\n\n### Create a posed component\n\n`posed` can be used to create posed components in two ways:\n\n- **Recommended:** Create HTML & SVG elements (eg `posed.div`)\n- **Advanced:** Convert existing components (eg `posed(Component)`)\n\n#### HTML & SVG elements\n\n`pose` isn't called directly, instead we pass [a pose config object](/pose/api/react-config) to `posed.div`, `posed.button` etc. Every HTML and SVG element is supported:\n\n```javascript\nconst DraggableCircle = posed.circle({\n  draggable: 'x',\n  dragBounds: { left: 0, right: 100 }\n})\n\nexport default ({ radius }) => <DraggableCircle r={radius} />\n```\n\n#### Existing components\n\nExisting components can be converted to posed components by calling `posed` directly:\n\n```javascript\nconst PosedComponent = posed(MyComponent)(poseProps)\n```\n\nFor performance and layout calculations, React Pose requires a reference to the underlying DOM element. So, the component to be animated **must pass forward a ref using the `React.forwardRef` function**:\n\n```javascript\nconst MyComponent = forwardRef((props, ref) => (\n  <div ref={ref} {...props} />\n));\n\nconst PosedComponent = posed(MyComponent)({\n  draggable: true\n});\n\nexport default () => <PosedComponent pose={isOpen ? 'open' : 'closed'} />\n```\n\nMany CSS-in-JS libraries like Styled Components will automatically do this for you.\n\nFor FLIP support in a `PoseGroup` component, it **optionally** needs to pass on the `style` prop:\n\n```javascript\nconst MyComponent = forwardRef(({ style }, ref) => (\n  <div ref={ref} style={style} />\n));\n```\n\n### Set a pose\n\nPoses can be set via the `pose` property. This can either be a string, or an array of strings to reference multiple poses:\n\n```javascript\nconst Sidebar = posed.nav({\n  open: { x: '0%' },\n  closed: { x: '-100%' }\n})\n\nexport default ({ isOpen }) => <Sidebar pose={isOpen ? 'open' : 'closed'} />\n```\n\n### Children\n\nUsing a posed component creates a new tree of posed components. Any children that are also posed components are automatically added to this tree.\n\nThis means that orchestrating animations through React trees becomes trivial, as a pose only has to be set on a parent. Any children with that pose defined will also animate:\n\n```javascript\nconst Sidebar = posed.nav({\n  open: { x: '0%', staggerChildren: 100 },\n  closed: { x: '-100%' }\n})\n\nconst NavItem = posed.li({\n  open: { opacity: 1 },\n  closed: { opacity: 0 }\n})\n\nexport default ({ isOpen, navItems }) => (\n  <Sidebar pose={isOpen ? 'open' : 'closed'}>\n    <ul>\n      {navItems.map(({ url, name }) => (\n        <NavItem>\n          <a href={url}>{name}</a>\n        </NavItem>\n      ))}\n    </ul>\n  </Sidebar>\n)\n```\n\n<CodePen id=\"MVQepE\" />\n\nIn tandem with the [`PoseGroup`](/pose/api/posegroup) component, this capability can be used to orchestrate sophisticated `enter` and `exit` animations.\n\nThis behaviour can be overridden by passing `newTree` to a posed component, which will ignore any parent posed components and create a new tree.\n\n### Styling\n\nPosed components are normal components, so they can be used with any CSS styling solution. For instance:\n\n#### Styled Components\n\n```javascript\nconst sidebarProps = {\n  open: { x: '0%' },\n  closed: { x: '-100%' }\n}\n\nconst Sidebar = styled(posed.nav(sidebarProps))`\n```\n\n#### className\n\n```javascript\n() => <Sidebar pose=\"closed\" className=\"my-class\" />\n```\n\n## Props\n\n### pose\n\n`pose?: string | string[]`\n\nThe name or names of the current pose.\n\n### initialPose\n\n`initialPose?: string | string[]`\n\nThe name of one or more poses to set to before the component mounts. Once the component mounts, it will transition from this pose into `pose`.\n\n### poseKey\n\n`poseKey?: string | number`\n\nIf `poseKey` changes, it'll force the posed component to transition to the current `pose`, even if it hasn't changed.\n\nThis won't be required for the majority of use-cases. But we might have something like a paginated where we pass the x offset to the component but the pose itself doesn't change:\n\n```javascript\nconst Slider = posed.div({\n  nextItem: {\n    x: ({ target }) => target\n  }\n})\n\n({ target }) => <Slider pose=\"nextItem\" poseKey={target} target={target} />\n```\n\n### withParent\n\n`withParent?: boolean = true`\n\nIf set to `false`, this component won't subscribe to its parent posed component and create root for any further child components.\n\n### onPoseComplete\n\n`onPoseComplete?: Function`\n\nA callback that fires whenever a pose has finished transitioning.\n\n### onValueChange\n\n`onValueChange?: { [key: string]: any }`\n\n`onValueChange` is a map of functions, each corresponding to a value being animated by the posed component and will fire when that value changes.\n\n### onDragStart/onDragEnd\n\n`onDragStart/onDragEnd: (e: Event) => void`\n\nCallbacks that fire when dragging starts or ends. **Note:** These props are immutable and can't be changed after mounting.\n\n### onPressStart/onPressEnd\n\n`onPressStart/onPressEnd: (e: Event) => void`\n\nCallbacks that fire when pressing starts or ends. **Note:** These props are immutable and can't be changed after mounting.\n\n### ref\n\n`ref?: RefObject | (ref: Element) => void`\n\nAn optional ref property. If a function, will call with the posed DOM element when it mounts, and `null` when it unmounts.\n\nAlternatively, it can be passed a ref object (created from `React.createRef`).\n\n### values/parentValues\n\n`values?: { [key: string]: Value }`\n\nNormally, Pose generates [Popmotion `value`](/api/value) for each animating property. It then passes these down to any posed children so `passive` values can link to them.\n\nNovel hierarchies, where the posed tree and the React component tree diverge, can be achieved by creating your own values map, and passing that to a single posed component.\n\nThis same map can then be passed to multiple other posed component's `parentValues` property in order to establish a parent-children relationship even between sibling components.\n\n<CodePen id=\"xWrbNm\" />\n\n### ...props\n\n`...props: { [key: string]: any }`\n\nWhen a new pose is entered, any remaining props set on a component will be used to resolve that pose's dynamic props:\n\n```javascript\nconst Component = posed.div({\n  visible: { opacity: 1, y: 0 },\n  hidden: {\n    opacity: 0,\n    y: ({ i }) => i * 50\n  }\n})\n\n// Later\n({ isVisibile, i }) => (\n  <Component pose={isVisible ? 'visible' : 'hidden'} i={i} />\n)\n```\n"
  },
  {
    "path": "packages/popmotion-pose/docs/api/react/posegroup.md",
    "content": "---\ntitle: PoseGroup\ndescription: Animate a group of posed components as they're added and removed.\ncategory: react\n---\n\n> React Pose has been **deprecated** in favour of [Framer Motion](https://framer.com/motion). [Read the upgrade guide](https://www.framer.com/api/motion/migrate-from-pose/)\n\n# PoseGroup\n\nThe `PoseGroup` component manages `enter` and `exit` animations on its direct children as they enter and exit the component tree.\n\n<TOC />\n\n## Import\n\n```javascript\nimport posed, { PoseGroup } from 'react-pose'\n```\n\n## Usage\n\nBy adding a [posed component](/pose/api/posed) as a direct child of `PoseGroup`, it will gain two new poses: `enter` and `exit`.\n\n```javascript\nconst Item = posed.div({\n  enter: { opacity: 1 },\n  exit: { opacity: 0 }\n})\n\nconst ItemList = ({ items }) => (\n  <PoseGroup>\n    {items.map((item) => <Item key={item.id} />)}\n  </PoseGroup>\n)\n```\n\n**Notes:**\n- Every child must be provided a unique `key` property for `PoseGroup` to track entering and exiting children.\n- Entering children transition from their pre-enter pose to `'enter'`. The pre-enter pose is `'exit'` by default, and can be edited with the [`preEnterPose` prop](#posegroup-props-preenterpose).\n\n### Animating children\n\nAs with any posed component, the `enter`/`exit` pose will propagate throughout any of its posed component children.\n\nIn the case of the `exit` pose, `PoseGroup` will only unmount the animating component once **all of its children** have also finished their `exit` animation.\n\n### Passing props to children\n\nA common problem with transition components is passing props to components that have been removed from the tree. They might be animating out, but as far as React is concerned, they've already left (so props don't get updated).\n\nWith Pose for React, any props you provide to `PoseGroup` will be forwarded to all children, even ones that are leaving the tree.\n\nThis allows you to use the latest props in dynamic poses:\n\n```javascript\nconst Item = posed.li({\n  enter: { opacity: 1, x: 0 },\n  exit: {\n    opacity: 0,\n    x: ({ selectedItemId, id }) =>\n      id === selectedItemId ? 100 : -100\n  }\n});\n\nexport default ({ items, selectedItemId }) => (\n  <PoseGroup selectedItemId={selectedItemId}>\n    {items.map(({ id }) => <Item id={id} />)}\n  </PoseGroup>\n);\n```\n\n## Props\n\n### animateOnMount\n\n`animateOnMount: boolean = false`\n\nBy default, only children added to the `PoseGroup` **after** it has mounted are animated to `enter`.\n\nBy setting `animateOnMount` to `true`, all children elements will animate in on mount.\n\n### enterPose\n\n`enterPose: string = 'enter'`\n\nThe name of the pose to use when a component enters.\n\n### exitPose\n\n`exitPose: string = 'exit'`\n\nThe name of the pose to use when a component leaves.\n\n### preEnterPose\n\n`preEnterPose: string = 'exit'`\n\nThe name of the pose to set before a component enters. This can be used to configure where a components animates in **from**.\n\n### flipMove\n\n`flipMove: boolean = true`\n\nWhen an element exits, Pose takes it out of the layout and applies `position: absolute` so it can detect the new position of surrounding elements and animate via FLIP.\n\nWhile it attempts to figure out the correct matching `transform-origin` there are times when this fails. Setting `flipMove={false}` will prevent these issues.\n\n### onRest\n\n`onRest: Function`\n\nWhen a component finishes exiting, it isn't removed immediately. Instead, it's kept in the DOM until **all** currently leaving components have finished animating out to prevent expensive layout thrashing.\n\n`onRest` will fire when all exit transitions are complete.\n\nIf new exit transitions begin in the meantime, `onRest` won't be fired until these have also finished.\n\n### ...props\n\nAll remaining props passed to `PoseGroup` will be forwarded to its immediate children, for use in dynamic props.\n\nThis is useful because if you're removing a component, it's impossible in React to update its props without doing a two-pass render.\n\nBy providing them to the `PoseGroup` prop, Pose can pass these to the posed components to change the `exit` animation:\n\n```javascript\nconst Box = posed.div({\n  enter: { x: 0 },\n  exit: { x: ({ delta }) => - delta * 100 + 'vw' }\n});\n\nexport default ({ isVisible }) => (\n  <PoseGroup delta={1}>\n    {isVisible && <Box key=\"a\" />}\n  </PoseGroup>\n)\n```\n\n"
  },
  {
    "path": "packages/popmotion-pose/docs/api/react/react-config.md",
    "content": "---\ntitle: Config\ndescription: Configure a posed component\ncategory: react\n---\n\n> React Pose has been **deprecated** in favour of [Framer Motion](https://framer.com/motion). [Read the upgrade guide](https://www.framer.com/api/motion/migrate-from-pose/)\n\n# Config options\n\nOptions to configure [posed components](/pose/api/posed) in React Pose.\n\n<TOC />\n\n## Options\n\n### draggable\n\n`draggable?: true | 'x' | 'y'`\n\nIf `true`, will make the element draggable on both axis. Setting to either `'x'` or `'y'` will restrict movement to that axis.\n\nIf defined, allows use of the special `drag` pose for styling the element while dragging is active.\n\nA `dragEnd` pose can be **optionally** set for animating on drag end.\n\n```javascript\nconst config = {\n  draggable: 'x',\n  init: { scale: 1 },\n  drag: { scale: 1.2 }\n}\n```\n\nThe `drag` and `dragEnd` poses will travel through any posed children.\n\n### dragBounds\n\n`dragBounds?: { [key: string]: number } | (props: Props) => { [key: string]: number }`\n\nAn object that defines `top`, `right`, `bottom` and/or `left` drag boundaries in pixels.\n\nCurrently, these boundaries are enforced by a hard clamp.\n\n### hoverable\n\n`hoverable?: boolean`\n\nIf `true`, this element will receive `hover` poses when a pointer hovers over it.\n\nThere's also an **optional** `hoverEnd` pose, for providing a different pose when hovering ends.\n\n```javascript\nconst config = {\n  hoverable: true,\n  init: { scale: 1 },\n  hover: { scale: 1.2 }\n}\n```\n\nThe `hover` and `hoverEnd` poses will travel through any posed children.\n\n### focusable\n\n`focusable?: boolean`\n\nIf `true`, this element will receive `focus` poses when the element receives focus, and `blur` poses when it loses focus.\n\n```javascript\nconst config = {\n  focusable: true,\n  init: { scale: 1 },\n  focus: { scale: 1.2 },\n  blur: {\n    scale: 1,\n    transition: {\n      type: 'spring',\n      stiffness: 800\n    }\n  }\n};\n```\n\n### pressable\n\n`pressable?: boolean`\n\nIf `true`, this element will receive `press` poses when the element is pressed, and **optionally** `pressEnd` when pressing stops.\n\n```javascript\nconst config = {\n  pressable: true,\n  init: { scale: 1 },\n  press: { scale: 0.8 }\n};\n```\n\n### passive\n\n`passive: { [key: string]: PassiveValue }`\n\n```typescript\ntype PassiveValue = [\n  subscribedKey: string,\n  transform: (subscribedValue: any) => any,\n  fromParent?: true | string\n]\n```\n\nMap of values that are passively changed when other values, either on this Poser or an ancestor, change.\n\n`fromParent` can be set either as `true` or as a `string`:\n  - `true`: Link to value from immediate parent.\n  - `string`: Link to the nearest ancestor with this `label` prop.\n\n#### Example\n\nThe `transform` function here is composed with Popmotion [transformers](/api/transformers):\n\n```javascript\nconst config = {\n  draggable: 'x',\n  passive: {\n    backgroundColor: ['x', pipe(\n      clamp(0, 300),\n      interpolate([0, 300], [0, 1]),\n      blendColor('#f00', '#0f0')\n    )]\n  }\n}\n```\n\n### label\n\n`label: string`\n\nSet a label on this poser. Currently, this allows a `passive` value on a child poser to refer to this ancestor value.\n\n### props\n\n`props: { [key: string]: any }`\n\nDefault properties to provide to entered pose `transition` methods and dynamic pose props. These can be overridden by providing props to the posed component.\n\n### ...poses\n\n`...poses: { [key: string]: Pose }`\n\nAny other config props will be treated as poses (see [Pose config](#pose-config)).\n\n## Poses\n\nYou can call a pose anything, and animate to it by setting `<PosedComponent pose=\"poseName\" />` (or multiple poses with an array).\n\nA pose is defined by style attributes like `x` or `backgroundColor`, and the following optional props:\n\n### delay\n\n`delay?: number | (props: Props) => number`\n\nA duration, in milliseconds, to delay this transition. Does **not** affect children.\n\n### delayChildren\n\n`delayChildren?: number | (props: Props) => number`\n\nA duration, in milliseconds, to delay the transition of direct children.\n\n### flip\n\n`flip?: boolean = false`\n\nIf `true`, will convert this animation to a [FLIP animation](https://aerotwist.com/blog/flip-your-animations/).\n\n### staggerChildren\n\n`staggerChildren?: number | (props: Props) => number`\n\nA duration, in milliseconds, between transitioning each children.\n\n### staggerDirection\n\n`staggerDirection?: 1 | -1 | (props: Props) => 1 | -1`\n\nIf `1`, staggers from the first child to the last. If `-1`, from last to first.\n\n### beforeChildren\n\n`beforeChildren?: boolean | (props: Props) => boolean`\n\nIf `true`, will ensure this animation completes before firing any child animations.\n\n### afterChildren\n\n`afterChildren?: boolean | (props: Props) => boolean`\n\nIf `true`, will ensure this animation only fires after all child animations have completed.\n\n### applyAtStart/applyAtEnd\n\n`applyAtStart/applyAtEnd?: { [string]: any | (props: Props) => any }`\n\n`applyAtStart` and `applyAtEnd` accept style properties to apply either at the start or end of an animation.\n\nFor instance, you might have an element that you want to flip between `display: block` before it fades in, and `display: none` after it fades out:\n\n```javascript\nconst config = {\n  visible: {\n    applyAtStart: { display: 'block' },\n    opacity: 1\n  },\n  hidden: {\n    applyAtEnd: { display: 'none' },\n    opacity: 0\n  }\n};\n```\n\n### transition\n\n`transition?`\n\nThe `transition` prop can be used to create custom transitions.\n\nIt can be set as a transition definition:\n\n```javascript\ntransition: { type: 'spring' }\n```\n\nA function that returns a transition definition **or** a Popmotion animation:\n\n```javascript\ntransition: (props) => spring({...props})\ntransition: (props) => ({ type: 'spring' })\n```\n\nOr finally, a named map, where a separate `transition` is defined for each animating value. `default` can be used to define a transition for all remaining values. \n\n```javascript\nvisible: {\n  x: 0,\n  opacity: 1,\n  transition: {\n    x: { type: 'spring' },\n    default: (props) => tween(props)\n  }\n}\n```\n\n#### Transition definitions\n\nA transition definition describes the type of animation Pose should use to transition to the value defined in the Pose.\n\nThere are many types, and each has its own specific configuration props available.\n\n##### Tween (default)\n\nTransitions between one value and another over a set duration of time.\n\n- `duration?: number = 300`: Total duration of animation, in milliseconds.\n- `elapsed?: number = 0`: Duration of animation already elapsed, in milliseconds.\n- `ease?: string | number[] | Function`: The name of an easing function, a cubic bezier definition (as an array of numbers), or an easing function. The following easings are included with Pose:\n  - 'linear'\n  - 'easeIn', 'easeOut', 'easeInOut'\n  - 'circIn', 'circOut', 'circInOut'\n  - 'backIn', 'backOut', 'backInOut'\n  - 'anticipate'\n- `loop?: number = 0`: Number of times to loop animation.\n- `flip?: number = 0`: Number of times to flip animation.\n- `yoyo?: number = 0`: Number of times to reverse tween.\n\n##### Spring\n\nA spring animation based on `stiffness`, `damping` and `mass`.\n\n- `type: 'spring'`: Set transition to spring.\n- `stiffness?: number = 100`: Spring stiffness.\n- `damping?: number = 10`: Strength of opposing force.\n- `mass?: number = 1.0`: Mass of the moving object.\n- `restDelta?: number = 0.01`: End animation if distance to `to` is below this value **and** `restSpeed` is `true`.\n- `restSpeed?: number = 0.01`: End animation if speed drops below this value **and** `restDelta` is `true`.\n\n##### Physics\n\nIntegrated simulation of velocity, acceleration, friction and springs.\n\n- `type: 'physics'`: Set transition to physics.\n- `acceleration?: number = 0`: Increase `velocity` by this amount every second.\n- `restSpeed?: number = 0.001`: When absolute speed drops below this value, `complete` is fired.\n- `friction?: number = 0`: Amount of friction to apply per frame, from `0` to `1`.\n- `springStrength?: number = 0`: If set with `to`, will spring towards target with this strength.\n\n##### Keyframes\n\nKeyframes accepts an array of `values` and will animate between each in sequence.\n\nTiming is defined with a combination of `duration`, `easings` and `times` properties.\n\n- `type: 'keyframes'`: Set transition to keyframes.\n- `values: number[]`: An array of numbers to animate between. To use the value defined in the Pose as the final target value, set `transition` as a function: `transition: ({ to }) => { type: 'keyframes', values: [0, to] }`\n- `duration?: number = 300`: Total duration of animation, in milliseconds.\n- `easings?: Easing | Easing[]`: An array of easing functions for each generated tween, or a single easing function applied to all tweens. This array should be `values.length - 1`. Defaults to `easeOut`. (This doesn't yet support named easings)\n- `times?: number[]`: An array of numbers between `0` and `1`, representing `0` to `duration`, that represent at which point each number should be hit. Defaults to an array of evenly-spread durations will be calculated.\n- `elapsed?: number = 0`: Duration of animation already elapsed, in milliseconds.\n- `ease?: Easing = easeOut`: A function, given a progress between `0` and `1`, that returns a new progress value. Used to affect the rate of playback across the duration of the animation. (This doesn't yet support named easings)\n- `loop?: number = 0`: Number of times to loop animation.\n- `flip?: number = 0`: Number of times to flip animation.\n- `yoyo?: number = 0`: Number of times to reverse tween.\n\n##### Decay\n\n`decay` exponentially decelerates a number and velocity to an automatically generated target value. This target can be modified by the user.\n\nThis animation is particularly useful for implementing momentum scrolling.\n\n- `type: 'decay'`: Set transition to decay.\n- `power?: number = 0.8`: A constant with which to calculate a target value. Higher power = further target. `0.8` should be okay.\n- `timeConstant?: number = 350`: Adjusting the time constant will change the duration of the deceleration, thereby affecting its feel.\n- `restDelta?: number = 0.5`: Automatically completes the action when the calculated value is this far away from the target.\n- `modifyTarget?: (v: number) => number`: A function that receives the calculated target and returns a new one. Useful for snapping the target to a grid, for example.\n\n##### General transition props\n\nThe following props can be set on any transition:\n\n- `from?: number | Color`: Start value of animation (overrides Pose-generated value).\n- `to?: number | Color`: End value of animation (overrides Pose-generated value).\n- `velocity?: number`: Initial velocity of animation (overrides Pose-generated value).\n- `delay?: number`: Delay the execution of the transition by this amount of time (in milliseconds).\n- `min?: number`: Restrict output to numbers larger than this.\n- `max?: number`: Restrict output to numbers smaller than this.\n- `round?: boolean`: If `true`, output numbers will be rounded.\n\n#### Transition props\n\nIf set as a function, `transition` receives the same user-defined props as other dynamic pose properties, with some generated by Pose:\n\n```typescript\ntype TransitionsProps = {\n  from: any,\n  to: any,\n  velocity: number,\n  key: string,\n  prevPoseKey: string\n}\n```\n\n- `from`: The current state of the value\n- `velocity`: The current velocity of the value, if it's a number\n- `to`: The state we're animating to, as defined in the current pose. **Note:** You're under no obligation to actually animate to this value (for instance for non-deterministic animations)\n- `key`: The name of the value\n- `prevPoseKey`: The name of the pose this value was previously in.\n\n### values\n\n`...values: any | (props: Props) => any`\n\nAny remaining properties are treated as stylistic values and will be animated.\n\n\n"
  },
  {
    "path": "packages/popmotion-pose/docs/api/react/react-pose-text.md",
    "content": "---\ntitle: SplitText\ndescription: Animate words and characters using the power of React Pose animations.\ncategory: react\n---\n\n> React Pose has been **deprecated** in favour of [Framer Motion](https://framer.com/motion). [Read the upgrade guide](https://www.framer.com/api/motion/migrate-from-pose/)\n\n# React Pose Text\n\nReact Pose Text automatically splits strings of text into individual words and/or characters. These can then be animated with the full power of Pose:\n\n- Magic animations\n- Stagger across words and characters\n- Animate any style property, including `color` and `text-shadow`\n- Make words and characters individually draggable, or respond to a parent's dragging.\n- `enter`/`exit` animations with `PoseGroup`\n- Only 1kb!\n\n<CodeSandbox id=\"4jzzvm1vz7\" />\n\n<TOC />\n\n## License\n\nReact Pose Text is free for **non-profit** use under a GPL-v3 license.\n\nA permissive, commercial license is exclusive to backers of the [Popmotion Patreon](https://patreon.com/popmotion)!\n\n## Usage\n\n### Install\n\n```\nnpm install react-pose react-pose-text\n```\n\n### SplitText\n\nReact Pose Text exports a single component, `SplitText`.\n\n```javascript\nimport SplitText from 'react-pose-text';\n\nexport default () => (\n  <SplitText>Hello world!</SplitText>\n);\n```\n\nStrings wrapped with this component will be split into posed components for every word and character.\n\nPoses can be defined for both words and characters by providing [Pose configs](https://popmotion.io/pose/api/react-config/) to the `wordPoses` and `charPoses` props, respectively:\n\n```javascript\nconst charPoses = {\n  enter: { opacity: 1 },\n  exit: { opacity: 0 }\n};\n\nexport default () => (\n  <SplitText charPoses={charPoses}>\n    Hello world!\n  </SplitText>\n);\n```\n\n`SplitText` acts like a regular posed component, which means we can animate between poses using the `pose` property:\n\n```javascript\nexport default ({ isVisible }) => (\n  <SplitText\n    charPoses={charPoses}\n    pose={isVisible ? 'enter' : 'exit'}\n  >\n    Hello world!\n  </SplitText>\n);\n```\n\nIt also responds to pose changes further up the tree.\n\n<CodeSandbox id=\"100lwoo7wl\" />\n\n#### Special pose props\n\nLike normal posed components, all props provided to `SplitText` are sent through to dynamic pose properties:\n\n```javascript\nconst charPoses = {\n  enter: { y: 0 },\n  exit: { y: ({ initialOffset }) => initialOffset }\n};\n\nexport default () => (\n  <SplitText initialOffset={5} charPoses={charPoses}>\n    Hello world!\n  </SplitText>\n);\n```\n\nBut `SplitText` also provides a series of special props.\n\nWords receive:\n- `wordIndex`\n- `numWords`\n\nCharacters receive:\n- `wordIndex`\n- `numWords`\n- `charIndex`\n- `numChars`\n- `charInWordIndex`\n- `numCharsInWord`\n\nYou can use these props in various ways, for instance to create a variety of staggering effects by dynamically generating `delay`:\n\n```javascript\nconst charPoses = {\n  enter: {\n    y: 0,\n    delay: ({ charIndex }) => charIndex * 50 \n  }\n};\n```\n\n<CodeSandbox id=\"zzlr2p70mm\" />\n\n#### Pointer events\n\nYou can use Pose's pointer events as usual. For instance, you can make every word draggable by setting `draggable: true`:\n\n<CodeSandbox id=\"yqwwn1rmjv\" />\n\nThose poses still cascade down, too. So by setting `dragging` and `dragEnd` poses to our characters, we can make our characters animate while dragging words:\n\n<CodeSandbox id=\"38047jqp7m\" />\n"
  },
  {
    "path": "packages/popmotion-pose/docs/api/react/supported-values.md",
    "content": "---\ntitle: Supported values\ndescription: A list of supported values in Pose for React.\ncategory: react\n---\n\n> React Pose has been **deprecated** in favour of [Framer Motion](https://framer.com/motion). [Read the upgrade guide](https://www.framer.com/api/motion/migrate-from-pose/)\n\n# Supported values\n\n<TOC />\n\n## Overview\n\n**Any value that contains a number or color, or multiple numbers and colors, is animatable.**\n\nPose doesn't need specific support for a value to animate it. The only limitation is that if you're animating a complex value like CSS's `background-image` or SVG's `d`, **the non-animating parts of the value must match**.\n\nFor instance, from `'linear-gradient(to bottom, #1e5799 0%, #7db9e8 100%)'` you could animate to `'linear-gradient(to bottom, #D32A2D 25%, #FF3236 75%);'`, but not to `'linear-gradient(to top, #D32A2D 25%, #000 50%, #FF3236 75%);'`\n\n## CSS\n\n### Enhanced values\n\nPose has enhanced support for `x`, `y`, `width`, `height`, `top`, `left`, `right` and `bottom` values.\n\nAll of these can be animated between different value units, for instance `x` could be animated like so:\n\n```javascript\n{\n  closed: { x: 0 },\n  open: { x: '100vw' }\n}\n```\n\nThey can also be animated with `calc()`:\n\n```javascript\n{\n  closed: { x: 0 },\n  open: { x: 'calc(50vw - 50%)' }\n}\n```\n\n`width` and `height` specifically can also be animated to and from `'auto'`.\n\n### Transforms\n\nTransform values can be animated as separate values:\n\n- `x`, `y`, `z`, \n- `rotate`, `rotateX`, `rotateY`, `rotateZ`, \n- `scale`, `scaleX`, `scaleY`, `scaleZ`, \n- `skewX`, `skewY`, \n- `perspective`\n\n## SVG\n\nAll SVG attributes like `fill` and `stroke` can be animated, and Pose attempts to replace the confusing SVG transformation model with CSS.\n\n### Path drawing\n\nPath drawing is the process of animating `stroke-dasharray` and `stroke-dashoffset` to emulate a pen drawing a line. [This blog post](https://css-tricks.com/svg-line-animation-works/) explains the effect in more detail.\n\nPath drawing works with these properties works with `circle`, `ellipse`, `path`, `polygon`, `polyline`, `rect` and `text` SVG elements.\n\nBut for `path`, there's three special properties:\n\n* `pathLength`\n* `pathSpacing`\n* `pathOffset`\n\nThese are all set as a **percentage of the total path length, from `0` to `100`**, which is automatically measured by Pose.\n\nSo you can define an animation from `0` to `100`:\n\n```javascript\n{\n  empty: { pathLength: 0 },\n  fill: { pathLength: 100 }\n}\n```\n\n## Automatic animations\n\nEvery value, if no `transition` prop is defined, will have an animation automatically generated for it.\n\nCurrently, these are:\n\n### Movement\n\nTranslation and rotational transforms use an overdamped spring that retain any existing velocity and incorporate that into the next animation.\n\nThis gives the animation a playful, snappy and robust feel.\n\n```javascript\n{\n  type: 'spring',\n  stiffness: 500,\n  damping: 25,\n  restDelta: 0.5,\n  restSpeed: 10\n}\n```\n\n### Scale\n\nScale transforms use an overdamped spring that ensure that scale isn't inverted.\n\n```javascript\n{\n  type: 'spring',\n  stiffness: 700,\n  damping: to === 0 ? 100 : 35\n}\n```\n\n### Opacity\n\nOpacity uses a linear easing tween. Opacity looks odd when eased, so we transition straight from one to the other.\n\n```javascript\n{\n  ease: 'linear'\n}\n```\n\n### Everything else\n\nAll other properties use [Popmotion Pure's default tween](/api/tween) settings.\n\nIn the future it'll be possible to define automatic animations by defining the type of interface you wish to have (ie 'confident', 'playfull' etc).\n\nIn the nearer future we'll intelligently combine automatic animations to ensure they all finish at the same time.\n"
  },
  {
    "path": "packages/popmotion-pose/docs/api/react-native/native-config.md",
    "content": "---\ntitle: Config\ndescription: Options to create a posed component\ncategory: react-native\n---\n\n# Config\n\nEvery posed component is created via a config object:\n\n```javascript\nconst PosedComponent = posed.View(config)\n```\n\n<TOC />\n\n## Available options\n\n### draggable\n\n`draggable?: true | x | y`\n\nIf `true`, will make the component draggable on both axis. Setting to either `'x'` or `'y'` will restrict movement to that axis.\n\nIf defined, will allow the use of a special `dragging` and `dragEnd` poses.\n\n### passive\n\n`passive?: { [key: string]: PassiveValue }`\n\n```typescript\ntype PassiveValue = [\n  bindKey: string,\n  interpolate: InterpolateConfig,\n  fromParent?: true | string\n]\n```\n\nMap of values that are passively changed when other values, either on this Poser or an ancestor, change.\n\n`bindKey` is the name of the value to interpolate from.\n\n`InterpolateConfig` is an object with any [valid `Animated.Value.interpolate` props](https://facebook.github.io/react-native/docs/animations.html#interpolation).\n\n`fromParent` can be set either as `true` or as a `string`:\n  - `true`: Link to value from immediate parent.\n  - `string`: Link to the nearest ancestor with this `label` prop.\n\n### label\n\n`label?: string`\n\nSet a label on this poser. Currently, this allows a `passive` value on a child poser to refer to this ancestor value.\n\n### props\n\n`props?: { [key: string]: any }`\n\nProps to provide to the `transition` method and dynamic props of entered poses.\n\n### ...poses\n\n`...poses: { [key: string]: Pose }`\n\nRemaining keys will be treated as poses:\n\n## Poses\n\nYou can call a pose anything, and animate to it by providing its name to the posed component's `pose` property:\n\n```javascript\n<PosedComponent pose=\"poseName\" />\n<PosedComponent pose={['poseName', /* Multiple poses allowed */]}>\n```\n\nA pose is defined by style attributes like `x` or `opacity`, and the following optional props:\n\n### transition\n\n`transition?`\n\nThe `transition` prop can be used to create custom transitions.\n\nIt can be set as transition definition:\n\n```javascript\ntransition: { type: 'spring' }\n```\n\nA function that returns a transition definition **or** a React Animated animation:\n\n```javascript\ntransition: ({ value, ...props }) => spring(value, props)\ntransition: (props) => ({ type: 'spring' })\n```\n\nOr finally, a named map, where a separate `transition` is defined for each animating value. `default` can be used to define a transition for all remaining values. \n\n```javascript\nvisible: {\n  x: 0,\n  opacity: 1,\n  transition: {\n    x: { type: 'spring' },\n    default: ({ value, ...props }) =>\n      Animated.timing(value, props)\n  }\n}\n```\n\n#### Transition definitions\n\nA transition definition describes the type of animation Pose should use to transition to the value defined in the Pose.\n\nThere are many types, and each has its own specific configuration props available.\n\n##### Tween (default)\n\nTransitions between one value and another over a set duration of time.\n\n- `duration?: number = 300`: Total duration of animation, in milliseconds.\n- `ease?: string | number[] | Function`: The name of an easing function, a cubic bezier definition (as an array of numbers), or an easing function. The following easings are included with Pose:\n  - 'linear'\n  - 'easeIn', 'easeOut', 'easeInOut'\n  - 'circIn', 'circOut', 'circInOut'\n  - 'backIn', 'backOut', 'backInOut'\n  - 'anticipate'\n\n##### Spring\n\nA spring animation based on `stiffness`, `damping` and `mass`.\n\n- `type: 'spring'`: Set transition to spring.\n- `stiffness?: number = 100`: Spring stiffness.\n- `damping?: number = 10`: Strength of opposing force.\n- `mass?: number = 1.0`: Mass of the moving object.\n- `velocity?: number = 0`: Initial velocity.\n- `restDelta?: number = 0.01`: End animation if distance to `to` is below this value **and** `restSpeed` is `true`.\n- `restSpeed?: number = 0.01`: End animation if speed drops below this value **and** `restDelta` is `true`.\n- `overshootClamping?: boolean = false`: Clamps any overshoot beyond the target value.\n\n##### Keyframes\n\nKeyframes accepts an array of `values` and will animate to each, in sequence.\n\nTiming is defined with a combination of `duration`, `easings` and `times` properties.\n\n- `type: 'keyframes'`: Set transition to keyframes.\n- `values: number[]`: An array of numbers to animate between. To use the value defined in the Pose as the final target value, set `transition` as a function: `transition: ({ toValue }) => { type: 'keyframes', values: [0, toValue] }`. To use the current value as the current value as the initial value, skip definition that value: `values: [, 45, 90]`\n- `duration?: number = 300`: Total duration of animation, in milliseconds.\n- `easings?: Easing | Easing[]`: An array of easings (see tween for options) to provide to each generated tween, or a single easing applied to all tweens. This array should be `values.length - 1`. Defaults to `'easeOut'`.\n- `times?: number[]`: An array of numbers between `0` and `1`, representing `0` to `duration`, that represent at which point each number should be hit. Defaults to an array of evenly-spread durations will be calculated.\n\n##### General transition props\n\nThe following props can be set on any transition:\n\n- `loop?: number = 0`: If set, defines how many times transition will replay.\n- `delay?: number = 0`: Delay the execution of the transition by this amount of time (in milliseconds).\n- `isInteraction?: boolean = true`: Defines whether this animation creates an \"interaction handle\" on React Native's `InteractionManager`.\n\n#### Transition props\n\nIf set as a function, `transition` receives the same user-defined props as other dynamic pose properties, with some generated by Pose:\n\n```javascript\ntype Props = {\n  value: Animated.Value,\n  toValue: number,\n  key: string,\n  prevPoseKey: string,\n  useNativeDriver: boolean,\n  ...props: any\n}\n```\n\n- `value`: The React Animated `Value` being animated.\n- `toValue`: The state we're animating to, as defined in the current pose. **Note:** You're under no obligation to actually animate to this value (for instance for non-deterministic animations)\n- `key`: The name of the value.\n- `prevPoseKey`: The name of the pose this value was previously in.\n- `useNativeDriver`: Whether to use the native animation driver for better performance. If returning an Animated animation (rather than a transition definition), this **must** be passed to that animation.\n\n### delay\n\n`delay?: number | (props: Props) => number`\n\nA duration, in milliseconds, to delay this transition. Does **not** affect children.\n\n### delayChildren\n\n`delayChildren?: number | (props: Props) => number`\n\nA duration, in milliseconds, to delay the transition of direct children.\n\n### staggerChildren\n\n`staggerChildren?: number | (props: Props) => number`\n\nA duration, in milliseconds, between transitioning each children.\n\n### staggerDirection\n\n`staggerDirection?: 1 | -1 | (props: Props) => 1 | -1`\n\nIf `1`, staggers from the first child to the last. If `-1`, from last to first.\n\n### beforeChildren\n\n`beforeChildren?: boolean | (props: Props) => boolean`\n\nIf `true`, will ensure this animation completes before firing any child animations.\n\n### afterChildren\n\n`afterChildren?: boolean | (props: Props) => boolean`\n\nIf `true`, will ensure this animation only fires after all child animations have completed.\n\n### ...values\n\n`...values: any | (props: TransitionProps) => any`\n\nAny remaining properties are treated as stylistic values and will be animated.\n"
  },
  {
    "path": "packages/popmotion-pose/docs/api/react-native/native-posed.md",
    "content": "---\ntitle: Posed\ndescription: Create posed components\ncategory: react-native\n---\n\n# `posed`\n\nReact Native Pose exports a single function, `posed`.\n\n```javascript\nimport posed from 'react-native-pose';\n```\n\n<TOC />\n\n## Posed components\n\n`posed` is a factory function that creates posed components. These are components [configured with a series of states that it can animate between and other options](/pose/api/native-config).\n\nWe can use `posed` to create three different kinds of posed component:\n\n- Included components (ie `posed.View`)\n- Custom components\n- Function as child components\n\n### Included components\n\n[React Animated](https://facebook.github.io/react-native/docs/animations.html) ships with four animatable components: `View`, `Text`, `Image` and `ScrollView`.\n\nLikewise, `posed` has shortcuts for each of these components:\n\n- `posed.View(config)`\n- `posed.Text(config)`\n- `posed.Image(config)`\n- `posed.ScrollView(config)`\n\n### Custom components\n\nAnimated also has a helper function that you can use to create animated components from any normal component: `createAnimatedComponent(Component)`.\n\nIf `posed` is called as a function, it can also create an animated component from any other:\n\n`posed(Component)(config)`\n\nThis makes `posed.View` practically the same as `posed(View)`.\n\n### Function as children components\n\nBy creating posed components with the previous two methods, React Native Pose will automatically handle the application of the generated `Animated.Value`s.\n\nIn return for this simplicity, you lose a little flexibility. For instance, you don't get to choose the `transform` order, and you can't create arbitrary values (as they all get applied as `style`s).\n\nBy calling `posed` as a function without any `Component`, the returned posed component will use the \"function as children pattern\" to provide the `Animated.Value`s to children:\n\n```javascript\nconst PosedComponent = posed()({\n  open: { x: 0, scaleY: 1 },\n  closed: { x: 100, scaleY: 0 }\n});\n\nexport default ({ isOpen }) => (\n  <PosedComponent pose={isOpen ? 'open': 'closed'}>\n    {({ x, scaleY }) => (\n      <Animated.View style={{ transform: [{ translateX: x }, { scaleY }] }} />\n    )}\n  </PosedComponent>\n)\n```\n\n## Props\n\n### pose\n\n`pose?: string | string[]`\n\nThe name of one or more poses to set to.\n\n### initialPose\n\n`initialPose?: string | string[]`\n\nThe name of one or more poses to set to before the component mounts. Once the component mounts, it will transition from this pose into `pose`.\n\n### poseKey\n\n`poseKey?: string | number`\n\nIf `poseKey` changes, it'll force the posed component to transition to the current `pose`, even if it hasn't changed.\n\nThis won't be required for the majority of use-cases. But we might have something like a paginated where we pass the x offset to the component but the pose itself doesn't change:\n\n```javascript\nconst Slider = posed.View({\n  nextItem: {\n    x: ({ target }) => target\n  }\n})\n\n({ target }) => <Slider pose=\"nextItem\" poseKey={target} target={target} />\n```\n\n### onDragStart/onDragEnd\n\n`onDragStart/onDragEnd?: (e: NativeEvent, gestureState: GestureState) => any`\n\nLifecycle callbacks for drag events. Provided the same arguments as [PanResponder's lifecycle events](https://facebook.github.io/react-native/docs/panresponder.html).\n\n### withParent\n\n`withParent?: boolean = true`\n\nIf explicitly set to `false`, this posed component will become a new root for any posed children components.\n\n### values\n\n`values?: { [key: string]: Animated.Value }`\n\nOptional way of providing the posed component the `Animated.Value`s rather than letting it create them itself. In case you want to retain ownership for whatever reason.\n"
  },
  {
    "path": "packages/popmotion-pose/docs/api/react-native/native-supported-values.md",
    "content": "---\ntitle: Supported values\ndescription: A list of supported values in Pose for React Native.\ncategory: react-native\n---\n\n# Supported values\n\n<TOC />\n\n## Transforms\n\nPose for React Native supports the animation of all `transform` values.\n\n`rotate`, `rotateX` and `rotateY` must (currently) be defined as `'deg'` values:\n\n```javascript\nposed.View({\n  init: { rotate: '0deg' },\n  flip: { rotate: '180deg' }\n})\n```\n\n## Colors\n\nColor animations (`backgroundColor`, `color` etc) are **currently** only supported as [passive values](/pose/learn/native-passive):\n\n```javascript\nposed.View({\n  draggable: 'x',\n  passive: {\n    backgroundColor: ['x', {\n      inputRange: [-200, 200],\n      outputRange: ['#f00', '#0f0']\n    }]\n  }\n})\n```\n\n## Other values\n\nAll other values, defined either as a number or unit type, are animatable.\n\n**However,** React Animated (the underlying animation library) doesn't currently support native animation of these values, and animating them will disable native animation of **all** values on that component.\n"
  },
  {
    "path": "packages/popmotion-pose/docs/api/react-native/native-transition.md",
    "content": "---\ntitle: Transition\ndescription: Control enter/exit animations with Pose for React Native's Transition component\ncategory: react-native\n---\n\n# `Transition`\n\nThe `Transition` component is used to animate components as they enter and exit the component tree.\n\n<TOC />\n\n## Import\n\n```javascript\nimport posed, { Transition } from 'react-native-pose';\n```\n\n## Usage\n\nTo animate posed components as they're added and removed from the React tree, provide them as **direct** children of `Transition`.\n\nSet `enter` and `exit` poses to define how they should animate in and out.\n\n### Switching visibility\n\n```javascript\nconst Box = posed.View({\n  enter: { opacity: 1, y: 0 },\n  exit: { opacity: 0, y: 50 }\n});\n\nexport default ({ isVisible }) => (\n  <Transition>\n    {isVisible && <Box key=\"a\" />}\n  </Transition>\n)\n```\n\n### Switching components\n\n```javascript\nexport default ({ toShow }) => (\n  <Transition>\n    {toShow === 'a' ? <Box key=\"a\" /> : <Box key=\"b\" />}\n  </Transition>\n)\n```\n\n### Multiple children\n\n```javascript\nexport default ({ items }) => (\n  <Transition>\n    {items.map(item => <Box key={item.id} />)}\n  </Transition>\n)\n```\n\n### Passing props to children\n\nA common problem with transition components is passing props to components that have been removed from the tree. They might be animating out, but as far as React is concerned, they've already left (so props don't get updated).\n\nWith Pose for React Native, any props you provide to `Transition` will be forwarded to all children, even ones that are leaving the tree.\n\nThis allows you to use the latest props in dynamic poses:\n\n```javascript\nconst Item = posed.li({\n  enter: { opacity: 1, x: 0 },\n  exit: {\n    opacity: 0,\n    x: ({ selectedItemId, id }) =>\n      id === selectedItemId ? 100 : -100\n  }\n});\n\nexport default ({ items, selectedItemId }) => (\n  <Transition selectedItemId={selectedItemId}>\n    {items.map(({ id }) => <Item id={id} />)}\n  </Transition>\n);\n```\n\n### Notes\n\n- Posed components must be direct children of `Transition`.\n- Enter and exit poses will propagate throughout posed components, allowing you to animate multiple children components when their parent enters/exits.\n- Every child must have a unique `key` property.\n- If components affect each other's layout, some snapping will occur when exiting components are removed. Position with `position: 'absolute'` or ensure exiting components animate out **before** animating new components in via the `enterAfterExit` prop. \n\n## Props\n\n### animateOnMount\n\n`animateOnMount: boolean = false`\n\nBy default, only children added to the `Transition` **after** it has mounted are animated to `enter`.\n\nBy setting `animateOnMount` to `true`, all children elements will animate in on mount.\n\n### enterPose\n\n`enterPose: string = 'enter'`\n\nThe name of the pose to use when a component enters.\n\n### exitPose\n\n`exitPose: string = 'exit'`\n\nThe name of the pose to use when a component leaves.\n\n### preEnterPose\n\n`preEnterPose: string = 'exit'`\n\nThe name of the pose to set before a component enters. This can be used to configure where a components animates in **from**.\n\n### enterAfterExit\n\n`enterAfterExit: boolean = false`\n\nIf `true`, `Transition` will finish animating exiting components out **before** animating entering components in.\n\nThis can be useful when animating two or more components that affect each other's layout, which can lead to snapping when the exiting components are removed.\n\n### onRest\n\n`onRest: Function`\n\nWhen a component finishes exiting, it isn't removed immediately. Instead, it's kept in the DOM until **all** currently leaving components have finished animating out to prevent expensive layout thrashing.\n\n`onRest` will fire when all exit transitions are complete.\n\nIf new exit transitions begin in the meantime, `onRest` won't be fired until these have also finished.\n\n### ...props\n\nAll remaining props passed to `Transition` will be forwarded to its immediate children, for use in dynamic props.\n\nThis is useful because if you're removing a component, it's impossible in React to update its props without doing a two-pass render.\n\nBy providing them to the `Transition` prop, Pose can pass these to the posed components to change the `exit` animation:\n\n```javascript\nconst Box = posed.View({\n  enter: { x: 0 },\n  exit: { x: ({ delta }) => - delta * 100 + 'vw' }\n});\n\nexport default ({ isVisible }) => (\n  <Transition delta={1}>\n    {isVisible && <Box key=\"a\" />}\n  </Transition>\n)\n```\n"
  },
  {
    "path": "packages/popmotion-pose/docs/api/vue/vue-config.md",
    "content": "---\ntitle: Config\ndescription: Configure a posed component\ncategory: vue\n---\n\n# Config options\n\nOptions to configure [posed components](/pose/api/vue-posed) in Pose for Vue.\n\n<TOC />\n\n## Options\n\n### draggable\n\n`draggable?: true | 'x' | 'y'`\n\nIf `true`, will make the element draggable on both axis. Setting to either `'x'` or `'y'` will restrict movement to that axis.\n\nIf defined, allows use of the special `drag` pose for styling the element while dragging is active.\n\nA `dragEnd` pose can be **optionally** set for animating on drag end.\n\n```javascript\nconst config = {\n  draggable: 'x',\n  init: { scale: 1 },\n  drag: { scale: 1.2 }\n}\n```\n\nThe `drag` and `dragEnd` poses will travel through any posed children.\n\n### dragBounds\n\n`dragBounds?: { [key: string]: number }`\n\nAn object that defines `top`, `right`, `bottom` and/or `left` drag boundaries in pixels.\n\nCurrently, these boundaries are enforced by a hard clamp.\n\n### hoverable\n\n`hoverable?: boolean`\n\nIf `true`, this element will receive `hover` poses when a pointer hovers over it.\n\nThere's also an **optional** `hoverEnd` pose, for providing a different pose when hovering ends.\n\n```javascript\nconst config = {\n  hoverable: true,\n  init: { scale: 1 },\n  hover: { scale: 1.2 }\n}\n```\n\nThe `hover` and `hoverEnd` poses will travel through any posed children.\n\n### focusable\n\n`focusable?: boolean`\n\nIf `true`, this element will receive `focus` poses when the element receives focus, and `blur` poses when it loses focus.\n\n```javascript\nconst config = {\n  focusable: true,\n  init: { scale: 1 },\n  focus: { scale: 1.2 },\n  blur: {\n    scale: 1,\n    transition: {\n      type: 'spring',\n      stiffness: 800\n    }\n  }\n};\n```\n\n### pressable\n\n`pressable?: boolean`\n\nIf `true`, this element will receive `press` poses when the element is pressed, and **optionally** `pressEnd` when pressing stops.\n\n```javascript\nconst config = {\n  pressable: true,\n  init: { scale: 1 },\n  press: { scale: 0.8 }\n};\n```\n\n### passive\n\n`passive: { [key: string]: PassiveValue }`\n\n```typescript\ntype PassiveValue = [\n  subscribedKey: string,\n  transform: (subscribedValue: any) => any,\n  fromParent?: true | string\n]\n```\n\nMap of values that are passively changed when other values, either on this Poser or an ancestor, change.\n\n`fromParent` can be set either as `true` or as a `string`:\n  - `true`: Link to value from immediate parent.\n  - `string`: Link to the nearest ancestor with this `label` prop.\n\n#### Example\n\nThe `transform` function here is composed with Popmotion [transformers](/api/transformers):\n\n```javascript\nconst config = {\n  draggable: 'x',\n  passive: {\n    backgroundColor: ['x', pipe(\n      clamp(0, 300),\n      interpolate([0, 300], [0, 1]),\n      blendColor('#f00', '#0f0')\n    )]\n  }\n}\n```\n\n### label\n\n`label: string`\n\nSet a label on this poser. Currently, this allows a `passive` value on a child poser to refer to this ancestor value.\n\n### props\n\n`props: { [key: string]: any }`\n\nDefault properties to provide to entered pose `transition` methods and dynamic pose props. These can be overridden by providing props to the posed component.\n\n### ...poses\n\n`...poses: { [key: string]: Pose }`\n\nAny other config props will be treated as poses (see [Pose config](#pose-config)).\n\n## Poses\n\nYou can call a pose anything, and animate to it by setting `<PosedComponent pose=\"poseName\" />` (or multiple poses with an array).\n\nA pose is defined by style attributes like `x` or `backgroundColor`, and the following optional props:\n\n### delay\n\n`delay?: number | (props: Props) => number`\n\nA duration, in milliseconds, to delay this transition. Does **not** affect children.\n\n### delayChildren\n\n`delayChildren?: number | (props: Props) => number`\n\nA duration, in milliseconds, to delay the transition of direct children.\n\n### flip\n\n`flip?: boolean = false`\n\nIf `true`, will convert this animation to a [FLIP animation](https://aerotwist.com/blog/flip-your-animations/).\n\n### staggerChildren\n\n`staggerChildren?: number | (props: Props) => number`\n\nA duration, in milliseconds, between transitioning each children.\n\n### staggerDirection\n\n`staggerDirection?: 1 | -1 | (props: Props) => 1 | -1`\n\nIf `1`, staggers from the first child to the last. If `-1`, from last to first.\n\n### beforeChildren\n\n`beforeChildren?: boolean | (props: Props) => boolean`\n\nIf `true`, will ensure this animation completes before firing any child animations.\n\n### afterChildren\n\n`afterChildren?: boolean | (props: Props) => boolean`\n\nIf `true`, will ensure this animation only fires after all child animations have completed.\n\n### applyAtStart/applyAtEnd\n\n`applyAtStart/applyAtEnd?: { [string]: any | (props: Props) => any }`\n\n`applyAtStart` and `applyAtEnd` accept style properties to apply either at the start or end of an animation.\n\nFor instance, you might have an element that you want to flip between `display: block` before it fades in, and `display: none` after it fades out:\n\n```javascript\nconst config = {\n  visible: {\n    applyAtStart: { display: 'block' },\n    opacity: 1\n  },\n  hidden: {\n    applyAtEnd: { display: 'none' },\n    opacity: 0\n  }\n};\n```\n\n### transition\n\n`transition?`\n\nThe `transition` prop can be used to create custom transitions.\n\nIt can be set as a transition definition:\n\n```javascript\ntransition: { type: 'spring' }\n```\n\nA function that returns a transition definition **or** a Popmotion animation:\n\n```javascript\ntransition: (props) => spring({...props})\ntransition: (props) => ({ type: 'spring' })\n```\n\nOr finally, a named map where each prop is either a transition definition, or a function returning a transition definition/Popmotion animation:\n\n```javascript\nvisible: {\n  x: 0,\n  opacity: 1,\n  transition: {\n    x: { type: 'spring' },\n    default: (props) => tween(props)\n  }\n}\n```\n\n#### Transition definitions\n\nA transition definition describes the type of animation Pose should use to move to the value defined in the Pose.\n\nThere are many types, and each has its own specific configuration props available.\n\n##### Tween (default)\n\nTransitions between one value and another over a set duration of time.\n\n- `duration?: number = 300`: Total duration of animation, in milliseconds.\n- `elapsed?: number = 0`: Duration of animation already elapsed, in milliseconds.\n- `ease?: string | number[] | Function`: The name of an easing function, a cubic bezier definition, or an easing function. The following easings are included with Pose:\n  - 'linear'\n  - 'easeIn', 'easeOut', 'easeInOut'\n  - 'circIn', 'circOut', 'circInOut'\n  - 'backIn', 'backOut', 'backInOut'\n  - 'anticipate'\n- `loop?: number = 0`: Number of times to loop animation.\n- `flip?: number = 0`: Number of times to flip animation.\n- `yoyo?: number = 0`: Number of times to reverse tween.\n\n##### Spring\n\nA spring animation based on `stiffness`, `damping` and `mass`.\n\n- `type: 'spring'`: Set transition to spring.\n- `stiffness?: number = 100`: Spring stiffness.\n- `damping?: number = 10`: Strength of opposing force.\n- `mass?: number = 1.0`: Mass of the moving object.\n- `restDelta?: number = 0.01`: End animation if distance to `to` is below this value **and** `restSpeed` is `true`.\n- `restSpeed?: number = 0.01`: End animation if speed drops below this value **and** `restDelta` is `true`.\n\n##### Physics\n\nIntegrated simulation of velocity, acceleration, friction and springs.\n\n- `type: 'physics'`: Set transition to physics.\n- `acceleration?: number = 0`: Increase `velocity` by this amount every second.\n- `restSpeed?: number = 0.001`: When absolute speed drops below this value, `complete` is fired.\n- `friction?: number = 0`: Amount of friction to apply per frame, from `0` to `1`.\n- `springStrength?: number = 0`: If set with `to`, will spring towards target with this strength.\n\n##### Keyframes\n\nKeyframes accepts an array of `values` and will animate between each in sequence.\n\nTiming is defined with a combination of `duration`, `easings` and `times` properties (see [Methods](#methods))\n\n- `type: 'keyframes'`: Set transition to keyframes.\n- `values: number[]`: An array of numbers to animate between. To use the value defined in the Pose as the final destination value, set `transition` as a function: `transition: ({ to }) => { type: 'keyframes', values: [0, to] }`\n- `duration?: number = 300`: Total duration of animation, in milliseconds.\n- `easings?: Easing | Easing[]`: An array of easing functions for each generated tween, or a single easing function applied to all tweens. This array should be `values.length - 1`. Defaults to `easeOut`. (This doesn't yet support named easings)\n- `times?: number[]`: An array of numbers between `0` and `1`, representing `0` to `duration`, that represent at which point each number should be hit. Defaults to an array of evenly-spread durations will be calculated.\n- `elapsed?: number = 0`: Duration of animation already elapsed, in milliseconds.\n- `ease?: Easing = easeOut`: A function, given a progress between `0` and `1`, that returns a new progress value. Used to affect the rate of playback across the duration of the animation. (This doesn't yet support named easings)\n- `loop?: number = 0`: Number of times to loop animation.\n- `flip?: number = 0`: Number of times to flip animation.\n- `yoyo?: number = 0`: Number of times to reverse tween.\n\n##### Decay\n\n`decay` exponentially decelerates a number and velocity to an automatically generated target value. This target can be modified by the user.\n\nThis animation is particularly useful for implementing momentum scrolling.\n\n- `type: 'decay'`: Set transition to decay.\n- `power?: number = 0.8`: A constant with which to calculate a target value. Higher power = further target. `0.8` should be okay.\n- `timeConstant?: number = 350`: Adjusting the time constant will change the duration of the deceleration, thereby affecting its feel.\n- `restDelta?: number = 0.5`: Automatically completes the action when the calculated value is this far away from the target.\n- `modifyTarget?: (v: number) => number`: A function that receives the calculated target and returns a new one. Useful for snapping the target to a grid, for example.\n\n##### General transition props\n\nThe following props can be set on any transition:\n\n- `from?: number | Color`: Start value of animation (overrides Pose-generated value).\n- `to?: number | Color`: End value of animation (overrides Pose-generated value).\n- `velocity?: number`: Initial velocity of animation (overrides Pose-generated value).\n- `delay?: number`: Delay the execution of the transition by this amount of time (in milliseconds).\n- `min?: number`: Restrict output to numbers larger than this.\n- `max?: number`: Restrict output to numbers smaller than this.\n- `round?: boolean`: If `true`, output numbers will be rounded.\n\n#### Transition props\n\nIf set as a function, `transition` received the same user-defined props as other dynamic pose properties, with some generated by Pose:\n\n```typescript\ntype TransitionsProps = {\n  from: any,\n  to: any,\n  velocity: number,\n  key: string,\n  prevPoseKey: string\n}\n```\n\n- `from`: The current state of the value\n- `velocity`: The current velocity of the value, if it's a number\n- `to`: The state we're animating to, as defined in the current pose. **Note:** You're under no obligation to actually animate to this value (for instance for non-deterministic animations)\n- `key`: The name of the value\n- `prevPoseKey`: The name of the pose this value was previously in.\n\n### values\n\n`...values: any | (props: Props) => any`\n\nAny remaining properties are treated as stylistic values and will be animated.\n\n\n"
  },
  {
    "path": "packages/popmotion-pose/docs/api/vue/vue-posed.md",
    "content": "---\ntitle: Posed\ndescription: Create a posed component with Pose for Vue\ncategory: vue\n---\n\n# `posed`\n\n`posed` is used to create animated and interactive components that you can reuse throughout your Vue site.\n\n<TOC />\n\n## Import\n\n```javascript\nimport posed from 'vue-pose';\n```\n## Usage\n\n### Create a posed component\n\n`posed` can be used to create posed HTML and SVG elements.\n\nIt isn't called directly, instead we call it via the name of the element we want to create, along with a [posed component config](/pose/api/vue-config).\n\n```\n<template>\n  <Box :pose=\"isVisible ? 'visible' : 'hidden'\" />\n</template>\n\n<script>\nimport posed from 'vue-pose';\n\nexport default {\n  props: ['isVisible'],\n  components: {\n    Box: posed.div({\n      visible: { opacity: 1 },\n      hidden: { opacity: 0 }\n    })\n  }\n};\n</script>\n```\n\nEvery HTML and SVG element is supported.\n\n### Set a pose\n\nPoses can be set via the `pose` property.\n\n```\n<template>\n  <Box :pose=\"isVisible ? 'visible' : 'hidden'\" />\n</template>\n```\n\n### Children\n\nUsing a posed component creates a new tree of posed components. Any children that are also posed components are automatically added to this tree.\n\nThis means that orchestrating animations through React trees becomes trivial, as a pose only has to be set on a parent. Any children with that pose defined will also animate:\n\n```\n<template>\n  <Sidebar :pose=\"isVisible ? 'visible' : 'hidden'\">\n    <ul>\n      <Item v-for={item in items} v-bind:key={item} />\n    </ul>\n  </Sidebar>\n</template>\n\n<script>\nimport posed from 'vue-pose';\n\nexport default {\n  props: ['isVisible', 'items'],\n  components: {\n    Sidebar: posed.nav({\n      open: { x: '0%', staggerChildren: 100 },\n      closed: { x: '-100%' }\n    }),\n    Item: posed.li({\n      open: { opacity: 1 },\n      closed: { opacity: 0 }\n    })\n  }\n};\n</script>\n```\n\n<CodeSandbox id=\"qq667ljpz4\" height=\"500\" vue />\n\n### Styling\n\nPosed components return regular HTML elements, so they can be used with any CSS styling solution.\n\n## Props\n\n### pose\n\n`pose?: string`\n\nThe name of the current pose.\n\n### preEnterPose\n\n`preEnterPose?: string`\n\nThe name of a pose to set before the component mounts. If present, once the component mounts it will transition from this pose into `pose`.\n\n### poseKey\n\n`poseKey?: string | number`\n\nIf `poseKey` changes, it'll force the posed component to transition to the current `pose`, even if it hasn't changed.\n\nThis won't be required for the majority of use-cases. But we might have something like a paginated where we pass the x offset to the component but the pose itself doesn't change:\n\n```\n<template>\n  <Slider pose=\"nextItem\" :poseKey=\"target\" :target=\"target\" >\n</template>\n\n<script>\nimport posed from 'vue-pose';\n\nexport default {\n  props: ['target'],\n  components: {\n    Slider: posed.div({\n      nextItem: {\n        x: ({ target }) => target\n      }\n    })\n  }\n};\n</script>\n```\n\n### withParent\n\n`withParent?: boolean = true`\n\nIf set to `false`, this component won't subscribe to its parent posed component and create root for any further child components.\n\n### onPoseComplete\n\n`onPoseComplete?: Function`\n\nA callback that fires whenever a pose has finished transitioning.\n\n### onValueChange\n\n`onValueChange?: { [key: string]: any }`\n\n`onValueChange` is a map of functions, each corresponding to a value being animated by the posed component and will fire when that value changes.\n\n### ...props\n\n`...props: { [key: string]: any }`\n\nWhen a new pose is entered, any remaining props set on a component will be used to resolve that pose's dynamic props:\n\n```\n<template>\n  <ul>\n    <Item\n      v-for={item in items}\n      v-bind:key={item}\n      :i={item}\n      :pose=\"isVisible ? 'visible' : 'hidden'\"\n    />\n  </ul>\n</template>\n\n<script>\nimport posed from 'vue-pose';\n\nexport default {\n  props: ['isVisible', 'items'],\n  components: {\n    Item: posed.li({\n      visible: { opacity: 1 },\n      hidden: {\n        opacity: 0,\n        y: ({ i }) => i * 50\n      }\n    })\n  }\n};\n</script>\n```\n\n## Events\n\nThe following events can be subscribed to with `v-on`:\n\n### drag-start/drag-end\n\n`drag-start/drag-end: (e: Event) => void`\n\nCallbacks that fire when dragging starts or ends. **Note:** These props are immutable and can't be changed after mounting.\n\n### press-start/press-end\n\n`press-start/press-end: (e: Event) => void`\n\nCallbacks that fire when pressing starts or ends. **Note:** These props are immutable and can't be changed after mounting.\n"
  },
  {
    "path": "packages/popmotion-pose/docs/api/vue/vue-posetransition.md",
    "content": "---\ntitle: PoseTransition\ndescription: A component for managing entering and exiting Vue components \ncategory: vue\n---\n\n# `PoseTransition`\n\n`PoseTransition` is a component that can animate a single element as its added to, and removed from, the DOM.\n\n<TOC />\n\n## Import\n\n```javascript\nimport { PoseTransition } from 'vue-pose';\n```\n\n## Usage\n\n### Animating a single element\n\nBy default, `PoseTransition` will automatically animate a child element in and out using a simple `opacity` fade. We can control whether the child is rendered using `v-if`:\n\n```javascript\nexport default {\n  props: ['isVisible'],\n  components: { PoseTransition },\n  template: `<PoseTransition>\n    <div v-if=\"isVisible\">Hello world</div>\n  </PoseTransition>`\n};\n```\n\n### Custom transition\n\nWe can change the enter and exit animations by making the child animation a posed component:\n\n```javascript\nexport default {\n  props: ['isVisible'],\n  components: {\n    PoseTransition,\n    Message: posed.div({\n      enter: { opacity: 1, y: 0 },\n      exit: { opacity: 0, y: 20 }\n    })\n  },\n  template: `<PoseTransition>\n    <Message v-if=\"isVisible\">Hello world</Message>\n  </PoseTransition>`\n}\n```\n\n### Animating children\n\nEnter and exit poses are propagated like any other:\n\n```javascript\nexport default {\n  props: ['isVisible'],\n  components: {\n    PoseTransition,\n    Shade: posed.div({\n      enter: { opacity: 1, beforeChildren: true },\n      exit: { opacity: 0, afterChildren: true }\n    }),\n    Modal: posed.div({\n      enter: { opacity: 1, y: 0 },\n      exit: { opacity: 0, y: 20 }\n    })\n  },\n  template: `<PoseTransition>\n    <Shade v-if=\"isVisible\">\n      <Modal>Hello world</Modal>\n    </Shade>\n  </PoseTransition>`\n}\n```\n\n<CodeSandbox id=\"3qvz9w2rp6\" height=\"500\" vue />\n\n### Animating between components\n\n`PoseTransition` uses Vue's `transition` component under the hood, so many of the [same techniques for animating between components](https://vuejs.org/v2/guide/transitions.html#Transitioning-Between-Components) work here.\n\n## Props\n\n### appear\n\n`appear: boolean = false`\n\nBy adding `appear`, any elements present when the component mounts will be animated in from their `'exit'` pose.\n\n```javascript\n<PoseTransition appear>\n  /* children */\n</PoseTransition>\n```\n\n### enterPose/exitPose\n\n`enterPose: string = 'enter'`\n`exitPose: string = 'exit'`\n\nBy default, the poses used for entering and exiting are `'enter'` and `'exit'`, respectfully.\n\nBy providing strings as props to `PoseTransition`, you can name these whatever you like.\n\n```javascript\n<PoseTransition enterPose=\"visible\">\n```\n\n### mode\n\n`mode: 'in-out' | 'out-in'`\n\nBy default, if one element is animating in and another is animating out, they'll both be rendered and animated simultaneously.\n\nThis can sometimes look odd, or not be the desired effect. By setting `mode`, we can change this behaviour:\n\n- `'in-out'`: New element transitions in, then the current element transitions out.\n- `'out-in'`: Current element transitions out, then the new element transitions in.\n\n```javascript\n<PoseTransition mode=\"out-in\">\n```\n  "
  },
  {
    "path": "packages/popmotion-pose/docs/api/vue/vue-supported-values.md",
    "content": "---\ntitle: Supported values\ndescription: A list of supported values in Pose for Vue\ncategory: vue\n---\n\n# Supported values\n\n<TOC />\n\n## Overview\n\n**Any value that contains a number or color, or multiple numbers and colors, is animatable.**\n\nPose doesn't need specific support for a value to animate it. The only limitation is that if you're animating a complex value like CSS's `background-image` or SVG's `d`, **the non-animating parts of the value must match**.\n\nFor instance, from `'linear-gradient(to bottom, #1e5799 0%, #7db9e8 100%)'` you could animate to `'linear-gradient(to bottom, #D32A2D 25%, #FF3236 75%);'`, but not to `'linear-gradient(to top, #D32A2D 25%, #000 50%, #FF3236 75%);'`\n\n## CSS\n\n### Enhanced values\n\nPose has enhanced support for `x`, `y`, `width`, `height`, `top`, `left`, `right` and `bottom` values.\n\nAll of these can be animated between different value units, for instance `x` could be animated like so:\n\n```javascript\n{\n  closed: { x: 0 },\n  open: { x: '100vw' }\n}\n```\n\nThey can also be animated with `calc()`:\n\n```javascript\n{\n  closed: { x: 0 },\n  open: { x: 'calc(50vw - 50%)' }\n}\n```\n\n`width` and `height` specifically can also be animated to and from `'auto'`.\n\n### Transforms\n\nTransform values can be animated as separate values:\n\n- `x`, `y`, `z`, \n- `rotate`, `rotateX`, `rotateY`, `rotateZ`, \n- `scale`, `scaleX`, `scaleY`, `scaleZ`, \n- `skewX`, `skewY`, \n- `perspective`\n\n## SVG\n\nAll SVG attributes like `fill` and `stroke` can be animated, and Pose attempts to replace the confusing SVG transformation model with CSS.\n\n### Path drawing\n\nPath drawing is the process of animating `stroke-dasharray` and `stroke-dashoffset` to emulate a pen drawing a line. [This blog post](https://css-tricks.com/svg-line-animation-works/) explains the effect in more detail.\n\nPath drawing works with these properties works with `circle`, `ellipse`, `path`, `polygon`, `polyline`, `rect` and `text` SVG elements.\n\nBut for `path`, there's three special properties:\n\n* `pathLength`\n* `pathSpacing`\n* `pathOffset`\n\nThese are all set as a **percentage of the total path length, from `0` to `100`**, which is automatically measured by Pose.\n\nSo you can define an animation from `0` to `100`:\n\n```javascript\n{\n  empty: { pathLength: 0 },\n  fill: { pathLength: 100 }\n}\n```\n\n## Automatic animations\n\nEvery value, if no `transition` prop is defined, will have an animation automatically generated for it.\n\nCurrently, these are:\n\n### Movement\n\nTranslation and rotational transforms use an overdamped spring that retain any existing velocity and incorporate that into the next animation.\n\nThis gives the animation a playful, snappy and robust feel.\n\n```javascript\n{\n  type: 'spring',\n  stiffness: 500,\n  damping: 25,\n  restDelta: 0.5,\n  restSpeed: 10\n}\n```\n\n### Scale\n\nScale transforms use an overdamped spring that ensure that scale isn't inverted.\n\n```javascript\n{\n  type: 'spring',\n  stiffness: 700,\n  damping: to === 0 ? 100 : 35\n}\n```\n\n### Opacity\n\nOpacity uses a linear easing tween. Opacity looks odd when eased, so we transition straight from one to the other.\n\n```javascript\n{\n  ease: 'linear'\n}\n```\n\n### Everything else\n\nAll other properties use [Popmotion Pure's default tween](/api/tween) settings.\n\nIn the future it'll be possible to define automatic animations by defining the type of interface you wish to have (ie 'confident', 'playfull' etc).\n\nIn the nearer future we'll intelligently combine automatic animations to ensure they all finish at the same time.\n"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/react/accordion.md",
    "content": "---\ntitle: Accordion\ndescription: Make accordion animations in React by animating height between 0 and 'auto'\ncategory: react\n---\n\n# Accordion\n\nPose supports animating between any unit type for `width` and `height`, including `'auto'`.\n\nThis makes it trivial to create accordion animations.\n\n```javascript\nconst Content = posed.div({\n  closed: { height: 0 },\n  open: { height: 'auto' }\n});\n```\n\n<CodeSandbox id=\"pwk5yq8pzx\" height=\"500\" />\n"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/react/css-variables.md",
    "content": "---\ntitle: CSS variables\ndescription: A live example of Pose declaratively animating CSS variables\ncategory: react\n---\n\n# CSS variables\n\nPose can animate CSS variables like normal style props.\n\nIn the following example, all the boxes have the class `.box` with these styles:\n\n```css\n.box {\n  background: var(--color);\n}\n```\n\nSo to animate their background color, we can animate the `--color` property of one of their ancestors. In the following example, that's the `Container` posed component.\n\n[Read the full tutorial](/pose/learn/css-variables/)\n\n<CodeSandbox id=\"18vx11mr6q\" />"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/react/enter-exit.md",
    "content": "---\ntitle: \"Enter/exit: Single component\"\ndescription: React Pose's powerful PoseGroup component can be used to animate single children in and out of the DOM.\ncategory: react\n---\n\n# Enter/exit: Single component\n\n`PoseGroup` can be used to animate `enter` and `exit` states of a single component when it's added/removed to and from the component tree.\n\n```javascript\nconst Modal = posed.div({\n  enter: { opacity: 1 },\n  exit: { opacity: 0 }\n});\n\nexport default ({ isVisible }) => (\n  <PoseGroup>\n    {isVisible ? <Menu /> : null}\n  </PoseGroup>\n)\n```\n\n<CodeSandbox height=\"500\" id=\"lx6k64453l\" />\n"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/react/event-drag-boundaries.md",
    "content": "---\ntitle: \"Events: Drag with boundaries\"\ndescription: Animate hover events with Pose\ncategory: react\n---\n\n# Events: Drag with boundaries\n\nBoundaries can be imposed on dragging by using the `dragBounds` property.\n\nIt accepts `top`, `left`, `right`, and `bottom` properties in either pixels or percentages.\n\n```javascript\nconst config = {\n  draggable: 'x',\n  dragBounds: { left: '-100%', right: '100%' }\n}\n```\n\n<CodeSandbox height=\"500\" id=\"j27p9l3v6y\" />\n"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/react/event-drag.md",
    "content": "---\ntitle: \"Events: Drag\"\ndescription: Easily make elements draggable with Popmotion Pose\ncategory: react\n---\n\n# Events: Drag\n\nMaking an element draggable is as easy as setting `draggable: true`.\n\n```javascript\nconst config = {\n  draggable: true\n}\n```\n\n<CodeSandbox height=\"500\" id=\"8z7j041kyl\" />\n"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/react/event-focus.md",
    "content": "---\ntitle: \"Events: Focus\"\ndescription: Easily make elements focusable with Popmotion Pose\ncategory: react\n---\n\n# Events: Focus\n\nTo animate an element on focus, set `focusable: true` and a `focus` prop.\n\n```javascript\nconst config = {\n  focusable: true,\n  init: {\n    color: '#aaa',\n    outlineWidth: '0px',\n    outlineOffset: '0px',\n    scale: 1\n  },\n  focus: {\n    color: '#000',\n    outlineWidth: '12px',\n    outlineOffset: '5px',\n    outlineColor: '#AB36FF',\n    scale: 1.2\n  }\n}\n```\n\n<CodeSandbox id=\"rlly2kryrn\" />\n"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/react/event-hover.md",
    "content": "---\ntitle: \"Events: Hover\"\ndescription: Easily make elements hoverable with Popmotion Pose\ncategory: react\n---\n\n# Events: Hover\n\nTo animate an element on hover, set `hoverable: true` and a `pose` prop.\n\n```javascript\nconst config = {\n  hoverable: true,\n  init: { scale: 1 },\n  hover: { scale: 1.2 }\n}\n```\n\n<CodeSandbox id=\"jlwnqwomo9\" />\n"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/react/event-press.md",
    "content": "---\ntitle: \"Events: Press\"\ndescription: Easily make elements pressable with Popmotion Pose\ncategory: react\n---\n\n# Events: Press\n\nTo animate an element on press, set `pressable: true` and a `press` prop.\n\n```javascript\nconst config = {\n  pressable: true,\n  init: { scale: 1 },\n  press: { scale: 0.8 }\n}\n```\n\n<CodeSandbox id=\"31n86p0jw6\" />\n"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/react/filter.md",
    "content": "---\ntitle: CSS filters\ndescription: A live example of animating CSS filters with React Pose\ncategory: react\n---\n\n# CSS filters\n\nCSS filters can be animated by settings `filter` as you [would in CSS](https://developer.mozilla.org/en-US/docs/Web/CSS/filter):\n\n```javascript\nconst config = {\n  hoverable: true,\n  init: { filter: 'grayscale(80%) blur(2px)' },\n  hover: { filter: 'grayscale(0%) blur(0px)' }\n};\n```\n\nHover over, or tap, the image in this example to see the effect in action.\n\n<CodeSandbox height=\"500\" id=\"31886n8vp1\" />\n"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/react/outline.md",
    "content": "---\ntitle: CSS outline\ndescription: A live example of animating CSS outline with React Pose\ncategory: react\n---\n\n# CSS outline\n\nThe outline properties can be animated with Pose either individually:\n\n```javascript\nconst config = {\n  focusable: true,\n  init: {\n    color: '#aaa',\n    outlineWidth: '0px',\n    outlineOffset: '0px',\n    scale: 1\n  },\n  focus: {\n    color: '#000',\n    outlineWidth: '12px',\n    outlineOffset: '5px',\n    outlineColor: '#AB36FF',\n    scale: 1.2\n  }\n};\n```\n\nOr as a single property:\n\n```javascript\nconst config = {\n  focusable: true,\n  init: {\n    outline: '0px ridge rgba(170, 50, 220, 0)'\n  },\n  focus: {\n    outline: '8px ridge rgba(170, 50, 220, .6)'\n  }\n};\n```\n\n<CodeSandbox id=\"rlly2kryrn\" />\n"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/react/posegroup-reordering.md",
    "content": "---\ntitle: 'PoseGroup: Reordering items'\ndescription: React Pose's powerful PoseGroup component can automatically animate reordered items.\ncategory: react\n---\n\n# PoseGroup: Reordering items\n\nWhen posed items in a `PoseGroup` component are reordered, they're automatically animated to their new position:\n\n```javascript\nconst Item = posed.li();\n\nexport default ({ items }) => (\n  <PoseGroup>\n    {items.map(({ id }) => <Item key={id} />)}\n  </PoseGroup>\n)\n```\n\n<CodeSandbox height=\"500\" id=\"82k2rxv3kl\" />\n"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/react/react-medium-style-image-zoom.md",
    "content": "---\ntitle: Medium-style image zoom\ndescription: Pose for React makes it easy to write Medium-style image zoom.\ncategory: react\n---\n\n# Medium-style image zoom\n\nBy leveraging Pose's FLIP capabilities, and the `applyAtStart` and `applyAtEnd` properties, it becomes trivial to implement [Medium](https://medium.com)-style image zooming.\n\n```javascript\nconst Frame = posed.div({\n  zoomedOut: {\n    applyAtEnd: { display: 'none' },\n    opacity: 0\n  },\n  zoomedIn: {\n    applyAtStart: { display: 'block' },\n    opacity: 1\n  }\n});\n\nconst Image = posed.img({\n  zoomedOut: {\n    position: 'static',\n    width: 'auto',\n    height: 'auto',\n    flip: true\n  },\n  zoomedIn: {\n    position: 'fixed',\n    top: 0,\n    left: 0,\n    right: 0,\n    bottom: 0,\n    flip: true\n  }\n});\n```\n\n<CodeSandbox height=\"700\" id=\"rrjx477w3n\" />\n"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/react/route-transitions-reach-router.md",
    "content": "---\ntitle: 'Route transitions: Reach Router'\ndescription: A live example of route transitions with Pose and Reach Router\ncategory: react\n---\n\n# Route transitions: Reach Router\n\n[Read the full tutorial](/pose/learn/route-transitions-reach-router/)\n\n<CodeSandbox height=\"600\" id=\"mzx1jz521p\" />\n"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/react/route-transitions-react-router.md",
    "content": "---\ntitle: 'Route transitions: React Router'\ndescription: A live example of route transitions with Pose and React Router\ncategory: react\n---\n\n# Route transitions: React Router\n\n[Read the full tutorial](/pose/learn/route-transitions-react-router/)\n\n<CodeSandbox height=\"600\" id=\"wq324qk687\" />\n"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/react/splittext-as-children.md",
    "content": "---\ntitle: SplitText as children\ndescription: Animate individual words and characters with Pose animations\ncategory: react\n---\n\n# SplitText as children\n\nPose changes flow through to the children posed components made by [React Pose Text](/pose/api/react-pose-text)'s `SplitText` component.\n\n<CodeSandbox id=\"100lwoo7wl\" />\n"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/react/splittext-custom-animations.md",
    "content": "---\ntitle: SplitText custom animations\ndescription: Animate individual words and characters with Pose animations\ncategory: react\n---\n\n# SplitText custom animations\n\nUsing the special properties provided by [React Pose Text](/pose/api/react-pose-text), you can create custom animations and staggers per word and character.\n\n<CodeSandbox id=\"zzlr2p70mm\" />\n"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/react/splittext-ui-events.md",
    "content": "---\ntitle: SplitText UI events\ndescription: Animate individual words and characters with Pose animations\ncategory: react\n---\n\n# SplitText UI events\n\nUsing [React Pose Text](/pose/api/react-pose-text), individual words and characters can be respond to all the same [UI events](/pose/api/ui-events) as other posed components.\n\nThese poses are all passed through both words and characters.\n\n<CodeSandbox id=\"38047jqp7m\" />\n"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/react/splittext.md",
    "content": "---\ntitle: SplitText\ndescription: Animate individual words and characters with Pose animations\ncategory: react\n---\n\n# SplitText\n\nWith [React Pose Text](/pose/api/react-pose-text), you can use Pose animations across individual words and characters.\n\n<CodeSandbox id=\"4jzzvm1vz7\" />\n"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/react/svg-morphing.md",
    "content": "---\ntitle: SVG Morphing\ndescription: With Pose and a path morphing library like Flubber, you can perform declarative SVG path morphing animations.\ncategory: react\n---\n\n# SVG Morphing\n\nBy combining a path morphing library like [Flubber](https://github.com/veltman/flubber) with Pose, we can declaratively animate between any two SVG paths.\n\nBy importing animations from [Popmotion Pure](/pure), which is included with Pose, we can use their powerful `pipe` method with Flubber's `interpolate` to create a special `transition` prop that animates between paths:\n\n```javascript\nimport { tween } from 'popmotion';\nimport { interpolate } from 'flubber';\n\nconst morphTransition = ({ from, to }) =>\n  tween().pipe(interpolate(from, to));\n```\n\n<CodeSandbox height=\"700\" id=\"31lzml4nr1\" />"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/vue/vue-animating-children.md",
    "content": "---\ntitle: Animating children\ndescription: An live example of animating across children using Pose for Vue.\ncategory: vue\n---\n\n# Animating children\n\nPose changes propagate across posed components, so you only have to set `pose` on a parent to animate all its children.\n\n```javascript\n<template>\n  <Sidebar :pose=\"isVisible ? 'visible': 'hidden'\">\n    <Item v-for=\"item in items\" v-bind:key=\"item\" />\n  </Sidebar>\n</template>\n```\n\n<CodeSandbox id=\"qq667ljpz4\" height=\"500\" vue />\n"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/vue/vue-enter-exit.md",
    "content": "---\ntitle: Enter/exit transitions\ndescription: An live example of using the PoseTransition component to make enter and exit transitions with Pose for Vue\ncategory: vue\n---\n\n# Enter/exit transitions\n\nPose for Vue offers a special version of Vue's `transition` component.\n\nUsed to animate between single children, `PoseTransition` automatically creates opacity animations as child DOM elements are added and removed.\n\nBy providing it posed components, custom animations can be defined. They even flow down through children!\n\n```javascript\nexport default {\n  data: () => ({ isVisible: true }),\n  components: {\n    PoseTransition,\n    Shade: posed.div({\n      enter: {\n        opacity: 1,\n        beforeChildren: true,\n        transition: { duration: 200, ease: \"linear\" }\n      },\n      exit: {\n        opacity: 0,\n        afterChildren: true,\n        transition: { duration: 200, ease: \"linear\" }\n      }\n    }),\n    Modal: posed.div({\n      enter: { opacity: 1, z: 0 },\n      exit: { opacity: 0, z: -150 }\n    })\n  },\n  template: `<div>\n    <button v-on:click=\"isVisible = true\">Open modal</button>\n    <PoseTransition appear>\n      <Shade v-on:click.native=\"isVisible = false\" class=\"shade\" v-if=\"isVisible\">\n        <Modal class=\"modal\" />\n      </Shade>\n    </PoseTransition>\n  </div>`\n};\n```\n\n<CodeSandbox id=\"3qvz9w2rp6\" height=\"500\" vue />\n"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/vue/vue-flip.md",
    "content": "---\ntitle: FLIP\ndescription: An live example of making FLIP animations in Pose for Vue\ncategory: vue\n---\n\n# FLIP\n\nThe FLIP technique, [fully explained here](https://aerotwist.com/blog/flip-your-animations/), is a way of animating expensive, layout-breaking animations like `width` and `top` by using quick transforms.\n\nIn Pose for Vue, performing a FLIP animation is as simple as providing a pose the `flip: true` property.\n\n```javascript\nBox: posed.div({\n  fullscreen: {\n    width: '100vw',\n    height: '100vh',\n    transition: tween,\n    flip: true\n  },\n  thumbnail: {\n    width: 100,\n    height: 100,\n    transition: tween,\n    flip: true\n  }\n})\n```\n\nClick on this box to see it in action:\n\n<CodeSandbox id=\"vvw57kww70\" height=\"500\" vue />\n"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/vue/vue-magic-animations.md",
    "content": "---\ntitle: Magic animations\ndescription: An live example of magic animations in Pose for Vue.\ncategory: vue\n---\n\n# Magic animations\n\nEven with no `transition` defined, Pose for Vue will automatically create snappy and responsive transitions between to states.\n\n```javascript\nposed.div({\n  left: { x: -100 },\n  right: { x: 100 }\n})\n```\n\n<CodeSandbox id=\"74471lpxqx\" vue />"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/vue/vue-medium-style-image-zoom.md",
    "content": "---\ntitle: Medium-style image zoom\ndescription: Pose for Vue makes it easy to write Medium-style image zoom.\ncategory: vue\n---\n\n# Medium-style image zoom\n\nBy leveraging Pose's FLIP capabilities, and the `applyAtStart` and `applyAtEnd` properties, it becomes trivial to implement [Medium](https://medium.com)-style image zooming.\n\n```javascript\nconst Frame = posed.div({\n  zoomedOut: {\n    applyAtEnd: { display: 'none' },\n    opacity: 0\n  },\n  zoomedIn: {\n    applyAtStart: { display: 'block' },\n    opacity: 1\n  }\n});\n\nconst Image = posed.img({\n  zoomedOut: {\n    position: 'static',\n    width: 'auto',\n    height: 'auto',\n    flip: true\n  },\n  zoomedIn: {\n    position: 'fixed',\n    top: 0,\n    left: 0,\n    right: 0,\n    bottom: 0,\n    flip: true\n  }\n});\n```\n\n<CodeSandbox height=\"700\" id=\"4w9vq9vkmw\" />\n"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/vue/vue-passive-values.md",
    "content": "---\ntitle: Passive values\ndescription: An live example of making passive values in Pose for Vue\ncategory: vue\n---\n\n# Passive values\n\nA passive value is a value that isn't animated directly. It only changes when another value changes.\n\n```javascript\nposed.div({\n  draggable: 'x',\n  passive: {\n    opacity: ['x', interpolate(\n      [-200, -100, 100, 200],\n      [0, 1, 1, 0]\n    )]\n  }\n})\n```\n\n<CodeSandbox id=\"848v06y8yj\" height=\"400\" vue />\n"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/vue/vue-ui-events-dragging.md",
    "content": "---\ntitle: \"UI events: Drag\"\ndescription: An live example of making an element draggable with a single prop in Pose for Vue\ncategory: vue\n---\n\n# UI events: Drag\n\nMaking an element draggable in Pose for Vue is a simple matter of setting `draggable` to `true`.\n\n```javascript\nposed.div({ draggable: true })\n```\n\nTo restrict to a single axis, use either `'x'` or `'y'`.\n\n```javascript\nposed.div({ draggable: 'x' })\n```\n\n<CodeSandbox id=\"xo2zn69j9p\" height=\"400\" vue />\n\nYou can use the special `drag` and `dragEnd` poses to animate the element while dragging is in progress:\n\n<CodeSandbox id=\"xvjnq4q6p4\" height=\"400\" vue />\n\n\n"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/vue/vue-ui-events-focus.md",
    "content": "---\ntitle: \"UI events: Focus\"\ndescription: An live example of making an element focusable with a single prop in Pose for Vue\ncategory: vue\n---\n\n# UI events: Focus\n\nMaking an element focusable in Pose for Vue is a simple matter of setting `press` to `true`, with associated poses:\n\n```javascript\nposed.input({\n  focusable: true,\n  init: {\n    color: '#aaa',\n    outlineWidth: '0px',\n    outlineOffset: '0px',\n    scale: 1\n  },\n  focus: {\n    color: '#000',\n    outlineWidth: '12px',\n    outlineOffset: '5px',\n    outlineColor: '#AB36FF',\n    scale: 1.2\n  }\n})\n```\n\n<CodeSandbox id=\"k3j0q867v7\" height=\"400\" vue />\n"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/vue/vue-ui-events-hover.md",
    "content": "---\ntitle: \"UI events: Hover\"\ndescription: An live example of making an element hoverable with a single prop in Pose for Vue\ncategory: vue\n---\n\n# UI events: Hover\n\nMaking an element hoverable in Pose for Vue is a simple matter of setting `press` to `true`, with associated poses:\n\n```javascript\nposed.div({\n  hoverable: true,\n  init: {\n    scale: 1,\n    boxShadow: '0px 0px 0px rgba(0,0,0,0)'\n  },\n  hover: {\n    scale: 1.2,\n    boxShadow: '0px 5px 10px rgba(0,0,0,0.2)'\n  }\n})\n```\n\n<CodeSandbox id=\"qvnw69lv9\" height=\"400\" vue />\n"
  },
  {
    "path": "packages/popmotion-pose/docs/examples/vue/vue-ui-events-press.md",
    "content": "---\ntitle: \"UI events: Press\"\ndescription: An live example of making an element pressable with a single prop in Pose for Vue\ncategory: vue\n---\n\n# UI events: Press\n\nMaking an element pressable in Pose for Vue is a simple matter of setting `press` to `true`, with associated poses:\n\n```javascript\nposed.div({\n  pressable: true,\n  init: { scale: 1 },\n  press: { scale: 0.8 }\n})\n```\n\n<CodeSandbox id=\"6jqrnr57ok\" height=\"400\" vue />\n"
  },
  {
    "path": "packages/popmotion-pose/docs/learn/get-started.md",
    "content": "---\ntitle: Get started\ndescription: Get started with the Pose animation system for HTML, SVG, React and React Native\n---\n\n# Get started\n\n## Choose your adventure:\n\n### [React](/pose/learn/popmotion-get-started)\n### [React Native](/pose/learn/native-get-started)\n### [Vue](/pose/learn/vue-get-started)\n"
  },
  {
    "path": "packages/popmotion-pose/docs/learn/how-to/css-variables.md",
    "content": "---\ntitle: CSS variables\ndescription: How to declaratively animate CSS variables\ncategory: how-to\n---\n\n# Animate CSS variables\n\n[CSS variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables) are variables that can be defined on a parent element and then referenced throughout its children:\n\n```css\nbody {\n  --brand-color: #f00;\n}\n\na {\n  color: var(--brand-color);\n}\n```\n\nThe benefit of CSS variables vs variables in CSS pre-processors like SASS is that they're **dynamic**, which means they can be updated at runtime.\n\nSo in the above example, to change the link color we'd simply change the value of `--brand-color`.\n\nBecause these values can be changed, they can be animated. In this tutorial we'll demonstrate how to animate multiple elements on a page by animating a single CSS variable.\n\n<CodePen id=\"JLaBNG\" />\n\n<TOC />\n\n## CSS\n\nFirst, open this [CodePen](https://codepen.io/popmotion/pen/mxGZNx?editors=0110) to follow along with the tutorial.\n\nAs a simple example, we're going to animate a `distance` property. Add that to `body`:\n\n```css\nbody {\n  --distance: 0px;\n}\n```\n\nNow, on the `.box` rule add a `transform` that uses this `distance`:\n\n```css\ntransform: translateX(var(--distance));\n``` \n\n## JavaScript\n\nIn all the previous Pose tutorials, if we've wanted to change a property of an element, we've selected the element itself.\n\nWith CSS variables, we're instead going to animate the parent element where the variable is set. Which, in this case, is `body`:\n\n```javascript\nconst body = document.querySelector('body')\n```\n\nNow define the pose config with a single pose, called `right`:\n\n```javascript\nconst config = {\n  right: { '--distance': '100px' }\n}\n```\n\nBring the two together by creating a new poser:\n\n```javascript\nconst bodyPoser = pose(body, config)\n```\n\nTo trigger the animation, set the pose to \"right\":\n\n```javascript\nbodyPoser.set('right')\n```\n\nAnd that's it! All four boxes will animate to the right.\n\n## Gotchas\n\nThere are a couple of points to keep in mind when you animate CSS variables.\n\n### Pose can't infer types\n\nIn the example above, we explicitly set `--distance` to `'100px'`. Usually when animating `x`, we'd simply use `100` as a raw number and Pose would infer that we should use pixels.\n\nWhen you're animating CSS variables, **Pose doesn't know what you're going to do with the variable**. So we need to manually tell it if we want specific measurements.\n\n### CSS variables sometimes contain whitespace\n\nIn [this CodePen](https://codepen.io/popmotion/pen/JLaBNG?editors=0010), we're animating using the `--color` variable as initially read directly from the CSS.\n\nOddly, this read value is sometimes returned with extra whitespace. If you then set the value with the extra whitespace, it breaks! In this example we're using `from` as `from.trim()` to fix this, but there is an [open issue in the Stylefire](https://github.com/Popmotion/stylefire/issues/16) to have this fixed.\n"
  },
  {
    "path": "packages/popmotion-pose/docs/learn/how-to/framer-x.md",
    "content": "---\ntitle: \"Use Pose in Framer X (WIP)\"\ndescription: Add declarative animations to your Framer X prototypes\ncategory: how-to\n---\n\n# Use Pose in Framer X (WIP)\n\nFramer X beta invites are going out and it's already possible to use Pose in Framer X prototypes.\n\nIt's early days at the moment so integration isn't seamless but it's already possible to add UI events like `drag`, `hover` and `press`.\n\nYou can also already use Framer X to test animations by exposing pose logic via the UI.\n\nBut there are currently limitations, and we'll take a look at those, too.\n\n<TOC />\n\n## Install Pose\n\nFirst we need to add Pose to our Framer project.\n\nWith our project open in Framer X, go to File > Show Project Folder.\n\n![Framer X Show Project](/guides/framer-x-show-project.png)\n\nYou should have the `container` folder highlighted. Open this folder in your terminal of choice.\n\n> If you're using VS Code, drag and drop the highlighted folder onto the VS Code dock icon. Then, in VS Code's file browser, right click in the project root and choose \"Open in Terminal\".\n\nThis folder is a typical yarn package, so you can add Pose by running `yarn add react-pose`.\n\nThe current limitation with this process is you have to repeat it for every project you want to use Pose in. I'm also unclear as to whether yarn dependencies are saved to the project file itself, as `Show Project Folder` opens a directory in the app cache.\n\n## Create a posed Framer component\n\nAt the bottom of the Framer X Component panel, there's a button labelled \"New Component\". Click that, give your component a name, choose \"from code\" and press \"Create and edit\".\n\n![Create a new component](/guides/framer-x-create-component.png)\n\nYou'll be greeted with a TypeScript file containing some simple React code.\n\nThe only Framer X-specific code in here is a static property called `propertyControls`, which we'll explore in a moment.\n\nFirst, import Pose and make a simple hoverable component:\n\n```javascript\nimport posed from 'react-pose';\n\nconst Container = posed.div({\n  hoverable: true,\n  init: { scale: 1 },\n  hover: { scale: 1.2 }\n});\n```\n\nReplace the render function with the following:\n\n```javascript\nreturn <Container style={style}>{this.props.text}</Container>;\n```\n\nSave, and return to the Framer X editor.\n\nIn the components panel you'll see your new component. You can add this to the Framer X editor by dragging and dropping it in place.\n\nClick the play icon in the top and hover over your new component. It'll react to your hovering as expected.\n\n![New Framer interactions!](/guides/framer-x-a.gif)\n\n## Expose pose controls\n\nGo back to your editor and highlight your component. Notice in the right-hand inspector there's a section named after your component with a text input labelled \"Text\". If you replace \"Hello world!\", your component will update with the input text.\n\nGo to the source code of your component and take a look at the `render` function. It's outputting `this.props.text`.\n\nNow look at `propertyControls`. It has a single property, `text`, with a title of \"Text\". This is how you expose control over `props` via the Framer X UI.\n\nWe're going to use this to control Pose animations.\n\nFirst, cmd-click on `propertyControls`' `PropertyControls` type. This will take you through to its type definition, and we can take a look at some of the control types available to us.\n\nLet's use a simple control, a `Boolean`. Add this to `propertyControls`:\n\n```javascript\nisVisible: {\n  type: ControlType.Boolean,\n  title: \"Is visible\"\n}\n```\n\nWe also need to add a default for this property to `defaultProps`:\n\n```javascript\nstatic defaultProps = {\n  text: \"Hello World!\",\n  isVisible: false\n};\n```\n\nAnd a type for the property to the `Props` interface:\n\n```javascript\ninterface Props {\n  text: string;\n  isVisible: boolean;\n}\n```\n\nNow, this control will be available to use in the inspector panel.\n\nBut we still need to use this prop in our pose logic. Add two new poses, `visible` and `hidden`:\n\n```javascript\nconst Container = posed.div({\n  hoverable: true,\n  init: { scale: 1 },\n  hover: { scale: 1.2 },\n  visible: { opacity: 1 },\n  hidden: { opacity: 0 }\n});\n```\n\nAnd set `Container`'s `pose` prop to either of these poses based the value of `isVisible`:\n\n```javascript\n<Container\n  style={style}\n  pose={this.props.isVisible ? \"visible\" : \"hidden\"}\n>\n  {this.props.text}\n</Container>\n```\n\nNow, back in our editor, the \"Is visible\" toggle control will make our component fade in and out.\n\n## Dynamic pose props\n\nWe can use the Framer UI to affect the actual transition used, too.\n\nRepeating the steps above, add a new `fadeDuration` property to the right-hand inspector. This time, we want it to be a `Number`.\n\nBy cmd-clicking `PropertyControls` again we can see that `NumberControl` has a `max` property available which, if we don't set, the range slider will max out at `100`. So lets change that to something higher like `10000`:\n\n```javascript\nfadeDuration: {\n  type: ControlType.Number,\n  max: 10000,\n  title: \"Fade duration\"\n}\n```\n\nThen make a new fade transition creator:\n\n```javascript\nconst fadeTransition = ({ fadeDuration }) => ({\n  type: 'tween',\n  duration: fadeDuration\n});\n```\n\nAnd apply this to our `visible` and `hidden` poses:\n\n```javascript\nconst Container = posed.div({\n  hoverable: true,\n  init: { scale: 1 },\n  hover: { scale: 1.2 },\n  visible: {\n    opacity: 1,\n    transition: fadeTransition\n  },\n  hidden: {\n    opacity: 0,\n    transition: fadeTransition\n  }\n});\n```\n\nFinally, ensure we're passing the `fadeDuration` prop to `Container`:\n\n```javascript\n<Container\n  style={style}\n  pose={this.props.isVisible ? \"visible\" : \"hidden\"}\n  fadeDuration={this.props.fadeDuration}\n>\n  {this.props.text}\n</Container>\n```\n\nNow, you can change the duration of the transition with the new \"Fade duration\" number slider in the inspector panel. Play with the visibility toggle to check it out!\n\n![Close down that feedback loop!](/guides/framer-x-b.gif)\n\n## Conclusion\n\nThis level of integration is already possible, but in the near future it'd be great to figure out a way of triggering local state/prop changes from other components within the Framer prototype itself.\n\nI'd also like to be able to expose the entire pose API via the Framer UI, as well as figure out `PoseGroup` integration. Framer will be a great tool for closing down the feedback loop when playing around with interactions.\n\nSome of the above may already be possible, and just requires further exploration. [Hit me up](https://twitter.com/popmotionjs) if you have any ideas!\n"
  },
  {
    "path": "packages/popmotion-pose/docs/learn/react/animating-children.md",
    "content": "---\ntitle: Animating children\ndescription: How to orchestrate animations across multiple elements\ncategory: react\nnext: ui-events\n---\n\n> React Pose has been **deprecated** in favour of [Framer Motion](https://framer.com/motion). [Read the upgrade guide](https://www.framer.com/api/motion/migrate-from-pose/)\n\n# Animating children\n\nTraditionally, coordinating animation across multiple children has been an involved process. Especially with React.\n\nWith Pose, it's as simple as animating just one. It looks like this:\n\n```javascript\nconst Parent = posed.ul();\nconst Child = posed.li();\n\n({items}) => (\n  <Parent pose=\"poseName\">\n    {items.map(item => <Child item={item} />)}\n  </Parent>\n)\n```\n\nWhenever a posed component changes `pose`, that change is communicated throughout all of its children posed components via React's context API. So even if they're not direct children, they still update accordingly.\n\nThis makes it super-simple to, for instance, make page-wide [route transitions](/pose/learn/route-transitions-react-router).\n\n<TOC />\n\n## Setup\n\nTo demonstrate animating children, we're going to create this sidebar animation (if the animation has already played, refresh the iframe):\n\n<CodeSandbox id=\"w6m757yj6l\" />\n\nFollow along by forking this [CodeSandbox](https://codesandbox.io/s/0q10o2xlyl).\n\n## Poses\n\nFirst, we need to describe two poses, \"open\" and \"closed\", for both the sidebar and the items within it.\n\nAt the top of your `index.js`, create your posed components:\n\n```javascript\nconst Sidebar = posed.ul({\n  open: { x: '0%' },\n  closed: { x: '-100%' }\n});\n\nconst Item = posed.li({\n  open: { y: 0, opacity: 1 },\n  closed: { y: 20, opacity: 0 }\n});\n```\n\n## Render\n\nIn our `render` function, replace `return null` with our `Sidebar`, setting our `pose` prop to either the `open` or `closed` poses defined above:\n\n```javascript\nreturn (\n  <Sidebar className=\"sidebar\" pose={isOpen ? 'open' : 'closed'} />\n);\n```\n\nNow when the `isOpen` is `true`, our sidebar animates out. All we have to do to also animate the `Item` components is add those as children:\n\n```javascript\nreturn (\n  <Sidebar className=\"sidebar\" pose={isOpen ? 'open' : 'closed'}>\n    <Item className=\"item\" />\n    <Item className=\"item\" />\n    <Item className=\"item\" />\n    <Item className=\"item\" />\n  </Sidebar>\n);\n```\n\nWe only provide `pose` to `Sidebar`, yet `Item` components also animate!\n\n## Scheduling animations\n\nCurrently, our children animations are being fired at the exact same time as the parent. But, often we'd prefer the child animations to be delayed or staggered.\n\nLuckily, we've got properties for that!\n\n### delay\n\nThe `delay` property can be used to delay the animation on the **current** poser, without affecting the execution of child animations.\n\nSo by setting `delay: 300` on the sidebar's `closed` pose, the children will all animate out before the sidebar itself.\n\n```javascript\nconst Sidebar = posed.ul({\n  open: { x: '0%' },\n  closed: { x: '-100%', delay: 300 }\n});\n```\n\n### delayChildren\n\nConversely, the `delayChildren` property can be used to delay all the children animations.\n\nBy setting `delayChildren` on the sidebar's `open` pose, we can animate the sidebar out and **then** animate the children in:\n\n```javascript\nconst Sidebar = posed.ul({\n  open: { x: '0%', delayChildren: 200 },\n  closed: { x: '-100%', delay: 300 }\n});\n```\n\n### staggerChildren\n\nRather than animating all the children in at once, it's possible to stagger them in individually. The `staggerChildren` prop can be used to determine the delay between each one, starting from **after** the `delayChildren` duration:\n\n```javascript\nconst Sidebar = posed.ul({\n  open: {\n    x: '0%',\n    delayChildren: 200,\n    staggerChildren: 50\n  },\n  closed: { x: '-100%', delay: 300 },\n  initialPose: 'closed'\n});\n```\n\n### staggerDirection\n\n`staggerDirection` can be used to determine which order we stagger over the children in. It can either be `1` (first to last, default), or `-1` (last to first).\n\n### beforeChildren/afterChildren\n\nSetting either `beforeChildren` or `afterChildren` props to `true` will make the parent animation play **before** or **after** any children animations."
  },
  {
    "path": "packages/popmotion-pose/docs/learn/react/custom-transitions.md",
    "content": "---\ntitle: Custom transitions\ndescription: How to use Pose for React to define custom transitions\ncategory: react\nnext: dynamic-props\n---\n\n> React Pose has been **deprecated** in favour of [Framer Motion](https://framer.com/motion). [Read the upgrade guide](https://www.framer.com/api/motion/migrate-from-pose/)\n\n# Custom transitions\n\nWith [automatic animations](/pose/learn/get-started), it's easy to create snappy and playful animations just by defining poses.\n\nBut there's plenty of instances where we want full control over our animation. For this, we can use the `transition` property.\n\n<TOC />\n\n## Basic usage\n\nJust like CSS, every pose can have a [`transition` property](/pose/api/react-config/#config-options-poses-transition). This property describes how each value should transition to its new pose:\n\n```javascript\nposed.div({\n  visible: {\n    opacity: 1,\n    transition: { duration: 300 }\n  }\n})\n```\n\nIf we're animating multiple properties, we can **optionally** provide different animations for each by providing a named map.\n\n```javascript\nposed.div({\n  visible: {\n    opacity: 1,\n    scaleY: 1,\n    transition: {\n      opacity: { ease: 'easeOut', duration: 300 },\n      default: { ease: 'linear', duration: 500 }\n    }\n  }\n});\n```\n\n**By default**, if we define a `transition`, it'll be a `tween`. This is an animation between two values over a specific duration of time.\n\nBy providing a `type` property, we can select a different animation to use:\n\n## Transitions\n\nPose ships with five types of animation from [Popmotion Pure](/pure). Tween, spring, decay, keyframes, and physics.\n\n### Tween\n\nA tween animates from one value to another over a set duration of time.\n\n```javascript\ntransition: {\n  duration: 400,\n  ease: 'linear'\n}\n```\n\n#### Easing\n\nThe `ease` property can be used to affect the speed of the tween over the course of its duration.\n\nThis property can be the name of a [Popmotion easing function](/api/easing):\n\n- 'linear'\n- 'easeIn', 'easeOut', 'easeInOut'\n- 'circIn', 'circOut', 'circInOut'\n- 'backIn', 'backOut', 'backInOut'\n- 'anticipate'\n\nOr an array of four numbers to create a cubic bezier easing function:\n\n```javascript\ntransition: {\n  ease: [.01, .64, .99, .56]\n}\n```\n\n[Full `tween` documentation](/api/tween)\n\n### Spring\n\nSpring animations maintain velocity between animations to create visceral, engaging motion.\n\nIt makes them perfect for animations that happen as a result of user interaction.\n\nBy adjusting their `stiffness`, `mass` and `damping` properties, a wide-variety of spring feels can be created.\n\n```javascript\ntransition: { type: 'spring', stiffness: 100 }\n```\n\n[Full `spring` documentation](/api/spring)\n\n### Decay\n\nDecay reduces the velocity of an animation over a duration of time.\n\nIt's a perfect match for the special `dragEnd` pose that fires when a user stops [dragging](/pose/learn/ui-events) something, as it can replicate the momentum-scrolling common on smart phones.\n\nThe end value is automatically calculated by Pose at the start of the animation, but with the `modifyTarget` prop, you can adjust this, allowing you to do things like snap to a grid.\n\n```javascript\ntransition: {\n  type: 'decay',\n  modifyTarget: v => Math.ceil(v / 100) * 100 // Snap to nearest 100px\n}\n```\n\n[Full `decay` documentation](/api/decay)\n\n### Keyframes\n\nKeyframes allows you to schedule a series of values to tween between.\n\n```javascript\ntransition: ({ from, to }) => ({\n  type: 'keyframes',\n  values: [from, 100, to],\n  times: [0, 0.25, 1]\n})\n```\n\n[Full `keyframes` documentation](/api/keyframes)\n\n### Physics\n\nPhysics allows you to simulate things like velocity, friction, and acceleration.\n\n```javascript\ntransition: {\n  type: 'physics',\n  velocity: 1000\n}\n```\n\n[Full `physics` documentation](/api/physics)\n\n## Transition props\n\nThere are a number of other properties that can be used with any transition:\n\n### Delay\n\nIf set, will delay the execution of the transition by the specified amount: \n\n```javascript\ntransition: {\n  type: 'physics',\n  delay: 400\n}\n```\n\n### Min/Max\n\nIf set, will ensure values are capped to no less than `min` and no more than `max`.\n\n```javascript\ntransition: {\n  type: 'keyframes',\n  values: [0, 3, 10],\n  min: 2,\n  max: 9\n}\n```\n\n### Round\n\nIf set to `true`, `round` will ensure that values output from the animation will be rounded.\n\n```javascript\ntransition: {\n  type: 'spring',\n  round: true\n}\n```\n"
  },
  {
    "path": "packages/popmotion-pose/docs/learn/react/dynamic-props.md",
    "content": "---\ntitle: Dynamic props\ndescription: Set props as dynamic functions\ncategory: react\nnext: animating-children\n---\n\n> React Pose has been **deprecated** in favour of [Framer Motion](https://framer.com/motion). [Read the upgrade guide](https://www.framer.com/api/motion/migrate-from-pose/)\n\n# Dynamic pose props\n\nEach pose property can be set as a function that resolves when the pose is entered:\n\n```javascript\nconst Box = posed.div({\n  visible: {\n    x: 0,\n    y: (props) => 100, // Resolved on `visible` enter\n    transition: {\n      x: { type: 'tween' },\n      y: (props) => ({ type: 'spring' }) // Resolved on `visible` enter\n    }\n  }\n})\n```\n\nBy using the provided `props` argument, this allows us to create dynamic properties that will react to changes in your app.\n\n<TOC />\n\n## Props\n\nSo what are props? They're just component props! Any props you provide to your posed component will be forwarded to these dynamic pose props.\n\nFor instance, you could use a component's `i` index prop to write a dynamic `delay` prop:\n\n```javascript\nconst Item = posed.li({\n  visible: {\n    opacity: 1,\n    transition: ({ i }) => ({ delay: i * 50 })\n  },\n  props: { i: 0 }\n});\n\nexport default ({ i, isVisible }) =>\n  <Item pose={isVisible ? 'hidden' : 'visible'} i={i} />\n```\n\n<CodePen id=\"jzXzdz\" height=\"400\" />\n\n## Transition props\n\n`transition` works a little differently than other pose props.\n\nIf set as a function, the function is run **once each for every property being animated**.\n\nThat function is provided a few extra props, automatically generated by Pose:\n\n- `from`: The current state of this value\n- `to`: The target state defined in the pose\n- `velocity`: If a numerical value, the current velocity of the value\n- `key`: The name of the current value\n- `prevPoseKey`: The name of the pose this value was previously set to\n\nThese props can be used to return a different transition definition based on the state of the value:\n\n```javascript\nconst Sidebar = posed.div({\n  open: {\n    x: '-100%',\n    transition: ({ velocity, to }) => velocity < 0\n      ? { to: 0 }\n      : { to }\n  }\n});\n```\n\nIf `transition` is a named map, **some or all** of these can be defined as functions:\n\n```javascript\nconst Sidebar = posed.div({\n  open: {\n    x: 0,\n    opacity: 1,\n    transition: {\n      x: ({ velocity, to }) => velocity < 0 ? { to: -300 } : { to },\n      opacity: { type: 'spring' }\n    }\n  }\n});\n```\n"
  },
  {
    "path": "packages/popmotion-pose/docs/learn/react/flip.md",
    "content": "---\ntitle: FLIP\ndescription: A look at Pose's powerful FLIP API\ncategory: react\n---\n\n> React Pose has been **deprecated** in favour of [Framer Motion](https://framer.com/motion). [Read the upgrade guide](https://www.framer.com/api/motion/migrate-from-pose/)\n\n# FLIP\n\nThe FLIP technique, [fully explained here](https://aerotwist.com/blog/flip-your-animations/), is a way of animating expensive, layout-breaking animations like `width` and `top` by using quick transforms.\n\nPose provides a couple of methods for performing FLIP:\n\n1. Animate `width`/`top`/etc and adding `flip: true` to a pose\n2. Via the [`PoseGroup` component](/pose/api/posegroup)\n\nIn this tutorial, we'll take a look at each of these.\n\n<TOC />\n\n## width/top\n\nThe problem with animating size and position properties is that they break layout. Recalculating layout is expensive, which can slow animations to below 60fps.\n\nSo, when you set a pose with `flip: true` and any of `width`, `height`, `top`, `left`, `right`, or `bottom` values, these will applied at the start of the animation. Pose will measure the size and position of the element before and after, and animate from one to the other using transform properties instead.\n\nFor instance, we can switch a `div` to fullscreen and back using the following config:\n\n```javascript\nconst Panel = posed.div({\n  fullscreen: {\n    width: '100vw',\n    height: '100vh',\n    transition: tween,\n    flip: true\n  },\n  thumbnail: {\n    width: 100,\n    height: 100,\n    transition: tween,\n    flip: true\n  }\n});\n```\n\n<CodePen id=\"BrmGmR\" />\n\n## PoseGroup\n\nReact Pose includes a [component called `PoseGroup`](/pose/api/posegroup).\n\nWhen wrapping a group of posed components, it enables two things:\n\n1. `enter`/`exit` poses\n2. FLIP-powered re-ordering\n\nWhen an item enters or exits the group, or changes position in it, all the other items automatically measure their position before the change and then FLIP into to the new position:\n\n<CodePen id=\"eMexyR\" />\n\nThis all happens automatically. Open [this CodePen template](https://codepen.io/popmotion/pen/mxqobd?editors=0010)\n\nAt the top of the JS, create a new posed component, a list item:\n\n```javascript\nconst Item = posed.li()\n```\n\nNow, replace `null` in the render function of `Example` with:\n\n```javascript\n(\n  <ul className=\"sidepanel\">\n    <PoseGroup>\n      {this.state.items.map(item => (\n        <Item className=\"item\" data-key={item} key={item} />\n      ))}\n    </PoseGroup>\n  </ul>\n);\n```\n\nThis component is pre-set to shuffle the items every two seconds. Notice how, without even defining any animations, all the items automatically animate to their new home.\n\nPlus, the `flip` pose is enabled. So we can define the animation they use to move position by changing `Item` to:\n\n```javascript\nconst { tween } = popmotion\n\nconst Item = posed.li({\n  flip: {\n    transition: tween\n  }\n})\n```\n"
  },
  {
    "path": "packages/popmotion-pose/docs/learn/react/install.md",
    "content": "---\ntitle: Install\ndescription: Overview of Pose's installation options.\ncategory: react\nnext: popmotion-get-started\n---\n\n> React Pose has been **deprecated** in favour of [Framer Motion](https://framer.com/motion). [Read the upgrade guide](https://www.framer.com/api/motion/migrate-from-pose/)\n\n# Install\n\n**React Pose requires React 16.3.0.**\n\n<TOC />\n\n## Package managers (recommended)\n\n### npm\n\n```bash\nnpm install react-pose --save\n```\n\n### yarn\n\n```bash\nyarn add react-pose\n```\n\n## File include\n\n**Note:** The Pose documentation uses the `import` syntax for importing individual modules.\n\n**If you use one of the following installation methods, top-level React Pose exports will be available as the global `posed` and `PoseGroup` variables.**\n\nSo, when you see in the docs `import posed, { PoseGroup } from 'react-pose'`, you can instead simply use the global `posed` and `PoseGroup` variables.\n\n### Download\n\nYou can download the latest version of Pose at https://unpkg.com/react-pose/dist/react-pose.js\n\n### Script include\n\nYou can include it in your HTML with this `script` tag:\n\n```\n<script src=\"https://unpkg.com/react-pose/dist/react-pose.js\"></script>\n```\n\n## CodePen\n\nYou can fork the [React Pose playground on CodePen](https://codepen.io/popmotion/pen/mxmrPZ?editors=0010), which is set up with the latest version of React Pose.\n\nYou an also add React Pose to any existing CodePen project by clicking on Settings > JavaScript and then pasting `https://unpkg.com/react-pose/dist/react-pose.js` into the \"Add External JavaScript\" field.\n"
  },
  {
    "path": "packages/popmotion-pose/docs/learn/react/passive.md",
    "content": "---\ntitle: Passive values\ndescription: Learn how to create passive values that only change when others do\ncategory: react\nnext: flip\n---\n\n> React Pose has been **deprecated** in favour of [Framer Motion](https://framer.com/motion). [Read the upgrade guide](https://www.framer.com/api/motion/migrate-from-pose/)\n\n# Passive values\n\nSometimes we don't want to explicitly define a state for a value, we might just want it to change whenever another value does.\n\nFor instance, we might want an element to disappear as it moves beyond certain boundaries:\n\n<CodePen id=\"LdOJZR\" />\n\nFor this, we can use **passive values**. In this tutorial we'll see how to define them, and how to make them respond to changes in parent values too.\n\n<TOC />\n\n## Defining a passive value\n\nOpen the [this draggable example](https://codepen.io/popmotion/pen/dmWWdp?editors=0010) and replace the posed component config with this:\n\n```javascript\nconst Box = posed.div({\n  draggable: 'x'\n});\n```\n\nThe dragging motion of the element is locked to the `x` axis. We can actually lock movement to the diagonal by defining `y` as a `passive` value.\n\nPassive values are defined a tuples, like this:\n\n```javascript\nconst Box = posed.div({\n  draggable: 'x',\n  passive: {\n    y: ['x', v => v]\n  }\n});\n```\n\nThe first item in the tuple is the name of the value we want to link to. In this case, that's `'x'`.\n\nThe second item is a mapping function. This takes the output of the linked value and returns our passive value. In this example, we're simply returning `x`, and creating this motion:\n\n<CodePen id=\"QmvmOe\" />\n\nBy using this mapping function we can start creating new effects. For instance, returning the negative of `x` creates diagonal movement in the opposite direction:\n\n```javascript\ny: ['x', v => -v]\n```\n\nOr by using `Math.sin` we can make wavey behaviour:\n\n```javascript\ny: ['x', v => v * Math.sin(v * 0.01)]\n```\n\n## Changing non-numerical values\n\nSo far, we've mapped two pixel values. But we can set any kind of value with any other.\n\nLong-time users of Popmotion will recognise the signature of the mapping function. It accepts one value, and returns another. Which means we can compose this function using [Popmotion's transformers](/api/transformers).\n\nFor instance, instead of `y` let's create a function that will map `x` to `backgroundColor`.\n\nFor this we'll need to import four functions from `popmotion.transform`:\n\n```javascript\nconst { pipe, clamp, interpolate, blendColor } = popmotion.transform\n```\n\nOur steps will be:\n\n1) Convert the output of `x` from pixels to a `0` to `1` range\n2) Clamp that output to within `0` and `1`\n3) Use that progress number to blend between two colors\n\nWhich means our function will look like this:\n\n```javascript\nbackgroundColor: ['x', pipe(\n  interpolate([-200, 200], [0, 1]),\n  clamp(0, 1),\n  blendColor('#FF1C68', '#09f')\n)]\n```\n\n<CodePen id=\"vRmRvV\" />\n\n## Linking to ancestors\n\nWe can also link a passive value to a value in one of the poser's ancestors.\n\nLet's revist our [sidebar example](https://codepen.io/popmotion/pen/LdybdN?editors=0010) from earlier.\n\nCurrently, we're actively animating the children by setting poses on both the parent and the children.\n\nBut, it's possible to change the opacity of the items as the `x` of their sidebar parent changes.\n\nTo do this, we pass `true` as the third and final argument of the tuple.\n\nAdd a slower `transition` to `sidebarConfig.open` to help us see this in effect.\n\n```javascript\ntransition: (props) => tween({  ...props, duration: 1000 })\n```\n\nNow, replace `itemConfig` with this:\n\n```javascript\nconst Box = posed.li({\n  passive: {\n    opacity: ['x', pipe(\n      parseFloat,\n      interpolate([-100, 0], [0, 1])\n    ), true]\n  }\n});\n```\n\nAs you can see, we're passing in a third parameter to the passive tuple, `true`. This says \"listen to the `x` value, but do so on my immediate parent\".\n\n<CodePen id=\"GxOXeX\" />\n\n### Distant ancestors\n\nUsing `true` is fine if we want to look just one part up the ancestor chain. But it's also possible to go much further up using `label`.\n\nBy explicitly naming our posers with a `label`, we can refer to any poser in the ancestor chain.\n\nAdd the label `'sidebar'` to our `sidebarConfig`:\n\n```javascript\nconst Sidebar = posed.ul({\n  label: 'sidebar',\n  /* other props */\n});\n```\n\nNow replace `true` in `itemConfig` with `'sidebar'`. It still works, and it will still work if you decide to put a poser between sidebar and items.\n"
  },
  {
    "path": "packages/popmotion-pose/docs/learn/react/popmotion-get-started.md",
    "content": "---\ntitle: Get started\ndescription: Introduction to Pose for React's declarative animation interface\ncategory: react\nnext: custom-transitions\n---\n\n> React Pose has been **deprecated** in favour of [Framer Motion](https://framer.com/motion). [Read the upgrade guide](https://www.framer.com/api/motion/migrate-from-pose/)\n\n# Get started\n\nPose is a declarative motion system that combines the simplicity of CSS transitions with the power and flexibility of JavaScript.\n\nIn this series of tutorials, we'll learn how to use Pose for React DOM. We'll gradually introduce each of its features, starting with this simple `opacity` animation:\n\n<CodeSandbox id=\"w71ppx095\" view=\"preview\" />\n\n<TOC />\n\n## Setup\n\nThe easiest way to play around with Pose is to [fork this CodeSandbox playground](https://codesandbox.io/s/qz0zyqwnqq).\n\nFor local development, all installation options can be found on the [install](/pose/learn/install) page.\n\n## The \"Hello World\" animation\n\nIn Pose for React, we create animated components by importing `posed` from `react-pose`:\n\n```javascript\nimport posed from 'react-pose';\n```\n\n`posed` can create animated versions of any HTML or SVG element. Use it to create a `div`:\n\n```javascript\nconst Box = posed.div();\n```\n\nChange the `render` function to return an instance of `Box` instead of `div`:\n\n```javascript\nreturn <Box className=\"box\" />;\n```\n\nWith Pose, we define possible states, or **poses**, that the `Box` can be in. It looks a lot like CSS:\n\n```javascript\nconst Box = posed.div({\n  visible: { opacity: 1 },\n  hidden: { opacity: 0 }\n});\n```\n\nNow to animate `Box` between its `visible` and `hidden` poses, we just pass it a `pose` prop:\n\n```javascript\nreturn (\n  <Box\n    className=\"box\"\n    pose={this.state.isVisible ? 'visible' : 'hidden'}\n  />\n);\n```\n\nThe box is now animating between the two poses!\n\n## But wait, where did we define the animation?\n\nShort answer: we didn't.\n\nMore helpful answer: By default, Pose **doesn't require you to explicitly define the animations** used to transition between two states.\n\nInstead, it automatically creates an animation based on the properties being animated.\n\nThese animations have been designed to create snappy and playful interfaces. Physical motion uses `spring` to maintain velocity between animations, whereas properties like `opacity` use a `tween`.\n\nHowever, there will always be situations where we want greater control. For that, we can define [custom transitions](/pose/learn/custom-transitions)."
  },
  {
    "path": "packages/popmotion-pose/docs/learn/react/react-exit-enter-transitions.md",
    "content": "---\ntitle: Enter/exit transitions\ndescription: Learn how to animate React components as they mount and unmount with Pose for React's PoseGroup component\ncategory: react\nnext: passive\n---\n\n> React Pose has been **deprecated** in favour of [Framer Motion](https://framer.com/motion). [Read the upgrade guide](https://www.framer.com/api/motion/migrate-from-pose/)\n\n# Enter/exit transitions\n\nAnimating components when they unmount has been historically tricky with React.\n\n[Pose for React's `PoseGroup` component](/pose/api/posegroup) makes it trivial to animate one or more children components as they enter and exit.\n\nIn this tutorial, we'll see how it can be used to make this modal animation:\n\n<CodeSandbox id=\"lx6k64453l\" />\n\n<TOC />\n\n## Setup\n\nTo start, fork [this CodeSandbox](https://codesandbox.io/s/842823w17j).\n\nIt's set up with a `setInterval` that switches the visibility of two components, the modal, and its background overlay.\n\n```javascript\nrender() {\n  return (\n    this.state.isVisible && [\n      <div key=\"shade\" className=\"shade\" />,\n      <div key=\"modal\" className=\"modal\" />\n    ]\n  );\n}\n```\n\nCurrently, both components snap in and out, so let's make them smoothly animate instead!\n\n## Import Pose for React\n\nFirst, we need to import Pose for React. This time, we're going to be importing both `posed` and the `PoseGroup` component:\n\n```javascript\nimport posed, { PoseGroup } from 'react-pose';\n```\n\n## Add PoseGroup\n\nTo start triggering animations when components enter and exit, we need to wrap them in `PoseGroup`.\n\n`PoseGroup` needs to stay rendered at all times, and its children can be added and removed via logic. So wrap our `isVisible` check like so:\n\n```javascript\nreturn (\n  <PoseGroup>\n    {this.state.isVisible && [\n      <div key=\"shade\" className=\"shade\" />,\n      <div key=\"modal\" className=\"modal\" />\n    ]}\n  </PoseGroup>\n);\n```\n\n## Create posed components\n\nAs the `shade` and `modal` children are currently plain `div` components, they won't animate. We need to replace them with posed components.\n\nAfter the block of imports, add:\n\n```javascript\nconst Modal = posed.div();\nconst Shade = posed.div();\n```\n\nThen replace the two `div`s with our new components:\n\n```javascript\n<Shade key=\"shade\" className=\"shade\" />,\n<Modal key=\"modal\" className=\"modal\" />\n```\n\n## Animate!\n\nBy default, `PoseGroup` will fire a component's `enter` pose when they enter (transitioning from its `exit` pose), and `exit` when they exit.\n\nSo let's give our new `Shade` and `Modal` components `enter` and `exit` poses:\n\n```javascript\nconst Modal = posed.div({\n  enter: { y: 0, opacity: 1 },\n  exit: { y: 50, opacity: 0 }\n});\n\nconst Shade = posed.div({\n  enter: { opacity: 1 },\n  exit: { opacity: 0 }\n});\n```\n\nNow, your modal and its shade will animate in and out!\n\nAs usual you can play around with these poses to tweak the animation. For instance you can add a `delay` to `Modal`'s `enter` pose to make it animate in a little after the `Shade`. Or provide it a custom `transition` to `exit` faster:\n\n```javascript\nconst Modal = posed.div({\n  enter: { y: 0, opacity: 1, delay: 300 },\n  exit: {\n    y: 50,\n    opacity: 0,\n    transition: { duration: 200 }\n  }\n});\n```\n"
  },
  {
    "path": "packages/popmotion-pose/docs/learn/react/react-tutorial-medium-style-image-zoom.md",
    "content": "---\ntitle: \"Tutorial: Medium-style image zoom\"\ndescription: How to make Medium-style image zooming with Pose for React\ncategory: react\n---\n\n> React Pose has been **deprecated** in favour of [Framer Motion](https://framer.com/motion). [Read the upgrade guide](https://www.framer.com/api/motion/migrate-from-pose/)\n\n# Tutorial: Medium-style image zoom\n\n[Medium](https://medium.com) have an beautiful zoom effect on their images. When clicked, they pop out of the page as a white background fades in behind them. Then, if clicked again, or if a user scrolls away, they pop back into place.\n\nTake a look:\n\n<iframe width=\"600\" height=\"400\" src=\"https://www.youtube.com/embed/Y2gd1ILCoYA\" frameborder=\"0\" allow=\"autoplay; encrypted-media\" allowfullscreen></iframe>\n\nIn this tutorial, we'll learn how to achieve this same effect using Pose for React.\n\n<TOC />\n\n## Setup\n\nTo get started, fork this [CodeSandbox template](https://codesandbox.io/s/y2k00vx22x).\n\nIt contains a mock article that contains a couple of images. These are being rendered via the component we're going to work on, `ZoomImage`.\n\nOpen `components/ZoomImage.js`, and let's get started!\n\n## State\n\nFirst, we need to create `state` so we know whether the image is zoomed or not. At the top of the `ZoomImage` class, add the following:\n\n```javascript\nstate = { isZoomed: false };\n```\n\nOf course, this state is useless on its own. We're going to need a couple of functions to set the zoom status. On the next line, add the following `zoomIn` and `zoomOut` methods:\n\n```javascript\nzoomIn() {\n  this.setState({ isZoomed: true });\n}\n\nzoomOut() {\n  this.setState({ isZoomed: false });\n}\n```\n\nFinally, we want to toggle the zoomed state when someone clicks the image container (as this will also later contain the white background):\n\n```javascript\n<div\n  class=\"image-frame\"\n  onClick={() => this.state.isZoomed ? this.zoomOut() : this.zoomIn()}\n  style={{ width: imageWidth, height: imageHeight }}\n>\n```\n\nNow, when the image is clicked, the component will change zoom status. But we're not responding to this in our `render` function. Let's make some animations!\n\n## Image zoom animation\n\nWhen the image zooms in, it needs to animate from its place in the document, smoothly into the center of the screen. To do this, we're going to use Pose's FLIP capabilities.\n\nYou can read the gritty details about FLIP in this [blog post by Paul Lewis](https://aerotwist.com/blog/flip-your-animations/). In essence, it's a way of *performantly* animating between two states that would otherwise be expensive, for instance where `position`, `top`, `width`, or other layout-changing properties have changed.\n\nIn Pose, you simply have to add `flip: true` to a pose, and it'll automatically perform the usually complicated steps to perform this animation.\n\nImport Pose for React:\n\n```javascript\nimport posed from 'react-pose';\n```\n\nNow make a posed `img` component:\n\n```javascript\nconst Image = posed.img();\n```\n\nWe're going to provide the component two poses, one for each zoom state: `zoomedIn` and `zoomedOut`.\n\nOur `zoomedIn` pose is going to set `position: fixed` and every positional prop to `0`. This will pop the content out of the layout and lock it to the viewport.\n\nIn our `styles.css` file, `img` has a style of `margin: auto` which centers the image when it's being stretched across the screen in this way.\n\n```javascript\nconst Image = posed.img({\n  zoomedIn: {\n    position: 'fixed',\n    top: 0,\n    left: 0,\n    bottom: 0,\n    right: 0,\n    flip: true\n  }\n});\n```\n\n`zoomedOut` sets `position: static` to pop it back into the DOM, as well as setting `width` and `height` to `auto` to make it fill its layout container:\n\n```javascript\nconst Image = posed.img({\n  zoomedIn: {\n    position: 'fixed',\n    top: 0,\n    left: 0,\n    bottom: 0,\n    right: 0,\n    flip: true\n  },\n  zoomedOut: {\n    position: 'static',\n    width: 'auto',\n    height: 'auto',\n    flip: true\n  }\n});\n```\n\nWe've now got our posed `img` component fully configured. Replace the `img` component in the `render` function with it:\n\n```javascript\n<Image {...props} />\n```\n\nTo animate `Image` between the two poses, we need to provide it a `pose` property.\n\nAt the top of the `render` function, set our `pose`:\n\n```javascript\nconst { isZoomed } = this.state;\nconst pose = isZoomed ? 'zoomedIn' : 'zoomedOut';\n```\n\nAnd provide it to `Image`:\n\n```javascript\n<Image pose={pose} {...props} />\n```\n\nNow, when we click our image, it zooms in and out!\n\nI find the automatically generated animation a little bouncy for this purpose. We can define a new `transition` with a `ease` curve generated at [Lea Verou's cubic bezier generator](http://cubic-bezier.com/#.08,.69,.2,.99).\n\n```javascript\nconst transition = {\n  duration: 400,\n  ease: [0.08, 0.69, 0.2, 0.99]\n};\n```\n\nProvide this as a `transition` prop to both poses, and the animation becomes a little slicker.\n\n## Background animation\n\nThat's the (usually) difficult bit out of the way. It's looking pretty good but the Medium example fades a background in behind the image as it zooms in and out.\n\nMake a new posed component called `Frame`:\n\n```javascript\nconst Frame = posed.div();\n```\n\nIn our `styles.css` add a new rule for `.frame`. We're going to make the background of this frame white, and set `translateZ(0)` to ensure its fade animation is hardware-accelerated:\n\n```css\n.frame {\n  position: fixed;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  display: none;\n  background: white;\n  transform: translateZ(0);\n}\n```\n\nAnd now add `Frame` as a sibling of `Image`, also passing it the `pose` prop:\n\n```javascript\n<Frame pose={pose} class=\"frame\" />\n<Image pose={pose} {...props} />\n```\n\nNow we can animate it! We just want to fade the overlay in and out, so first add those poses:\n\n```javascript\nconst Frame = posed.div({\n  zoomedIn: { opacity: 1 },\n  zoomedOut: { opacity: 0 }\n});\n```\n\nBy itself this won't do anything, as we've got `display` set to `none` in the CSS.\n\nFor this we can use the `applyAtStart` and `applyAtEnd` props. They allow you to define styles to set at the start and at the end of the pose transition, respectively.\n\n```javascript\nconst Frame = posed.div({\n  zoomedIn: {\n    applyAtStart: { display: 'block' },\n    opacity: 1\n  },\n  zoomedOut: {\n    applyAtEnd: { display: 'none' },\n    opacity: 0\n  }\n});\n```\n\nNow your background will fade in and out behind the image as it zooms in!\n\n## Scroll to zoom out\n\nThe original Medium image zoom has a nice feature where if a user starts scrolling, the image zooms out back into its original place.\n\nWe can accomplish the same thing by adding a `'scroll'` event listener to `zoomIn`:\n\n```javascript\nzoomIn() {\n  window.addEventListener('scroll', this.zoomOut);\n  this.setState({ isZoomed: true });\n}\n```\n\nBy itself, this isn't going to work. When `this.zoomOut` is called, it'll be in the execution context of the event caller rather than our React component. We can bind `zoomOut` to our component by changing it to an arrow function:\n\n```javascript\nzoomOut = () => {\n  this.setState({ isZoomed: false });\n};\n```\n\nFinally, we need to remove the event listener when a user does zoom out:\n\n```javascript\nzoomOut = () => {\n  window.removeEventListener('scroll', this.zoomOut);\n  this.setState({ isZoomed: false });\n};\n```\n\n## Conclusion\n\nHere's our finished example:\n\n<CodeSandbox height=\"700\" id=\"rrjx477w3n\" />\n\nThere's plenty of fun things you can do to improve accessibility and aesthetics.\n\nHave a think about:\n\n- Closing the image via the `esc` key\n- Changing the background animation. You could even incorporate SVGs.\n- Adding a \"scroll delay\" where a user has to scroll a minimum distance before we close the image.\n- Changing the cursor to show a zoom in or zoom out icon."
  },
  {
    "path": "packages/popmotion-pose/docs/learn/react/route-transitions-reach-router.md",
    "content": "---\ntitle: \"Tutorial: Reach Router\"\ndescription: How to make route transition animations with React Pose and Reach Router\ncategory: react\n---\n\n> React Pose has been **deprecated** in favour of [Framer Motion](https://framer.com/motion). [Read the upgrade guide](https://www.framer.com/api/motion/migrate-from-pose/)\n\n# Route transitions with Reach Router\n\n> **Note:** This tutorial is for **Reach** Router. Users of **React** Router will want to use the [React Router tutorial](/pose/learn/route-transitions-react-router).\n\nRoute transitions in React are notoriously fiddly. With [Pose](/pose) and the accessibility-first [Reach Router](https://reach.tech/router), they can be pretty simple.\n\nWe're going first learn how to make a simple fade transition between two routes.\n\nThen, as Pose has the ability to coordinate animations throughout the component tree, we'll show how to animate each route differently, with content staggering in and out.\n\nHere's what we'll be making:\n\n<CodeSandbox height=\"600\" id=\"mzx1jz521p\" />\n\n<TOC />\n\n## Sandbox\n\nWe've created a [CodeSandbox](https://codesandbox.io/s/mzx1jz521p) example preloaded with React Pose and Reach Router, for you to fork and follow along.\n\nIt's set up in a standard way according to the [Reach Router docs](https://reach.tech/router), so if you're not already familiar with Reach Router, it's worth reading the overview there.\n\n## Fade transition\n\nSo, let's animate! The first animation we'll add is a simple fade transition. When a user clicks a link, we want to fade the existing content out, and the new content in.\n\nWe'll start by importing React Pose. We're going to be using both `posed` and `PoseGroup`. So at the end of your imports, add:\n\n```javascript\nimport posed, { PoseGroup } from 'react-pose';\n```\n\nNow, let's create a posed component with our two visual states, `enter` and `exit`. After the line above, add:\n\n```javascript\nconst RoutesContainer = posed.div({\n  enter: { opacity: 1 },\n  exit: { opacity: 0 }\n});\n```\n\nWe can now use this to wrap our `Router` component:\n\n```javascript\n{({ location }) => (\n  <RoutesContainer>\n    <Router location={location}>\n      {children}\n    </Router>\n  </RoutesContainer>\n)}\n```\n\nTo animate this component between the two `enter` and `exit` states, we can use the `PoseGroup` component.\n\n`PoseGroup` tracks the entering and exiting of child components (as well as reordering), and will animate them in an out. Any components exiting will only be physically removed from the tree once they've finished their `exit` animation.\n\n```javascript\n{({ location }) => (\n  <PoseGroup>\n    <RoutesContainer>\n      <Router location={location}>\n        {children}\n      </Router>\n    </RoutesContainer>\n  </PoseGroup>\n)}\n```\n\nAh, but wait! If you try and click between pages, there's still no animation. What's up?\n\nWithout passing `RoutesContainer` a `key`, `PoseGroup` doesn't know that it has a new child, so it can't animate anything. Let's use Reach Router's `location.key` prop as our key:\n\n```javascript\n<RoutesContainer key={location.key}>\n```\n\nNow, when you change routes, the content will fade in and out!\n\nThe two pieces of content currently fade on top of each other. By adding a small delay to the `enter` state, we can optionally separate the animations:\n\n```javascript\nconst RoutesContainer = posed.div({\n  enter: { opacity: 1, delay: 300 },\n  exit: { opacity: 0 }\n});\n```\n\n## Content transitions\n\nWith that animation in place, we can go a step further and animate the entering and exiting content.\n\nFirst, add a `beforeChildren: true` property to the `RoutesContainer` `enter` pose. This will ensure that it finishes fading in before we animate any of its children:\n\n```javascript\nconst RoutesContainer = posed.div({\n  enter: {\n    opacity: 1,\n    delay: 300,\n    beforeChildren: true\n  },\n  exit: { opacity: 0 }\n});\n```\n\nLet's animate our first page. Open `pages/about.js`. You'll see that we've pre-made two posed components, `Container` and `P`, and used those to markup the `About` component.\n\nIn the markup, the `P` components are children of `Container`, and `Container` is a child of `RoutesContainer`. So when `RoutesContainer` changes to `enter` and `exit` poses, these will flow through each of the posed components in turn, allowing us to animate them.\n\nAdd `enter` and `exit` poses to `P`:\n\n```javascript\nconst P = posed.p({\n  enter: { x: 0, opacity: 1 },\n  exit: { x: 50, opacity: 0 }\n});\n```\n\nNow, when you enter and exit the `About` page, all the paragraphs will animate in and out. But they all animate in together. It'd be nice to stagger these animations instead.\n\nThat's why we've made `Container` a posed component too. It's not going to do animation itself, it's just going to control the animation of its children with the `staggerChildren` property:\n\n```javascript\nconst Container = posed.div({\n  enter: { staggerChildren: 50 }\n});\n```\n\nTry entering and exiting the `About` page again. The paragraphs stagger in.\n\nWe can try the same trick on the `Home` page. Open `pages/home.js` and replace the `ListContainer` and `Item` posed components with this:\n\n```javascript\nconst ListContainer = posed.ul({\n  enter: { staggerChildren: 50 },\n  exit: { staggerChildren: 20, staggerDirection: -1 }\n});\n\nconst Item = posed.li({\n  enter: { y: 0, opacity: 1 },\n  exit: { y: 50, opacity: 0 }\n});\n```\n\nThis time, `ListContainer`'s `exit` pose has a new property, `staggerDirection`. Setting this to `-1` reverses the stagger, so elements animate out from the bottom up.\n\n## Conclusion\n\nWe've learned how to use Pose with Reach Router to do a quick and simple fade transition, as well as animating across children to provide unique effects for every page.\n\nWe've also seen how posed components can be used not only to animate, but to sequence the animations of their children.\n"
  },
  {
    "path": "packages/popmotion-pose/docs/learn/react/route-transitions-react-router.md",
    "content": "---\ntitle: \"Tutorial: React Router 4\"\ndescription: How to make route transition animations with React Pose and React Router\ncategory: react\n---\n\n> React Pose has been **deprecated** in favour of [Framer Motion](https://framer.com/motion). [Read the upgrade guide](https://www.framer.com/api/motion/migrate-from-pose/)\n\n# Route transitions with React Router\n\n> **Note:** This tutorial is for **React** Router. Users of **Reach** Router will want to use the [Reach Router tutorial](/pose/learn/route-transitions-reach-router).\n\nRoute transitions in React are notoriously fiddly. With [Pose](/pose) and [React Router](https://reacttraining.com/react-router/), they can be pretty simple.\n\nWe're going first learn how to make a simple fade transition between two routes.\n\nThen, as Pose has the ability to coordinate animations throughout the component tree, we'll show how to animate each route differently, with content staggering in and out.\n\nHere's what we'll be making:\n\n<CodeSandbox height=\"600\" id=\"wq324qk687\" />\n\n<TOC />\n\n## Sandbox\n\nWe've created a [CodeSandbox](https://codesandbox.io/s/m3z4pm0myx) example preloaded with React Pose and React Router, for you to fork and follow along.\n\nIt's set up in a standard way according to the [React Router docs](https://reacttraining.com/react-router/web/guides/philosophy), so if you're not already familiar with React Router, it's worth reading the overview there.\n\n## Fade transition\n\nSo, let's animate! The first animation we'll add is a simple fade transition. When a user clicks a link, we want to fade the existing content out, and the new content in.\n\nWe'll start by importing React Pose. We're going to be using both `posed` and `PoseGroup`. So at the end of your imports, add:\n\n```javascript\nimport posed, { PoseGroup } from 'react-pose';\n```\n\nNow, let's create a posed component with our two visual states, `enter` and `exit`. After the line above, add:\n\n```javascript\nconst RoutesContainer = posed.div({\n  enter: { opacity: 1 },\n  exit: { opacity: 0 }\n});\n```\n\nWe can now use this to wrap our `Switch` component:\n\n```javascript\n<RoutesContainer>\n  <Switch location={location}>\n    {/* ...routes */}\n  </Switch>\n</RoutesContainer>\n```\n\nTo animate this component between the two `enter` and `exit` states, we can use the `PoseGroup` component.\n\n`PoseGroup` tracks the entering and exiting of child components (as well as reordering), and will animate them in an out. Any components exiting will only be physically removed from the tree once they've finished their `exit` animation.\n\n```javascript\n<PoseGroup>\n  <RoutesContainer>\n    <Switch location={location}>\n      {/* ...routes */}\n    </Switch>\n  </RoutesContainer>\n</PoseGroup>\n```\n\nAh, but wait! If you try and click between pages, there's still no animation. What's up?\n\nWithout passing `RoutesContainer` a `key`, `PoseGroup` doesn't know that it has a new child, so it can't animate anything. Let's use React Router's `location.key` prop as our key:\n\n```javascript\n<RoutesContainer key={location.key}>\n```\n\nNow, when you change routes, the content will fade in and out!\n\nThe two pieces of content currently fade on top of each other. By adding a small delay to the `enter` state, we can optionally separate the animations:\n\n```javascript\nconst RoutesContainer = posed.div({\n  enter: { opacity: 1, delay: 300 },\n  exit: { opacity: 0 }\n});\n```\n\n## Content transitions\n\nWith that animation in place, we can go a step further and animate the entering and exiting content.\n\nFirst, add a `beforeChildren: true` property to the `RoutesContainer` `enter` pose. This will ensure that it finishes fading in before we animate any of its children:\n\n```javascript\nconst RoutesContainer = posed.div({\n  enter: {\n    opacity: 1,\n    delay: 300,\n    beforeChildren: true\n  },\n  exit: { opacity: 0 }\n});\n```\n\nLet's animate our first page. Open `pages/about.js`. You'll see that we've pre-made two posed components, `Container` and `P`, and used those to markup the `About` component.\n\nIn the markup, the `P` components are children of `Container`, and `Container` is a child of `RoutesContainer`. So when `RoutesContainer` changes to `enter` and `exit` poses, these will flow through each of the posed components in turn, allowing us to animate them.\n\nAdd `enter` and `exit` poses to `P`:\n\n```javascript\nconst P = posed.p({\n  enter: { x: 0, opacity: 1 },\n  exit: { x: 50, opacity: 0 }\n});\n```\n\nNow, when you enter and exit the `About` page, all the paragraphs will animate in and out. But they all animate in together. It'd be nice to stagger these animations instead.\n\nThat's why we've made `Container` a posed component too. It's not going to do animation itself, it's just going to control the animation of its children with the `staggerChildren` property:\n\n```javascript\nconst Container = posed.div({\n  enter: { staggerChildren: 50 }\n});\n```\n\nTry entering and exiting the `About` page again. The paragraphs stagger in.\n\nWe can try the same trick on the `Home` page. Open `pages/home.js` and replace the `ListContainer` and `Item` posed components with this:\n\n```javascript\nconst ListContainer = posed.ul({\n  enter: { staggerChildren: 50 },\n  exit: { staggerChildren: 20, staggerDirection: -1 }\n});\n\nconst Item = posed.li({\n  enter: { y: 0, opacity: 1 },\n  exit: { y: 50, opacity: 0 }\n});\n```\n\nThis time, `ListContainer`'s `exit` pose has a new property, `staggerDirection`. Setting this to `-1` reverses the stagger, so elements animate out from the bottom up.\n\n## Conclusion\n\nWe've learned how to use Pose with React Router to do a quick and simple fade transition, as well as animating across children to provide unique effects for every page.\n\nWe've also seen how posed components can be used not only to animate, but to sequence the animations of their children.\n"
  },
  {
    "path": "packages/popmotion-pose/docs/learn/react/ui-events.md",
    "content": "---\ntitle: UI events and interactions\ndescription: Trigger animations based on UI events like drag, press, hover and focus\ncategory: react\nnext: react-exit-enter-transitions\n---\n\n> React Pose has been **deprecated** in favour of [Framer Motion](https://framer.com/motion). [Read the upgrade guide](https://www.framer.com/api/motion/migrate-from-pose/)\n\n# UI events and interactions\n\nPose can be used to power and animate interactions. Currently, it supports the following events: drag, press, hover and focus.\n\nIn this tutorial, we'll take a look at each.\n\n<TOC />\n\n## Drag\n\nWith Pose, making an element draggable is as simple as passing `draggable: true` to the config:\n\n```javascript\nconst Box = posed.div({\n  draggable: true\n});\n```\n\n<CodeSandbox id=\"8z7j041kyl\" />\n\n`true` sets both axis to draggable, but we can select a single axis to drag by setting it to `'x'` or `'y'`.\n\n<CodeSandbox id=\"x23pw14oop\" />\n\n### Boundaries\n\nWe can add boundaries to the range of motion with the `dragBounds` property.\n\nIt accepts `top`, `left`, `bottom` and/or `right`, measured in pixels or percentages:\n\n```javascript\nconst Box = posed.div({\n  draggable: 'x',\n  dragBounds: { left: '-100%', right: '100%' }\n});\n```\n\n<CodeSandbox id=\"j27p9l3v6y\" />\n\n### Poses\n\nWhen a posed component is draggable, two new poses are fired.\n\nWhile dragging is active, the `drag` pose takes effect.\n\n```javascript\nconst Box = posed.div({\n  draggable: true,\n  init: { scale: 1 },\n  drag: { scale: 1.2 }\n});\n```\n\n**Note:** A current limitation with the `drag` pose is you must leave `transition` **undefined**.\n\nWhen dragging finishes, by default all values revert to their previous pose. Optionally, a `dragEnd` pose can be defined:\n\n```javascript\nconst Box = posed.div({\n  draggable: true,\n  init: { scale: 1 },\n  drag: { scale: 1.2 },\n  dragEnd: { scale: 0.5 }\n});\n```\n\n<CodeSandbox id=\"0xjn840k6p\" />\n\nYou can use this pose to animate `x` and `y`, too. For instance, you could make the object spring back to its origin:\n\n```javascript\nconst Box = posed.div({\n  draggable: true,\n  init: { scale: 1 },\n  drag: { scale: 1.2 },\n  dragEnd: {\n    x: 0,\n    y: 0,\n    transition: { type: 'spring' }\n  }\n});\n```\n\n<CodeSandbox id=\"mynjwyp478\" />\n\n### Events\n\nWe can respond to drag start, drag end, and value change events to trigger updates in our UI.\n\nYou can provide callbacks to the `onDragStart` and `onDragEnd` props. These fire with the originating mouse or touch events.\n\nTo track changes in `x` and `y`, the `onValueChange` prop accepts a map of callbacks, one for each animating value.\n\n```javascript\nconst Box = posed.div({ draggable: 'x' })\n\nexport default ({ onStart, onEnd, onDrag }) => (\n  <Box\n    onDragStart={onStart}\n    onDragEnd={onEnd}\n    onValueChange={{ x: onDrag }}\n  />\n);\n```\n\n## Press\n\nWith `pressable` set to `true`, you can respond to mouse and touch down events with the `press` pose:\n\n```javascript\nconst Box = posed.div({\n  pressable: true,\n  init: { scale: 1 },\n  press: { scale: 0.8 }\n});\n```\n\n<CodeSandbox id=\"31n86p0jw6\" />\n\nBy default, when pressing ends, values will return to their previous pose. You can **optionally** set a `pressEnd` pose to override this.\n\n### Events\n\nWe can respond to press start and end events with the `onPressStart` and `onPressEnd` callbacks:\n\n```javascript\nconst Box = posed.div({\n  pressable: true,\n  init: { scale: 1 },\n  press: { scale: 0.8 }\n});\n\nexport default ({ onStart, onEnd }) => (\n  <Box onPressStart={onStart} onPressEnd={onEnd} />\n);\n```\n\nYou might prefer to use this over React's in-built `onMouseDown`/`onMouseUp` etc events because Pose's event handling method avoids the annoying situation where a user presses an element, and only stops pressing once they've moved their pointer outside the element.\n\nThose `onMouseUp`/`onTouchEnd` callbacks only fire if the pointer is still on the triggering element, whereas `onPressEnd` will fire anywhere in the page.\n\n## Hover\n\nComponents can respond to hovers by settings `hoverable` to `true`. This will enable use of the `hover` pose:\n\n```javascript\nconst Box = posed.div({\n  hoverable: true,\n  init: {\n    scale: 1,\n    boxShadow: '0px 0px 0px rgba(0,0,0,0)'\n  },\n  hover: {\n    scale: 1.2,\n    boxShadow: '0px 5px 10px rgba(0,0,0,0.2)'\n  }\n});\n```\n\n<CodeSandbox id=\"jlwnqwomo9\" />\n\nBy default, when hovering ends, values will return to their previous pose. You can **optionally** set a `hoverEnd` pose to override this.\n\n## Focus\n\nFocusable elements can animate into the `focus` pose by setting `focusable: true`:\n\n```javascript\nconst Box = posed.div({\n  focusable: true,\n  init: {\n    color: '#aaa',\n    outlineWidth: '0px',\n    outlineOffset: '0px',\n    scale: 1\n  },\n  focus: {\n    color: '#000',\n    outlineWidth: '12px',\n    outlineOffset: '5px',\n    outlineColor: '#AB36FF',\n    scale: 1.2\n  }\n});\n```\n\n<CodeSandbox id=\"rlly2kryrn\" />\n\nBy default, when hovering ends, values will return to their previous pose. You can **optionally** set a `blur` pose to override this.\n"
  },
  {
    "path": "packages/popmotion-pose/docs/learn/react-native/native-animating-children.md",
    "content": "---\ntitle: Animating children\ndescription: How to orchestrate animations across multiple elements\ncategory: react-native\nnext: native-dragging\n---\n\n# Animating children\n\nTraditionally, coordinating animations across multiple children has been a delicate, involved process.\n\nWith Pose, animating multiple components is as simple as animating one.\n\nIt looks like this:\n\n```javascript\nexport default ({items}) => (\n  <Parent pose=\"poseName\">\n    {items.map(item => <Child />)}\n  </Parent>\n)\n```\n\n<Video src=\"/videos/native-children.mp4\" height=\"320\" />\n\nHere's how it's done.\n\n<TOC />\n\n## Child animation\n\nWe're going to make an animation of an overlay sliding in from the bottom of the screen. As it animates in, its children items will fade and slide in from the right.\n\nFirst, we need to define the posed components:\n\n```javascript\nconst Overlay = posed.View({\n  open: { y: 0 },\n  closed: { y: '100vh' }\n});\n\nconst Item = posed.View({\n  open: { x: 0, opacity: 1 },\n  closed: { x: 100, opacity: 0 }\n})\n```\n\nTo make the transition between the two states, we make `Item` children components of `Overlay`: \n\n```javascript\nexport default ({ isOpen }) => (\n  <Overlay pose={isOpen ? 'open' : 'closed'}>\n    <Item />\n    <Item />\n    <Item />\n    <Item />\n  </Overlay>\n)\n```\n\nWhen `pose` changes on `Overlay`, that will be propagated through to `Item`.\n\nFor simplicity's sake, they're shown here as direct children. But it's important to note that they don't need to be direct children, or rendered in the same component. Plus, `Item` could have posed children that also had `open` and `closed` poses, and the animations would propagate through to those too.\n\n## Block pose propagation\n\nIf you have a posed component that's a child of another posed component, and you **don't** want pose changes propagating down to it, you can start a new ancestor chain by passing `withParent={false}`:\n\n```javascript\n<Item withParent={false} />\n```\n\n## Schedule parent and child animations\n\nCurrently, our child animations are being fired at the exact same time as the parent. We can change that with some props that can delay, stagger or rearrange animations.\n\n### delay\n\nThe `delay` property can be used to delay the animation on the current poser, without affecting the execution of child animations.\n\nSo by setting `delay: 300` on the overlay's `closed` pose, the children animations will wait 300 milliseconds before animating out.\n\n```javascript\nconst Overlay = posed.View({\n  open: { y: 0 },\n  closed: { y: '100vh', delay: 300 }\n});\n```\n\n### delayChildren\n\nConversely, the `delayChildren` property can be used to delay all the children animations.\n\nBy setting `delayChildren` on the overlay's `open` pose, we can animate the overlay out and **then** animate the children in:\n\n```javascript\nconst Overlay = posed.View({\n  open: { y: 0, delayChildren: 200 },\n  closed: { y: '100vh', delay: 300 }\n});\n```\n\n### staggerChildren\n\nRather than animating all the children in at once, it's possible to stagger them in individually. The `staggerChildren` prop can be used to determine the delay between each one, starting from **after** the `delayChildren` duration:\n\n```javascript\nconst Overlay = posed.View({\n  open: {\n    y: 0,\n    delayChildren: 200,\n    staggerChildren: 50\n  },\n  closed: { y: '100vh', delay: 300 }\n});\n```\n\n### staggerDirection\n\n`staggerDirection` can be used to determine which order we stagger over the children in. It can either be `1` (first to last, default), or `-1` (last to first).\n\n### beforeChildren/afterChildren\n\nSetting either `beforeChildren` or `afterChildren` props to `true` will make the parent animation play **before** or **after** any children animations.\n"
  },
  {
    "path": "packages/popmotion-pose/docs/learn/react-native/native-custom-transitions.md",
    "content": "---\ntitle: Custom transitions\ndescription: How to use custom transitions with Pose for React Native\ncategory: react-native\nnext: native-animating-children\n---\n\n# Custom transitions\n\nWith [automatic animations](/pose/learn/native-get-started), it's easy to create snappy and playful animations just by defining poses.\n\nBut there's plenty of instances where we want full control over our animation. For this, we can use the [`transition` property](/pose/api/native-config/#config-poses-transition).\n\n<TOC />\n\n## Basic usage\n\n`transition` can be defined as an object that describes how each value should transition to its new pose:\n\n```javascript\nposed.View({\n  visible: {\n    opacity: 1,\n    transition: { duration: 300 }\n  }\n})\n```\n\nIf we're animating multiple properties, we can **optionally** provide different animations for each by providing a named map.\n\n```javascript\nposed.View({\n  visible: {\n    opacity: 1,\n    scaleY: 1,\n    transition: {\n      opacity: { ease: 'easeOut', duration: 300 },\n      default: { ease: 'linear', duration: 500 }\n    }\n  }\n});\n```\n\n**By default**, if we define a `transition`, it'll be a `tween`. This is an animation between two values over a specific duration of time.\n\nBy providing a `type` property, we can select a different animation to use:\n\n```javascript\ntransition: { type: 'spring', stiffness: 100 }\n```\n\nPose for React Native currently supports tween, spring, and keyframes animations.\n\n## Advanced usage\n\nIt's possible to set a `transition` prop as a function.\n\nThis can be used to generate a transition definition using dynamic props:\n\n```javascript\ntransition: ({ toValue }) => ({\n  type: 'keyframes',\n  values: [0, 10, toValue]\n})\n```\n\nOr to return any [React Animated](https://facebook.github.io/react-native/docs/animated) animation:\n\n```javascript\nposed.View({\n  draggable: 'x',\n  dragEnd: {\n    x: 0,\n    transition: ({ value, toValue, gestureState, useNativeDriver }) =>\n      gestureState.dx > 50 || gestureState.dx < -50\n        ? Animated.decay(value, { velocity: gestureState.vx, useNativeDriver })\n        : Animated.spring(value, { toValue, useNativeDriver })\n  }\n})\n```\n\n**Note:** When returning a React Animated animation, you **must** pass it the `useNativeDriver` prop as provided by the transition function."
  },
  {
    "path": "packages/popmotion-pose/docs/learn/react-native/native-dragging.md",
    "content": "---\ntitle: Dragging\ndescription: Make elements draggable with React Native Pose\ncategory: react-native\nnext: native-passive\n---\n\n# Dragging (experimental)\n\nSimplifying interactivity is a core aim for Pose on the web, and the same is true for React Native Pose.\n\nCurrently, it offers experimental dragging support. In this tutorial, we'll:\n\n- Make a component draggable\n- Hook into the special `dragging` and `dragEnd` poses\n- Use the `onDragStart` and `onDragEnd` callbacks\n\n<TOC />\n\n## Dragging\n\nTo make a component draggable set `draggable: true` in the posed component config:\n\n```javascript\nconst config = {\n  draggable: true\n};\n```\n\n<Video src=\"/videos/native-drag.mp4\" height=\"320\" />\n\n`true` sets both axis to draggable, but we can select a single axis to drag on by setting it to `'x'` or `'y'`:\n\n```javascript\nconst config = {\n  draggable: 'x'\n}\n```\n\n<Video src=\"/videos/native-drag-x.mp4\" height=\"320\" />\n\n## Special poses\n\nWhen dragging, two special poses become available. `dragging`, and `dragEnd`.\n\nThese two poses will be set automatically and will propagate throughout the component's children as normal.\n\nFor instance, we could make a component that increases in scale while the user's dragging:\n\n```javascript\nconst config = {\n  draggable: true,\n  dragging: { scale: 1.2 },\n  dragEnd: { scale: 1 }\n};\n```\n\n<Video src=\"/videos/native-drag-pose.mp4\" height=\"320\" />\n\nBoth of these poses gets provided [PanResponder's](https://facebook.github.io/react-native/docs/panresponder.html) `gestureState` object, so we can make different animations based on the behaviour of the drag:\n\n```javascript\nconst config = {\n  draggable: 'x',\n  dragEnd: {\n    x: 0,\n    transition: ({ value, toValue, gestureState }) => {\n      return gestureState.dx > 50 || gestureState.dx < -50\n        ? Animated.decay(value, { velocity: gestureState.vx })\n        : Animated.spring(value, { toValue })\n    }\n  }\n}\n```\n\n<Video src=\"/videos/native-drag-end.mp4\" height=\"320\" />\n\n## onDragStart/onDragEnd\n\nIf `onDragStart` or `onDragEnd` callbacks are provided to the component, they'll be called with the same arguments as [PanResponder's](https://facebook.github.io/react-native/docs/panresponder.html) `onPanResponderGrant` and `onPanResponderRelease` callbacks.\n\n```javascript\n<DraggableComponent onDragEnd={(e, gestureState) => {}} />\n```\n\n## Coming soon\n\nPose for the web has a `dragBounds` property that can clamp movement to within a specified range. This feature will come to React Native Pose in the coming weeks.\n\nIn the longer term we want to introduce a range of properties like snap points, but the serialisable nature of Animated's API makes this difficult compared to the functional API of Popmotion.\n\n## Dragging via Interactable\n\nWix's [Interactable](https://github.com/wix/react-native-interactable) library is a declarative way of introducing interactions at the component level and is compatible with React Native Pose. If you use it be careful **not** to set `draggable: true` on the posed component otherwise Pose will disable the native driver.\n\n```javascript\nconst PosedComponent = posed()(config);\n\nexport default () => (\n  <PosedComponent pose=\"poseName\">\n    {({ x, y }) => (\n      <Interactable.View\n        animatedValueX={x}\n        horizontalOnly={true}\n        snapPoints={[{x: 0}, {x: -200}]}\n      />\n    )}\n  </PosedComponent>\n)\n```\n"
  },
  {
    "path": "packages/popmotion-pose/docs/learn/react-native/native-get-started.md",
    "content": "---\ntitle: Get started\ndescription: Introduction to Pose for React Native's declarative animation interface\ncategory: react-native\nnext: native-custom-transitions\n---\n\n# Get started\n\nPose is a declarative motion system that combines the simplicity of CSS syntax with the power and flexibility of JavaScript animations and interactions.\n\nIn this series of tutorials, we'll learn how to use Pose for React Native. We'll gradually introduce each of its features, starting with this simple `opacity` animation:\n\n<Video src=\"/videos/native-get-started.mp4\" height=\"320\" />\n\n<TOC />\n\n## Setup\n\nInstall Pose for React Native in your React Native project:\n\n### npm\n\n```bash\nnpm install react-native-pose\n```\n\n### yarn\n\n```bash\nyarn add react-native-pose\n```\n\n## The \"Hello World\" animation\n\nIn Pose for React Native, we create animated components by importing `posed` from `react-native-posed`:\n\n```javascript\nimport posed from 'react-native-pose';\n```\n\n`posed` can create [animated versions of any component](/pose/api/native-posed), but it has built-in support for `View`, `Text`, `Image`, and `ScrollView`:\n\n```javascript\nconst Box = posed.View();\n```\n\nWe can pass a [a configuration object](/pose/api/native-config) to the posed component that defines visual states, or \"poses\", that our component can be in:\n\n```javascript\nconst Box = posed.View({\n  visible: { opacity: 1 },\n  hidden: { opacity: 0 }\n});\n```\n\nThis `Box` component can be animated between `'hidden'` and `'visible'` poses by passing it a `pose` property on render:\n\n```javascript\nexport default ({ isVisible }) => (\n  <Box style={styles.box} pose={isVisible ? 'visible' : 'hidden'} />\n)\n```\n\nAnd that's it! By switching `isVisible`, your `Box` component will animate in and out.\n\n## But wait, where did we define the animation?\n\nShort answer: we didn't.\n\nMore helpful answer: By default, Pose **doesn't require you to explicitly define the animations** used to transition between two states.\n\nInstead, it automatically selects a React Animated animation based on the property being animated.\n\nThese animations have been designed to create snappy and playful interfaces. Physical motion uses `spring` to maintain velocity between animations, whereas properties like `opacity` use a `tween`.\n\nHowever, there will always be situations where we need greater control over our animations. For that, we can define [custom transitions](/pose/learn/native-custom-transitions).\n"
  },
  {
    "path": "packages/popmotion-pose/docs/learn/react-native/native-passive.md",
    "content": "---\ntitle: Passive values\ndescription: Learn how to create passive values that only change when others do\ncategory: react-native\n---\n\n# Passive values\n\nPassive values bind to a value defined in your poses, and change when they change using `Animated.Value.interpolate`.\n\nThey're currently the **only** way to animate colors in React Native Pose.\n\n<TOC />\n\n## Defining a passive value\n\nPassive values are defined via the `passive` config prop.\n\nThey're defined as tuples, and look like this:\n\n```javascript\nconst config = {\n  draggable: 'x',\n  passive: {\n    opacity: ['x', {\n      inputRange: [-200, 0, 200],\n      outputRange: [0, 1, 0]\n    }]\n  }\n}\n```\n\n<Video src=\"/videos/native-passive-opacity.mp4\" height=\"320\" />\n\nThe first property in the tuple is the name of the value to bind to.\n\nThe second is [the interpolation definition](https://facebook.github.io/react-native/docs/animations.html#interpolation). It maps from the bound value to our passive value.\n\n## Animating color\n\nWe currently use `passive` to animate colors (though the ability to define them in poses is on the roadmap).\n\n```javascript\nconst config = {\n  open: { scale: 1 },\n  closed: { scale: 0 },\n  passive: {\n    backgroundColor: ['scale', {\n      inputRange: [0.5, 1],\n      outputRange: ['#f00', '#0f0']\n    }]\n  }\n};\n```\n\n<Video src=\"/videos/native-passive-color.mp4\" height=\"320\" />\n\n## Binding to ancestors\n\nSo far we've bound passive values to other values on the same posed components.\n\nWe can also look back up the ancestor chain and link to values defined in parent posed components.\n\n### First posed parent\n\nTo link to the first ancestor in the posed component ancestor chain, we just pass `true` as the third and final argument of the tuple.\n\n```javascript\nconst Sidebar = posed.View({\n  open: { x: 0 },\n  closed: { x: -300 }\n})\n\nconst Item = posed.View({\n  passive: {\n    opacity: ['x', {\n      inputRange: [-300, 0],\n      outputRange: [0, 1]\n    }, true]\n  }\n})\n\nexport default ({ isOpen }) => (\n  <Sidebar pose={isOpen ? 'open' : 'closed'}>\n    <Item />\n    <Item />\n    <Item />\n  </Sidebar>\n)\n```\n\n<Video src=\"/videos/native-passive-children.mp4\" height=\"320\" />\n\n### Further ancestors\n\nTo go further up the chain, we can use the `label` prop instead of `true`.\n\nFirst, provide a label to the ancestor:\n\n```javascript\nconst Sidebar = posed.View({\n  label: 'sidebar',\n  open: { x: 0 },\n  closed: { x: 300 }\n})\n```\n\nThen we provide this label to a child component:\n\n```javascript\nconst Item = posed.View({\n  passive: {\n    opacity: ['x', {\n      inputRange: [0, 300],\n      outputRange: [1, 0]\n    }, 'sidebar']\n  }\n})\n```\n\n`Item` could now be many posed components deep and it'll still bind to the Sidebar component.\n"
  },
  {
    "path": "packages/popmotion-pose/docs/learn/vue/vue-animating-children.md",
    "content": "---\ntitle: Animating children\ndescription: How to orchestrate animations across multiple elements in Pose for Vue\ncategory: vue\nnext: vue-ui-events\n---\n\n# Animating children\n\nTraditionally, coordinating animation across multiple children has been an involved process.\n\nWith Pose for Vue, it's as simple as animating just one. It looks like this:\n\n```javascript\nconst Component = {\n  components: {\n    Parent: posed.ul(ulPoses),\n    Child: posed.li(liPoses)\n  },\n  template: `\n    <Parent :pose=\"currentPose\">\n      <Child v-for=\"items in item\" v-bind:key=\"item\" />\n    </Parent>\n  `\n};\n```\n\nWhenever a posed component changes `pose`, that change is communicated throughout all of its children components. Even if they're not direct children, they still update accordingly.\n\nThis makes it super-simple to, for instance, make page-wide route transitions.\n\n<TOC />\n\n## Setup\n\nTo demonstrate animating children, we're going to create this sidebar animation:\n\n<CodeSandbox id=\"qq667ljpz4\" vue height=\"500\" />\n\nFollow along by forking this [CodeSandbox](https://codesandbox.io/s/n36vyq63vm?module=%2Fsrc%2FApp.vue).\n\n## Sidebar (parent)\n\nIn our sandbox, look in the `script` section. We're exporting a component that simply toggles an `isVisible` boolean every two seconds.\n\nOur template is currently empty, so let's add a `Sidebar` that open and closes depending on the status of `isVisible`.\n\nAdd a new property to our exported component called `components`. In it, add a `Sidebar` posed component with a couple of poses, `'visible'` and `'hidden'`:\n\n```javascript\ncomponents: {\n  Sidebar: posed.ul({\n    visible: { x: 0 },\n    hidden: { x: '-100%' }\n  })\n}\n```\n\nIn our `template` section, lets render this `Sidebar` component, passing it either a `'visible'` or `'hidden'` pose depending on `isVisible`:\n\n```javascript\n<template>\n  <Sidebar class=\"sidebar\" :pose=\"isVisible ? 'visible' : 'hidden'\" />\n</template>\n```\n\nAlready, we can see our sidebar peeking in and out of our page. Let's add some items to it.\n\n## Items (children)\n\nWe need a new posed component, this time called `Item`. Add it to `components`:\n\n```javascript\nItem: posed.li({\n  visible: { opacity: 1, y: 0 },\n  hidden: { opacity: 0, y: 20 }\n})\n```\n\nWe can render this by iterating over the `items` array being created our exported component's `data` function. Pass this as a child of `Sidebar`:\n\n```javascript\n<template>\n  <Sidebar class=\"sidebar\" :pose=\"isVisible ? 'visible': 'hidden'\">\n    <Item class=\"item\" v-for=\"item in items\" v-bind:key=\"item\" />\n  </Sidebar>\n</template>\n```\n\nWe've only passed `pose` to `Sidebar`, but all our `Item`s are animating in and out, too!\n\nIn this example, `Item` is a direct child of `Sidebar`, but this will still work if it was a far descendant of `Sidebar`. You could even add children to `Item` and those would be animated correctly, too.\n\n## Scheduling animations\n\nCurrently, our children animations are being fired at the exact same time as the parent. But, often we'd prefer the child animations to be delayed or staggered.\n\nLuckily, we've got properties for that!\n\n### delay\n\nThe `delay` property can be used to delay the animation on the **current** poser, without affecting the execution of child animations.\n\nSo by setting `delay: 300` on the sidebar's `closed` pose, the children will all animate out before the sidebar itself.\n\n```javascript\nSidebar: posed.ul({\n  open: { x: '0%' },\n  closed: { x: '-100%', delay: 300 }\n});\n```\n\n### delayChildren\n\nConversely, the `delayChildren` property can be used to delay all the children animations.\n\nBy setting `delayChildren` on the sidebar's `open` pose, we can animate the sidebar out and **then** animate the children in:\n\n```javascript\nSidebar: posed.ul({\n  open: { x: '0%', delayChildren: 200 },\n  closed: { x: '-100%', delay: 300 }\n});\n```\n\n### staggerChildren\n\nRather than animating all the children in at once, it's possible to stagger them in individually. The `staggerChildren` prop can be used to determine the delay between each one, starting from **after** the `delayChildren` duration:\n\n```javascript\nSidebar: posed.ul({\n  open: {\n    x: '0%',\n    delayChildren: 200,\n    staggerChildren: 50\n  },\n  closed: { x: '-100%', delay: 300 },\n  initialPose: 'closed'\n});\n```\n\n### staggerDirection\n\n`staggerDirection` can be used to determine which order we stagger over the children in. It can either be `1` (first to last, default), or `-1` (last to first).\n\n### beforeChildren/afterChildren\n\nSetting either `beforeChildren` or `afterChildren` props to `true` will make the parent animation play **before** or **after** any children animations."
  },
  {
    "path": "packages/popmotion-pose/docs/learn/vue/vue-custom-transitions.md",
    "content": "---\ntitle: Custom transitions\ndescription: How to use Pose for Vue to define custom transitions.\ncategory: vue\nnext: vue-dynamic-props\n---\n\n# Custom transitions\n\nWith [automatic animations](/pose/learn/vue-get-started), it's easy to create snappy and playful animations just by defining poses.\n\nBut there's plenty of instances where we want full control over our animation. For this, we can use the `transition` property.\n\n<TOC />\n\n## Basic usage\n\nJust like CSS, every pose can have a `transition` property. This property describes how each value should transition to its new pose:\n\n```javascript\nconst config = {\n  visible: {\n    opacity: 1,\n    transition: { duration: 300 }\n  }\n}\n```\n\nIf we're animating multiple properties, we can **optionally** provide different animations for each by providing a named map.\n\n```javascript\nconst config = {\n  visible: {\n    opacity: 1,\n    scaleY: 1,\n    transition: {\n      opacity: { ease: 'easeOut', duration: 300 },\n      default: { ease: 'linear', duration: 500 }\n    }\n  }\n};\n```\n\n**By default**, if we define a `transition`, it'll be a `tween`. This is an animation between two values over a specific duration of time.\n\nBy providing a `type` property, we can select a different animation to use:\n\n## Transitions\n\nPose ships with five types of animation from [Popmotion Pure](/pure). Tween, spring, decay, keyframes, and physics.\n\n### Tween\n\nA tween animates from one value to another over a set duration of time.\n\n```javascript\ntransition: {\n  duration: 400,\n  ease: 'linear'\n}\n```\n\n#### Easing\n\nThe `ease` property can be used to affect the speed of the tween over the course of its duration.\n\nThis property can be the name of a [Popmotion easing function](/api/easing):\n\n- 'linear'\n- 'easeIn', 'easeOut', 'easeInOut'\n- 'circIn', 'circOut', 'circInOut'\n- 'backIn', 'backOut', 'backInOut'\n- 'anticipate'\n\nOr an array of four numbers to create a cubic bezier easing function:\n\n```javascript\ntransition: {\n  ease: [.01, .64, .99, .56]\n}\n```\n\n[Full `tween` documentation](/api/tween)\n\n### Spring\n\nSpring animations maintain velocity between animations to create visceral, engaging motion.\n\nIt makes them perfect for animations that happen as a result of user interaction.\n\nBy adjusting their `stiffness`, `mass` and `damping` properties, a wide-variety of spring feels can be created.\n\n```javascript\ntransition: { type: 'spring', stiffness: 100 }\n```\n\n[Full `spring` documentation](/api/spring)\n\n### Decay\n\nDecay reduces the velocity of an animation over a duration of time.\n\nIt's a perfect match for the special `dragEnd` pose that fires when a user stops [dragging](/pose/learn/vue-ui-events) something, as it can replicate the momentum-scrolling common on smart phones.\n\nThe end value is automatically calculated by Pose at the start of the animation, but with the `modifyTarget` prop, you can adjust this, allowing you to do things like snap to a grid.\n\n```javascript\ntransition: {\n  type: 'decay',\n  modifyTarget: v => Math.ceil(v / 100) * 100 // Snap to nearest 100px\n}\n```\n\n[Full `decay` documentation](/api/decay)\n\n### Keyframes\n\nKeyframes allows you to schedule a series of values to tween between.\n\n```javascript\ntransition: ({ from, to }) => ({\n  type: 'keyframes',\n  values: [from, 100, to],\n  times: [0, 0.25, 1]\n})\n```\n\n[Full `keyframes` documentation](/api/keyframes)\n\n### Physics\n\nPhysics allows you to simulate things like velocity, friction, and acceleration.\n\n```javascript\ntransition: {\n  type: 'physics',\n  velocity: 1000\n}\n```\n\n[Full `physics` documentation](/api/physics)\n\n## Transition props\n\nThere are a number of other properties that can be used with any transition:\n\n### Delay\n\nIf set, will delay the execution of the transition by the specified amount: \n\n```javascript\ntransition: {\n  type: 'physics',\n  delay: 400\n}\n```\n\n### Min/Max\n\nIf set, will ensure values are capped to no less than `min` and no more than `max`.\n\n```javascript\ntransition: {\n  type: 'keyframes',\n  values: [0, 3, 10],\n  min: 2,\n  max: 9\n}\n```\n\n### Round\n\nIf set to `true`, `round` will ensure that values output from the animation will be rounded.\n\n```javascript\ntransition: {\n  type: 'spring',\n  round: true\n}\n```\n"
  },
  {
    "path": "packages/popmotion-pose/docs/learn/vue/vue-dynamic-props.md",
    "content": "---\ntitle: Dynamic pose props\ndescription: Use props in Pose for Vue to create dynamic poses.\ncategory: vue\nnext: vue-animating-children\n---\n\n# Dynamic pose props\n\nEach pose property can be set as a function that resolves when the pose is entered:\n\n```javascript\nconst Box = posed.div({\n  visible: {\n    x: 0,\n    y: (props) => 100, // Resolved on `visible` enter\n    transition: {\n      x: { type: 'tween' },\n      y: (props) => ({ type: 'spring' }) // Resolved on `visible` enter\n    }\n  }\n})\n```\n\nBy using the provided `props` argument, this allows us to create dynamic properties that will react to changes in your app.\n\n<TOC />\n\n## Props\n\nSo what are props? In Pose for Vue, they're any taken from any [non-prop attributes](https://vuejs.org/v2/guide/components-props.html#Non-Prop-Attributes) set on the posed component.\n\nFor instance, you could use a component's `i` index attribute to write a dynamic `delay` prop:\n\n```javascript\nconst Component = {\n  components: {\n    Item: posed.li({\n      visible: {\n        opacity: 1,\n        transition: ({ i }) => ({ delay: i * 50 })\n      }\n    })\n  },\n  template: `<ul>\n  <Item\n    :pose=\"isVisible ? 'visible' : 'hidden'\"\n    v-for=\"item in items\"\n    v-bind:key=\"item\"\n    v-bind:i=\"item\"\n  />\n</ul>`\n};\n```\n\n<CodeSandbox id=\"v1vx1y2yz0\" height=\"500\" vue />\n\n## Transition props\n\n`transition` works a little differently than other pose props.\n\nIf set as a function, the function is run **once each for every property being animated**.\n\nThat function is provided a few extra props, automatically generated by Pose:\n\n- `from`: The current state of this value\n- `to`: The target state defined in the pose\n- `velocity`: If a numerical value, the current velocity of the value\n- `key`: The name of the current value\n- `prevPoseKey`: The name of the pose this value was previously set to\n\nThese props can be used to return a different transition definition based on the state of the value:\n\n```javascript\nconst Sidebar = posed.div({\n  open: {\n    x: '-100%',\n    transition: ({ velocity, to }) => velocity < 0\n      ? { to: 0 }\n      : { to }\n  }\n});\n```\n\nIf `transition` is a named map, **some or all** of these can be defined as functions:\n\n```javascript\nconst Sidebar = posed.div({\n  open: {\n    x: 0,\n    opacity: 1,\n    transition: {\n      x: ({ velocity, to }) => velocity < 0 ? { to: -300 } : { to },\n      opacity: { type: 'spring' }\n    }\n  }\n});\n```\n"
  },
  {
    "path": "packages/popmotion-pose/docs/learn/vue/vue-enter-exit-transitions.md",
    "content": "---\ntitle: Enter/exit transitions\ndescription: Learn how to make enter and exit transitions with Pose for Vue's PoseTransition component\ncategory: vue\nnext: vue-passive\n---\n\n# Enter/exit transitions\n\nPose for Vue includes a spin on the [Vue `transition` component](https://vuejs.org/v2/guide/transitions.html), `PoseTransition`.\n\nIts used for animating a single component as it's added or removed from the DOM.\n\nIn this tutorial we'll learn how to use it to animate a single component as it enters and leaves the DOM.\n\n<CodeSandbox id=\"3qvz9w2rp6\" height=\"500\" vue />\n\n<TOC />\n\n## Setup\n\nBegin by forking this [CodeSandbox playground](https://codesandbox.io/s/r7wv84wmnn?module=%2Fsrc%2FApp.vue).\n\nIt's set up with some basic styles, and a `button` that sets an `isVisible` data property to `true`.\n\n## Adding the modal\n\nFirst lets add a modal that gets conditionally rendered when `isVisible` is `true`.\n\nIn our template, add after the `button`:\n\n```html\n<div class=\"shade\" v-if=\"isVisible\">\n  <div class=\"modal\" />\n</div>\n```\n\nNow, when you click the button, the modal is added to the DOM.\n\nTo animate this, we can use `PoseTransition`. At the top of the `script` section, import it:\n\n```javascript\nimport { PoseTransition } from 'vue-pose';\n```\n\nPass this through to our template by providing it in the `components` property of our exported component:\n\n```javascript\nexport default {\n  data: () => ({ isVisible: false }),\n  components: { PoseTransition }\n};\n```\n\nNow in our `template` section we can wrap our newly-added HTML with the `PoseTransition` component:\n\n```html\n<PoseTransition>\n  <div class=\"shade\" v-if=\"isVisible\">\n    <div class=\"modal\" />\n  </div>\n</PoseTransition>\n```\n\nAwesome! Our modal now fades in when we click the button.\n\nIf we add a new event to our `shade` div, we can see it also fades out when we remove the modal:\n\n```javascript\n<div class=\"shade\" v-if=\"isVisible\" v-on:click=\"isVisible = false\">\n```\n\n## Custom transition\n\nIn many cases, we'll want to customise the animation used as components animate in and out.\n\nWe can do this by using posed components.\n\nImport `posed`:\n\n```javascript\nimport posed, { PoseTransition } from 'vue-pose';\n```\n\nNow made a new component for `Shade`. It's already a `div`, so let's use a `div`. We can define anything we want for the `'enter'` and `'exit'` poses, but for now lets just animate `opacity` with a quicker transition:\n\n```javascript\ncomponents: {\n  PoseTransition,\n  Shade: posed.div({\n    enter: {\n      opacity: 1,\n      transition: { duration: 200 }\n    },\n    exit: { opacity: 0 }\n  })\n}\n```\n\nNow replace the direct child of `PoseTransition` with `Shade`:\n\n```html\n<PoseTransition>\n  <Shade class=\"shade\" v-if=\"isVisible\" v-on:click=\"isVisible = false\">\n    <div class=\"modal\" />\n  </Shade>\n</PoseTransition>\n```\n\nAnd now the modal fades in faster! But wait, it doesn't fade out any more...\n\nWe can fix this by changing `v-on:click` with `v-on:click.native`. This tells Vue we want to add the event listener to the underlying element.\n\n## Animating children\n\nIt'd be cooler if we could do an animation that involves the white modal box, too. Well, we can! As we saw before, poses get propagated throughout the DOM, and components under `PoseTransition` are no different.\n\nReplace our `modal` div with:\n\n```html\n<Modal class=\"modal\" />\n```\n\nAnd add a new posed component called `Modal` to `components`:\n\n```javascript\nModal: posed.div({\n  enter: { opacity: 1, z: 0 },\n  exit: { opacity: 0, z: -150 }\n})\n```\n\nNow the modal animates too! But all the animations happen at the same time. We can adjust the timings by providing some extra props to `Shade`.\n\nBy adding `beforeChildren` to `enter` and `afterChildren` to `exit`, we can ensure that `Modal` animates separately to `Shade`:\n\n```javascript\nShade: posed.div({\n  enter: {\n    opacity: 1,\n    beforeChildren: true,\n    transition: { duration: 200, ease: \"linear\" }\n  },\n  exit: {\n    opacity: 0,\n    afterChildren: true,\n    transition: { duration: 200, ease: \"linear\" }\n  }\n}),\n```\n\n<CodeSandbox id=\"3qvz9w2rp6\" height=\"500\" vue />\n\n## Conclusion\n\nThere's more to `PoseTransition`, like animating between sibling components, and animating on mount. Find out its full capabilities with the [full API docs](/pose/api/vue-posetransition).\n"
  },
  {
    "path": "packages/popmotion-pose/docs/learn/vue/vue-flip.md",
    "content": "---\ntitle: FLIP\ndescription: A look at Pose for Vue's powerful FLIP API\ncategory: vue\n---\n\n# FLIP\n\nThe FLIP technique, [fully explained here](https://aerotwist.com/blog/flip-your-animations/), is a way of animating expensive, layout-breaking animations like `width` and `top` by using quick transforms.\n\nPose for Vue makes animating using the FLIP technique as simple as `flip: true`. Let's take a look.\n\n<TOC />\n\n## width/top\n\nThe problem with animating size and position properties is that they break layout. Recalculating layout is expensive, which can slow animations to below 60fps.\n\nSo, when you set a pose with `flip: true` and any of `width`, `height`, `top`, `left`, `right`, or `bottom` values, these will applied at the start of the animation. Pose will measure the size and position of the element before and after, and animate from one to the other using transform properties instead.\n\nFor instance, we can switch a `div` to fullscreen and back using the following config:\n\n```javascript\nPanel: posed.div({\n  fullscreen: {\n    width: '100vw',\n    height: '100vh',\n    transition: tween,\n    flip: true\n  },\n  thumbnail: {\n    width: 100,\n    height: 100,\n    transition: tween,\n    flip: true\n  }\n});\n```\n\n<CodeSandbox id=\"vvw57kww70\" vue />\n"
  },
  {
    "path": "packages/popmotion-pose/docs/learn/vue/vue-get-started.md",
    "content": "---\ntitle: Get started\ndescription: Introduction to Pose for Vue's declarative animation interface\ncategory: vue\nnext: vue-custom-transitions\n---\n\n# Get started\n\nPose for Vue is a declarative motion system that combines the simplicity of CSS transitions with the power and flexibility of JavaScript.\n\nIn this series of tutorials, we'll learn how to use Pose for Vue. We'll gradually introduce each of its features, starting with with this simple `opacity` animation:\n\n<CodeSandbox id=\"3vov3orj71\" vue view=\"preview\" />\n\n<TOC />\n\n## Setup\n\nThe easiest way to follow this tutorial is to [fork this CodeSandbox playground](https://codesandbox.io/s/9l3vknjv74?module=%2Fsrc%2FApp.vue).\n\nFor local development, all installation options can be found on the [install](/pose/learn/vue-install) page.\n\n## The \"Hello World\" animation\n\nIn Pose for Vue, we create animated components by importing `posed` from `vue-pose`.\n\nIn the head of the `script` section, add:\n\n```javascript\nimport posed from 'vue-pose';\n```\n\n`posed` can create animated versions of any HTML or SVG element.\n\nAdd a `components` property to our exported component that uses `posed` to create a `div`:\n\n```javascript\ncomponents: {\n  Box: posed.div()\n}\n```\n\nNow change the `div` in our `template` section to be an instance of `Box`:\n\n```javascript\n<template>\n  <Box class=\"box\" />\n</template>\n```\n\nWith Pose, we define possible states, or **poses**, that a component can be in. It looks a lot like CSS:\n\n```javascript\ncomponents: {\n  Box: posed.div({\n    visible: { opacity: 1 },\n    hidden: { opacity: 0 }\n  })\n}\n```\n\nNow to animate `Box` between its `visible` and `hidden` poses, we just pass it a `pose` prop.\n\nOur exported component has an interval set on it that toggles `isVisible` between `true` and `false`. We can use that variable in our template to define a pose:\n\n```javascript\n<template>\n  <Box class=\"box\" :pose=\"isVisible ? 'visible' : 'hidden'\" />\n</template>\n```\n\nThe box is now animating between the two poses!\n\n## But wait, where did we define the animation?\n\nShort answer: we didn't.\n\nMore helpful answer: By default, Pose **doesn't require you to explicitly define the animations** used to transition between two states.\n\nInstead, it automatically creates an animation based on the properties being animated.\n\nThese animations have been designed to create snappy and playful interfaces. Physical motion uses `spring` to maintain velocity between animations, whereas properties like `opacity` use a `tween`.\n\nHowever, there will always be situations where we want greater control. For that, we can define [custom transitions](/pose/learn/vue-custom-transitions)."
  },
  {
    "path": "packages/popmotion-pose/docs/learn/vue/vue-install.md",
    "content": "---\ntitle: Install\ndescription: Overview of Pose for Vue's installation options.\ncategory: vue\nnext: vue-get-started\n---\n\n# Install\n\n<TOC />\n\n## Package managers (recommended)\n\n### npm\n\n```bash\nnpm install vue-pose --save\n```\n\n### yarn\n\n```bash\nyarn add vue-pose\n```\n\n## File include\n\n**Note:** The Pose documentation uses the `import` syntax for importing individual modules.\n\n**If you use one of the following installation methods, top-level Pose for Vue exports will be available as the global `posed` variable.**\n\nSo, when you see in the docs `import posed from 'vue-pose'`, you can instead simply use the global `posed` variable.\n\n### Download\n\nYou can download the latest version of Pose for Vue at https://unpkg.com/vue-pose/dist/vue-pose.js\n\n### Script include\n\nYou can include it in your HTML with this `script` tag:\n\n```\n<script src=\"https://unpkg.com/vue-pose/dist/vue-pose.js\"></script>\n```\n\n## CodeSandbox\n\nYou can fork the [Pose for Vue playground on CodeSandbox](https://codesandbox.io/s/74471lpxqx), which is set up with the latest version of Pose for Vue.\n"
  },
  {
    "path": "packages/popmotion-pose/docs/learn/vue/vue-passive.md",
    "content": "---\ntitle: Passive values\ndescription: Learn how to create passive values that only change when others do\ncategory: vue\nnext: vue-flip\n---\n\n# Passive values\n\nSometimes we don't want to explicitly define a state for a value, we might just want it to change whenever another value does.\n\nFor instance, we might want an element to disappear as it moves beyond certain boundaries:\n\n<CodeSandbox vue id=\"848v06y8yj\" />\n\nFor this, we can use **passive values**. In this tutorial we'll see how to define them, and how to make them respond to changes in parent values too.\n\n<TOC />\n\n## Defining a passive value\n\nOpen the [this draggable example](https://codesandbox.io/s/848v06y8yj?module=%2Fsrc%2FApp.vue) and replace the posed component config with this:\n\n```javascript\nBox: posed.div({\n  draggable: 'x'\n});\n```\n\nThe dragging motion of the element is locked to the `x` axis. We can actually lock movement to the diagonal by defining `y` as a `passive` value.\n\nThe `passive` syntax will become clearer in the future  but for now they're defined as tuples, like this:\n\n```javascript\nconst Box = posed.div({\n  draggable: 'x',\n  passive: {\n    y: ['x', v => v]\n  }\n});\n```\n\nThe first item in the tuple is the name of the value we want to link to. In this case, that's `'x'`.\n\nThe second item is a mapping function. This takes the output of the linked value and returns our passive value. In this example, we're simply returning `x`, and creating this motion:\n\n<CodeSandbox vue id=\"qzz3l8j32w\" />\n\nBy using this mapping function we can start creating new effects. For instance, returning the negative of `x` creates diagonal movement in the opposite direction:\n\n```javascript\ny: ['x', v => -v]\n```\n\nOr by using `Math.sin` we can make wavey behaviour:\n\n```javascript\ny: ['x', v => v * Math.sin(v * 0.01)]\n```\n\n## Changing non-numerical values\n\nSo far, we've mapped two pixel values. But we can set any kind of value with any other.\n\nLong-time users of [Popmotion Pure](/pure) will recognise the signature of the mapping function. It accepts one value, and returns another. Which means we can compose this function using [Popmotion's transformers](/api/transformers).\n\nFor instance, instead of `y` let's create a function that will map `x` to `backgroundColor`.\n\nFor this we'll need to import four functions from `popmotion.transform`:\n\n```javascript\nimport transform from 'popmotion';\nconst { pipe, clamp, interpolate, blendColor } = transform;\n```\n\nOur steps will be:\n\n1) Convert the output of `x` from pixels to a `0` to `1` range\n2) Clamp that output to within `0` and `1`\n3) Use that progress number to blend between two colors\n\nWhich means our function will look like this:\n\n```javascript\nbackgroundColor: ['x', pipe(\n  interpolate([-200, 200], [0, 1]),\n  clamp(0, 1),\n  blendColor('#FF1C68', '#09f')\n)]\n```\n\n<CodeSandbox id=\"ovj5wvoq2z\" vue />\n\n## Linking to ancestors\n\nWe can also link a passive value to a value in one of the poser's ancestors.\n\nLet's revist our [sidebar example](https://codesandbox.io/s/qq667ljpz4?module=%2Fsrc%2FApp.vue) from earlier.\n\nCurrently, we're actively animating the children by setting poses on both the parent and the children.\n\nBut, it's possible to change the opacity of the items as the `x` of their sidebar parent changes.\n\nTo do this, we pass `true` as the third and final argument of the tuple. `true` says \"link to my parent\".\n\nAdd a slower `transition` to `Sidebar`'s `'visible'` pose to help us see this in effect.\n\n```javascript\ntransition: { duration: 1000 }\n```\n\nNow, import `pipe` and `interpolate` from `'popmotion'`:\n\n```javascript\nimport { transform } from 'popmotion';\nconst { pipe, interpolate } = transform;\n```\n\nAnd replace `Item`'s config with this:\n\n```javascript\nItem: posed.li({\n  passive: {\n    opacity: ['x', pipe(\n      parseFloat,\n      interpolate([-100, 0], [0, 1])\n    ), true]\n  }\n});\n```\n\nAs you can see, we're passing in a third parameter to the passive tuple, `true`. This says \"listen to the `x` value, but do so on my immediate parent\".\n\n### Distant ancestors\n\nUsing `true` is fine if we want to look just one part up the ancestor chain. But it's also possible to go much further up using `label`.\n\nBy explicitly naming our posers with a `label`, we can refer to any poser in the ancestor chain.\n\nAdd the label `'sidebar'` to our `Sidebar` config:\n\n```javascript\nSidebar: posed.ul({\n  label: 'sidebar',\n  /* other props */\n});\n```\n\nNow replace `true` in the `Item` config with `'sidebar'`. It still works, and it will still work if you decide to put a different posed component between `Sidebar` and `Item`.\n"
  },
  {
    "path": "packages/popmotion-pose/docs/learn/vue/vue-tutorial-medium-style-image-zoom.md",
    "content": "---\ntitle: \"Tutorial: Medium-style image zoom\"\ndescription: How to make Medium-style image zooming with Pose for Vue\ncategory: vue\n---\n\n# Tutorial: Medium-style image zoom\n\n[Medium](https://medium.com) have an beautiful zoom effect on their images. When clicked, they pop out of the page as a white background fades in behind them. Then, if clicked again, or if a user scrolls away, they pop back into place.\n\nTake a look:\n\n<iframe width=\"600\" height=\"400\" src=\"https://www.youtube.com/embed/Y2gd1ILCoYA\" frameborder=\"0\" allow=\"autoplay; encrypted-media\" allowfullscreen></iframe>\n\nIn this tutorial, we'll learn how to achieve this same effect using Pose for Vue.\n\n<TOC />\n\n## Setup\n\nTo get started, fork this [CodeSandbox template](https://codesandbox.io/s/n4n8opjjvj?module=%2Fsrc%2FApp.vue).\n\n`App.vue` contains a mock article that contains a couple of images. These are being rendered via the component we're going to work on, `ZoomImage`.\n\nOpen `components/ZoomImage.vue`, and let's get started!\n\n## State\n\nFirst, we need to create some state to keep track of whether the image is zoomed or not.\n\nIn the component exported from the `script` section, add a `data` property that returns our initial state:\n\n```javascript\nexport default {\n  props: ['imageWidth', 'imageHeight', 'src'],\n  data: () => ({ isZoomed: false })\n}\n```\n\nOf course, this state is useless on its own. We're going to need a couple of functions to set the zoom status. After the `data` prop, add a `methods` prop with `zoomIn` and `zoomOut` functions:\n\n```javascript\nmethods: {\n  zoomIn() {\n    this.isZoomed = true;\n  },\n  zoomOut() {\n    this.isZoomed = false;\n  }\n}\n```\n\nFinally, we want to toggle the zoomed state when someone clicks the image or, when zoomed in, its white background.\n\nAdd a `computed` property to the component with a `toggleZoom` property. This will return either `zoomIn` or `zoomOut` depending on whether `isZoomed` is `true` or `false`:\n\n```javascript\ncomputed: {\n  toggleZoom() {\n    return this.isZoomed ? this.zoomOut : this.zoomIn;\n  }\n}\n```\n\nIn the `template` section, we can now provide this `toggleZoom` property to the `div`:\n\n```javascript\n<div\n  v-bind:style=\"{ width: imageWidth + 'px', height: imageHeight + 'px' }\"\n  v-on:click=\"toggleZoom\"\n>\n```\n\nNow, when the image is clicked, the component will change zoom status. But we're not responding to this in our `template`. Let's make some animations!\n\n## Image zoom animation\n\nWhen the image zooms in, it needs to animate from its place in the document, smoothly into the center of the screen. To do this, we're going to use Pose's FLIP capabilities.\n\nYou can read the gritty details about FLIP in this [blog post by Paul Lewis](https://aerotwist.com/blog/flip-your-animations/). In essence, it's a way of *performantly* animating between two states that would otherwise be expensive, for instance where `position`, `top`, `width`, or other layout-changing properties have changed.\n\nIn Pose, you simply have to add `flip: true` to a pose, and it'll automatically perform the usually complicated steps to perform this animation.\n\nImport Pose for Vue:\n\n```javascript\nimport posed from 'vue-pose';\n```\n\nNow add a `components` prop to our exported component, and give it a posed `img` component named `ZoomImage`:\n\n```javascript\ncomponents: {\n  ZoomImage: posed.img()\n}\n```\n\nWe're going to provide the component two poses, one for each zoom state: `zoomedIn` and `zoomedOut`.\n\nOur `zoomedIn` pose is going to set `position: fixed` and every positional prop to `0`. This will pop the content out of the layout and lock it to the viewport.\n\nIn our `style` section, `img` has a style of `margin: auto` which centers the image when it's being stretched across the screen in this way.\n\n```javascript\nZoomImage: posed.img({\n  zoomedIn: {\n    position: 'fixed',\n    top: 0,\n    left: 0,\n    bottom: 0,\n    right: 0,\n    flip: true\n  }\n})\n```\n\n`zoomedOut` sets `position: static` to pop it back into the DOM, as well as setting `width` and `height` to `auto` to make it fill its layout container:\n\n```javascript\nZoomImage: posed.img({\n  zoomedOut: {\n    position: 'static',\n    width: 'auto',\n    height: 'auto',\n    flip: true\n  },\n  zoomedIn: {\n    position: 'fixed',\n    top: 0,\n    left: 0,\n    right: 0,\n    bottom: 0,\n    flip: true\n  }\n})\n```\n\nWe've now got our posed `img` component fully configured. Replace the `img` component in the `render` function with it:\n\n```html\n<ZoomImage :src=\"src\" />\n```\n\nTo animate `ZoomImage` between the two poses, we need to provide it a `pose` property.\n\nAdd a new `computed` property, `pose`. This will return the name of one of our defined poses, `'zoomedIn'` or `'zoomedOut'`, depending on whether `isZoomed` is `true` or `false`:\n\n```javascript\npose() {\n  return this.isZoomed ? 'zoomedIn' : 'zoomedOut';\n}\n```\n\nWe can now use this `pose` prop in our `template`:\n\n```html\n<ZoomImage :pose=\"pose\" :src=\"src\" />\n```\n\nNow, when we click our image, it zooms in and out!\n\nI find the automatically generated animation a little bouncy for this purpose. We can define a new `transition` with a `ease` curve generated at [Lea Verou's cubic bezier generator](http://cubic-bezier.com/#.08,.69,.2,.99).\n\n```javascript\nconst transition = {\n  duration: 400,\n  ease: [0.08, 0.69, 0.2, 0.99]\n};\n```\n\nProvide this as a `transition` prop to both `ZoomImage` poses, and the animation becomes a little slicker.\n\n## Background animation\n\nThat's the (usually) difficult bit out of the way. It's looking pretty good but the Medium example fades a background in behind the image as it zooms in and out.\n\nMake a new posed component in `components` called `Frame`:\n\n```javascript\nFrame: posed.div();\n```\n\nIn our `style` section, add a new rule for `.frame`. We're going to make the background of this frame white, and set `translateZ(0)` to ensure its fade animation is hardware-accelerated:\n\n```css\n.frame {\n  position: fixed;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  display: none;\n  background: white;\n  transform: translateZ(0);\n}\n```\n\nAnd now add `Frame` as a sibling of `Image`, also passing it the `pose` prop:\n\n```html\n<Frame :pose=\"pose\" class=\"frame\" />\n<ZoomImage :pose=\"pose\" :src=\"src\" />\n```\n\nNow we can animate it! We just want to fade the overlay in and out, so first add those poses:\n\n```javascript\nFrame: posed.div({\n  zoomedIn: { opacity: 1 },\n  zoomedOut: { opacity: 0 }\n});\n```\n\nBy itself this won't do anything, as we've got `display` set to `none` in the CSS.\n\nFor this we can use the `applyAtStart` and `applyAtEnd` props. They allow you to define styles to set at the start and at the end of the pose transition, respectively.\n\n```javascript\nFrame: posed.div({\n  zoomedIn: {\n    applyAtStart: { display: 'block' },\n    opacity: 1\n  },\n  zoomedOut: {\n    applyAtEnd: { display: 'none' },\n    opacity: 0\n  }\n});\n```\n\nNow your background will fade in and out behind the image as it zooms in!\n\n## Scroll to zoom out\n\nThe original Medium image zoom has a nice feature where if a user starts scrolling, the image zooms out back into its original place.\n\nWe can accomplish the same thing by adding a `'scroll'` event listener to `zoomIn`, and remove that event listener on `zoomOut`:\n\n```javascript\nzoomIn() {\n  window.addEventListener('scroll', this.zoomOut);\n  this.isZoomed = true;\n},\nzoomOut() {\n  window.removeEventListener('scroll', this.zoomOut);\n  this.isZoomed = false;\n}\n```\n\n## Conclusion\n\nHere's our finished example:\n\n<CodeSandbox height=\"700\" id=\"4w9vq9vkmw\" vue />\n\nThere's plenty of fun things you can do to improve accessibility and aesthetics.\n\nHave a think about:\n\n- Closing the image via the `esc` key\n- Changing the background animation. You could even incorporate SVGs.\n- Adding a \"scroll delay\" where a user has to scroll a minimum distance before we close the image.\n- Changing the cursor to show a zoom in or zoom out icon."
  },
  {
    "path": "packages/popmotion-pose/docs/learn/vue/vue-ui-events.md",
    "content": "---\ntitle: UI events and interactions\ndescription: Trigger animations based on UI events like drag, press, hover and focus in Pose for Vue\ncategory: vue\nnext: vue-enter-exit-transitions\n---\n\n# UI events and interactions\n\nPose for Vue can be used to power and animate interactions. Currently, it supports the following events: drag, press, hover and focus.\n\nIn this tutorial, we'll take a look at each.\n\n<TOC />\n\n## Drag\n\nWith Pose for Vue, making an element draggable is as simple as passing `draggable: true` to the config:\n\n```javascript\nconst Box = posed.div({\n  draggable: true\n});\n```\n\n<CodeSandbox id=\"xo2zn69j9p\" vue />\n\n`true` sets both axis to draggable, but we can select a single axis to drag by setting it to `'x'` or `'y'`.\n\n### Boundaries\n\nWe can add boundaries to the range of motion with the `dragBounds` property.\n\nIt accepts `top`, `left`, `bottom` and/or `right`, measured in pixels or percentages:\n\n```javascript\nconst Box = posed.div({\n  draggable: 'x',\n  dragBounds: { left: '-100%', right: '100%' }\n});\n```\n\n<CodeSandbox id=\"0zzqly3xl\" vue />\n\n### Poses\n\nWhen a posed component is draggable, two new poses are fired.\n\nWhile dragging is active, the `drag` pose takes effect.\n\n```javascript\nconst Box = posed.div({\n  draggable: true,\n  init: { scale: 1 },\n  drag: { scale: 1.2 }\n});\n```\n\n**Note:** A current limitation with the `drag` pose is you must leave `transition` **undefined**.\n\nWhen dragging finishes, by default all values revert to their previous pose. Optionally, a `dragEnd` pose can be defined:\n\n```javascript\nconst Box = posed.div({\n  draggable: true,\n  init: { scale: 1 },\n  drag: { scale: 1.2 },\n  dragEnd: { scale: 0.5 }\n});\n```\n\nYou can use this pose to animate `x` and `y`, too. For instance, you could make the object spring back to its origin:\n\n```javascript\nconst Box = posed.div({\n  draggable: true,\n  init: { scale: 1 },\n  drag: { scale: 1.2 },\n  dragEnd: {\n    x: 0,\n    y: 0,\n    transition: { type: 'spring' }\n  }\n});\n```\n\n<CodeSandbox id=\"xvjnq4q6p4\" vue />\n\n### Events\n\nWe can respond to drag start, drag end, and value change events to trigger updates in our UI.\n\nYou can attach listeners for the `drag-start` and `drag-end` events, as well as a map of listeners for each animated property to `on-value-change`:\n\n```vue\n<template>\n  <Box\n    class=\"box\"\n    :on-value-change=\"{ x: log }\"\n    v-on:drag-start=\"log\"\n    v-on:drag-end=\"log\"\n  />\n</template>\n\n<script>\nimport posed from 'vue-pose';\n\nexport default {\n  methods: { log: console.log },\n  components: {\n    Box: posed.div({ draggable: true })\n  }\n};\n</script>\n```\n\n## Press\n\nWith `pressable` set to `true`, you can respond to mouse and touch down events with the `press` pose:\n\n```javascript\nconst Box = posed.div({\n  pressable: true,\n  init: { scale: 1 },\n  press: { scale: 0.8 }\n});\n```\n\n<CodeSandbox id=\"6jqrnr57ok\" vue />\n\nBy default, when pressing ends, values will return to their previous pose. You can **optionally** set a `pressEnd` pose to override this.\n\n### Events\n\nWe can respond to press start and end events with the `press-start` and `press-end` listeners:\n\n```vue\n<template>\n  <Box class=\"box\" v-on:press-start=\"log\" v-on:press-end=\"log\" />\n</template>\n\n<script>\nimport posed from 'vue-pose';\n\nexport default {\n  methods: { log: console.log },\n  components: {\n    Box: posed.div({\n      pressable: true,\n      init: { scale: 1 },\n      press: { scale: 0.8 }\n    })\n  }\n};\n</script>\n```\n\nYou might prefer to use this over Vue's in-built events because Pose's event handling method avoids the annoying situation where a user presses an element, and only stops pressing once they've moved their pointer outside the element.\n\nThose `mouse-up`/`touch-end` callbacks only fire if the pointer is still on the triggering element, whereas `press-end` will fire anywhere in the page.\n\n## Hover\n\nComponents can respond to hovers by settings `hoverable` to `true`. This will enable use of the `hover` pose:\n\n```javascript\nconst Box = posed.div({\n  hoverable: true,\n  init: {\n    scale: 1,\n    boxShadow: '0px 0px 0px rgba(0,0,0,0)'\n  },\n  hover: {\n    scale: 1.2,\n    boxShadow: '0px 5px 10px rgba(0,0,0,0.2)'\n  }\n});\n```\n\n<CodeSandbox id=\"qvnw69lv9\" vue />\n\nBy default, when hovering ends, values will return to their previous pose. You can **optionally** set a `hoverEnd` pose to override this.\n\n## Focus\n\nFocusable elements can animate into the `focus` pose by setting `focusable: true`:\n\n```javascript\nconst Box = posed.input({\n  focusable: true,\n  init: {\n    color: '#aaa',\n    outlineWidth: '0px',\n    outlineOffset: '0px',\n    scale: 1\n  },\n  focus: {\n    color: '#000',\n    outlineWidth: '12px',\n    outlineOffset: '5px',\n    outlineColor: '#AB36FF',\n    scale: 1.2\n  }\n});\n```\n\n<CodeSandbox id=\"k3j0q867v7\" vue />\n\nBy default, when hovering ends, values will return to their previous pose. You can **optionally** set a `blur` pose to override this.\n"
  },
  {
    "path": "packages/projection/CHANGELOG.md",
    "content": "# Changelog\n\nProjection adheres to [Semantic Versioning](http://semver.org/).\n\n## [2.0.0] Unreleased"
  },
  {
    "path": "packages/projection/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright © 2020 Matt Perry\n\nPermission 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:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE 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."
  },
  {
    "path": "packages/projection/README.md",
    "content": "<p align=\"center\"><img alt=\"Projection\" width=\"315px\" height=\"250px\" src=\"https://user-images.githubusercontent.com/7850794/102894782-89d3bd80-445b-11eb-9ca4-1db275e684f0.png\" /></p>\n\n<h3 align=\"center\">A lightweight layout projection library</h3>\n\n## Introduction\n\nLayout projection is a method for animating layout at 60fps.\n\nIn essence, it's the ability to project any element from its browser-computed layout to a size and position on screen of your choosing.\n\n[Learn more about layout projection's capabilities.](https://mattperry.is/writing-code/layout-projection-animate-browser-layout-60fps-3)\n\n**Projection** is an experimental, lightweight layout projection library. It currently clocks in at 1.8kb, and I expect it to land somewhere in the 2.5kb range.\n\n[Demo](https://codesandbox.io/s/floral-frog-hv1k7?file=/src/index.js)\n\n## Install\n\n**Projection** is currently in alpha. Expect bugs, and breaking changes as the scope of the library is better defined.\n\n```bash\nnpm install projection@alpha\n```\n\n## Usage\n\n### Projecting an element\n\n```javascript\nimport { layoutNode, updateProjectionStyle } from \"projection\"\n\nconst element = document.getElementById(\"element-id\")\n\n/**\n * Create a layoutNode for each element you want to project\n */\nconst node = layoutNode({\n  onProjectionUpdate: () => updateProjectionStyle(node, element)\n})\n\n/**\n * To project, we need an accurate measurement of the element. To do this \n * accurately, the measured element can't currently have a transform applied.\n * Future releases will handle this automatically.\n * \n * Ensure that that `setLayout` is called every time the element's layout is recomputed.\n */\nconst bbox = element.getBoundingClientRect()\nnode.setLayout(bbox)\n\n/**\n * Now we can project. Setting a target will project an element into\n * the provided bounding box.\n */\nnode.setTarget({\n  top: 100,\n  left: 100,\n  right: 400,\n  bottom: 400\n})\n```\n\n### Projecting trees\n\nA major difficulty of layout animations is once you apply a transform to a parent, you distort children elements that you might wish to be of a particular size or position throughout the animation.\n\nThe calculations involved in correcting this distortion become increasingly complex for deeper layout animation trees.\n\n**Projection** removes this complexity by allowing `layoutNode` to accept another `layoutNode` as a parent. In this way, a tree can be formed. Projection will ensure all child transforms are calculated to compensate for parent transforms.\n\n```javascript\nconst childNode = layoutNode(options, parentNode)\n```\n\n#### Relative projection\n\nSet relative to parent:\n\n```javascript\nchildNode.setRelativeTarget({ top: 10, left: 10 })\n```\n\nChange relative parent:\n\n```javascript\nchildNode.setRelativeParent(node)\n```\n\n### Animations\n\nBy using a low-level animation library like [Popmotion](https://popmotion.io), layout animations are a matter of calling `setTarget` once per frame.\n\n```javascript\nimport { animate, mix } from \"popmotion\"\n\n// Just before layout change:\nconst prev = element.getBoundingClientRect()\n\n// Immediately after layout change:\nelement.style.transform = \"\"\nconst next = element.getBoundingClientRect()\nnode.setLayout(next)\n\nanimate({\n  from: 0,\n  to: 1,\n  onUpdate: progress => {\n    node.setTarget({\n      left: mix(prev.left, next.left, progress),\n      right: mix(prev.right, next.right, progress),\n      top: mix(prev.top, next.top, progress),\n      bottom: mix(prev.bottom, next.bottom, progress),\n    })\n  }\n})\n```\n\n## TODO\n\n- [ ] Add helper functions for scale correcting box shadow, border etc.\n- [ ] Make more DOM-specific API.\n- [ ] Develop relative target support to include pinned width/height animations.\n- [ ] Add support for `rotate`.\n- [ ] Add support for custom origins. \n- [ ] Add support for additional transforms. \n\n---\n\nThanks to [Alex Nault](https://alexnault.dev) for donating the `projection` package name!\n"
  },
  {
    "path": "packages/projection/cypress/fixtures/example.json",
    "content": "{\n  \"name\": \"Using fixtures to represent data\",\n  \"email\": \"hello@cypress.io\",\n  \"body\": \"Fixtures are a great way to mock data for responses to routes\"\n}"
  },
  {
    "path": "packages/projection/cypress/integration/index.spec.js",
    "content": "/// <reference types=\"Cypress\" />\n/* eslint-disable */\n\ndescribe(\"Layout projection\", () => {\n    it(\"Correctly projects DOM elements\", () => {\n        cy.visit(\"cypress/tests/index.html\")\n            .wait(50)\n            .get(\"#test\")\n            .should(($test) => {\n                const element = $test[0]\n                const {\n                    left,\n                    top,\n                    bottom,\n                    right,\n                } = element.getBoundingClientRect()\n\n                expect(left).to.equal(200)\n                expect(top).to.equal(200)\n                expect(right).to.equal(400)\n                expect(bottom).to.equal(500)\n            })\n    })\n    it(\"Correctly projects absolute children\", () => {\n        cy.visit(\"cypress/tests/index.html\")\n            .wait(50)\n            .get(\"#absolute-child\")\n            .should(($test) => {\n                const element = $test[0]\n                const {\n                    left,\n                    top,\n                    bottom,\n                    right,\n                } = element.getBoundingClientRect()\n\n                expect(left).to.equal(250)\n                expect(top).to.equal(300)\n                expect(right).to.equal(800)\n                expect(bottom).to.equal(330)\n            })\n    })\n    it(\"Correctly projects relative children\", () => {\n        cy.visit(\"cypress/tests/index.html\")\n            .wait(50)\n            .get(\"#relative-child\")\n            .should(($test) => {\n                const element = $test[0]\n                const {\n                    left,\n                    top,\n                    bottom,\n                    right,\n                } = element.getBoundingClientRect()\n\n                expect(left).to.equal(210)\n                expect(top).to.equal(210)\n                expect(right).to.equal(310)\n                expect(bottom).to.equal(310)\n            })\n    })\n})\n"
  },
  {
    "path": "packages/projection/cypress/plugins/index.js",
    "content": "/// <reference types=\"cypress\" />\n// ***********************************************************\n// This example plugins/index.js can be used to load plugins\n//\n// You can change the location of this file or turn off loading\n// the plugins file with the 'pluginsFile' configuration option.\n//\n// You can read more here:\n// https://on.cypress.io/plugins-guide\n// ***********************************************************\n\n// This function is called when a project is opened or re-opened (e.g. due to\n// the project's config changing)\n\n/**\n * @type {Cypress.PluginConfig}\n */\nmodule.exports = (on, config) => {\n  // `on` is used to hook into various events Cypress emits\n  // `config` is the resolved Cypress config\n}\n"
  },
  {
    "path": "packages/projection/cypress/support/commands.js",
    "content": "// ***********************************************\n// This example commands.js shows you how to\n// create various custom commands and overwrite\n// existing commands.\n//\n// For more comprehensive examples of custom\n// commands please read more here:\n// https://on.cypress.io/custom-commands\n// ***********************************************\n//\n//\n// -- This is a parent command --\n// Cypress.Commands.add(\"login\", (email, password) => { ... })\n//\n//\n// -- This is a child command --\n// Cypress.Commands.add(\"drag\", { prevSubject: 'element'}, (subject, options) => { ... })\n//\n//\n// -- This is a dual command --\n// Cypress.Commands.add(\"dismiss\", { prevSubject: 'optional'}, (subject, options) => { ... })\n//\n//\n// -- This will overwrite an existing command --\n// Cypress.Commands.overwrite(\"visit\", (originalFn, url, options) => { ... })\n"
  },
  {
    "path": "packages/projection/cypress/support/index.js",
    "content": "// ***********************************************************\n// This example support/index.js is processed and\n// loaded automatically before your test files.\n//\n// This is a great place to put global configuration and\n// behavior that modifies Cypress.\n//\n// You can change the location of this file or turn off\n// automatically serving support files with the\n// 'supportFile' configuration option.\n//\n// You can read more here:\n// https://on.cypress.io/configuration\n// ***********************************************************\n\n// Import commands.js using ES2015 syntax:\nimport './commands'\n\n// Alternatively you can use CommonJS syntax:\n// require('./commands')\n"
  },
  {
    "path": "packages/projection/cypress/tests/index.html",
    "content": "<html>\n    <head></head>\n    <body>\n        <script src=\"../../dist/projection.js\"></script>\n\n        <div id=\"test\">\n            <div id=\"absolute-child\"></div>\n            <div id=\"relative-child\"></div>\n        </div>\n\n        <style>\n            body {\n                margin: 0;\n                padding: 0;\n            }\n\n            #test {\n                width: 200px;\n                height: 200px;\n                background: red;\n            }\n\n            #absolute-child {\n                width: 100px;\n                height: 100px;\n                position: absolute;\n                top: 50px;\n                left: 50px;\n                background: green;\n            }\n\n            #relative-child {\n                width: 100px;\n                height: 100px;\n                position: absolute;\n                top: 50px;\n                left: 50px;\n                background: blue;\n            }\n        </style>\n\n        <script>\n            const root = document.getElementById(\"test\")\n            const absolute = document.getElementById(\"absolute-child\")\n            const relative = document.getElementById(\"relative-child\")\n            const { layoutNode, updateProjectionStyle } = projection\n\n            const rootNode = layoutNode({\n                onProjectionUpdate: () => updateProjectionStyle(root, rootNode),\n            })\n\n            const absoluteNode = layoutNode(\n                {\n                    onProjectionUpdate: () =>\n                        updateProjectionStyle(absolute, absoluteNode),\n                },\n                rootNode\n            )\n\n            const relativeNode = layoutNode(\n                {\n                    onProjectionUpdate: () =>\n                        updateProjectionStyle(relative, relativeNode),\n                },\n                rootNode\n            )\n\n            rootNode.setLayout(root.getBoundingClientRect())\n            absoluteNode.setLayout(absolute.getBoundingClientRect())\n            relativeNode.setLayout(relative.getBoundingClientRect())\n\n            rootNode.setTarget({\n                top: 200,\n                left: 200,\n                right: 400,\n                bottom: 500,\n            })\n\n            absoluteNode.setTarget({\n                top: 300,\n                left: 250,\n                right: 800,\n                bottom: 330,\n            })\n\n            relativeNode.setRelativeTarget({\n                top: 10,\n                left: 10,\n            })\n        </script>\n    </body>\n</html>\n"
  },
  {
    "path": "packages/projection/cypress.json",
    "content": "{}\n"
  },
  {
    "path": "packages/projection/package.json",
    "content": "{\n    \"name\": \"projection\",\n    \"version\": \"2.0.0-alpha.4\",\n    \"description\": \"The animator's toolbox\",\n    \"author\": \"Matt Perry\",\n    \"homepage\": \"https://popmotion.io\",\n    \"main\": \"lib/index.js\",\n    \"types\": \"lib/index.d.ts\",\n    \"module\": \"dist/es/index.mjs\",\n    \"jsnext:main\": \"dist/es/index.mjs\",\n    \"unpkg\": \"./dist/projection.min.js\",\n    \"exports\": {\n        \".\": {\n            \"types\": \"./lib/index.d.ts\",\n            \"import\": \"./dist/es/index.mjs\",\n            \"require\": \"./dist/projection.cjs.js\",\n            \"default\": \"./dist/projection.cjs.js\"\n        },\n        \"./package.json\": \"./package.json\"\n    },\n    \"sideEffects\": false,\n    \"repository\": {\n        \"type\": \"git\",\n        \"url\": \"https://github.com/Popmotion/popmotion/tree/master/packages/projection\"\n    },\n    \"bugs\": {\n        \"url\": \"https://github.com/Popmotion/popmotion/issues\"\n    },\n    \"keywords\": [\n        \"animation\",\n        \"ux\",\n        \"ui\",\n        \"flip\",\n        \"layout animation\"\n    ],\n    \"analyze\": true,\n    \"license\": \"MIT\",\n    \"scripts\": {\n        \"build\": \"rollup -c && tsc --emitDeclarationOnly && yarn measure\",\n        \"postbuild\": \"yarn babel $npm_package_module --out-file $npm_package_module --no-babelrc --plugins annotate-pure-calls\",\n        \"dev\": \"rollup -c -w\",\n        \"prepublishOnly\": \"yarn test && yarn build\",\n        \"measure\": \"gzip -c $npm_package_unpkg | wc -c\",\n        \"test\": \"jest --coverage --maxWorkers=2 && cypress run\",\n        \"publish-beta\": \"npm publish --tag beta\"\n    },\n    \"dependencies\": {\n        \"framesync\": \"5.0.0\",\n        \"hey-listen\": \"^1.0.8\",\n        \"popmotion\": \"9.0.1\",\n        \"style-value-types\": \"^3.2.0\",\n        \"tslib\": \"^2.1.0\"\n    },\n    \"devDependencies\": {\n        \"@rollup/plugin-commonjs\": \"^11.0.1\",\n        \"cypress\": \"^6.1.0\",\n        \"tslint-circular-dependencies\": \"^0.1.0\"\n    },\n    \"prettier\": {\n        \"printWidth\": 80,\n        \"tabWidth\": 4,\n        \"semi\": false,\n        \"trailingComma\": \"es5\"\n    },\n    \"jest\": {\n        \"moduleFileExtensions\": [\n            \"ts\",\n            \"js\"\n        ],\n        \"moduleNameMapper\": {\n            \"style-value-types\": \"<rootDir>/../../style-value-types/src\",\n            \"framesync\": \"<rootDir>/../../framesync/src\"\n        },\n        \"transform\": {\n            \"\\\\.(ts)$\": \"../../../node_modules/ts-jest/preprocessor.js\"\n        },\n        \"testRegex\": \"/__tests__/.*\\\\.test.(ts|js)$\",\n        \"rootDir\": \"src\",\n        \"collectCoverageFrom\": [\n            \"**/*.{js,jsx,ts,tsx}\",\n            \"!**/node_modules/**\",\n            \"!**/__tests__/**\",\n            \"!**/worklet/**\"\n        ],\n        \"coverageDirectory\": \"<rootDir>/../coverage\"\n    }\n}\n"
  },
  {
    "path": "packages/projection/rollup.config.js",
    "content": "import generateConfig from \"../../rollup-generate-config\"\nimport pkg from \"./package.json\"\n\nexport default [...generateConfig(pkg)]\n"
  },
  {
    "path": "packages/projection/src/__tests__/index.test.ts",
    "content": "import { layoutNode } from \"..\"\nimport { Projection } from \"../geometry/types\"\n\ndescribe(\"layoutNode\", () => {\n    test(\"Correctly assigns root node\", () => {\n        const parent = layoutNode()\n        const child = layoutNode({}, parent)\n        const grandChild = layoutNode({}, child)\n\n        expect(grandChild.scheduleUpdateProjection).toBe(\n            parent.scheduleUpdateProjection\n        )\n    })\n\n    test(\"Correctly projects tree\", async () => {\n        const promise = new Promise<Projection[]>((resolve) => {\n            const parent = layoutNode()\n            const grandChild = layoutNode(\n                {\n                    onProjectionUpdate: () => {\n                        resolve([parent.projection, grandChild.projection])\n                    },\n                },\n                parent\n            )\n\n            parent.setLayout({\n                left: 100,\n                right: 200,\n                top: 100,\n                bottom: 300,\n            })\n\n            grandChild.setLayout({\n                left: 110,\n                right: 210,\n                top: 110,\n                bottom: 210,\n            })\n\n            parent.setTarget({\n                left: 300,\n                right: 350,\n                top: 300,\n                bottom: 700,\n            })\n            grandChild.setTarget({\n                left: 300,\n                right: 400,\n                top: 300,\n                bottom: 400,\n            })\n        })\n\n        return expect(promise).resolves.toEqual([\n            {\n                x: {\n                    origin: 0.5,\n                    originPoint: 150,\n                    scale: 0.5,\n                    translate: 175,\n                },\n                y: {\n                    origin: 0.5,\n                    originPoint: 200,\n                    scale: 2,\n                    translate: 300,\n                },\n            },\n            {\n                x: {\n                    origin: 0.5,\n                    originPoint: 330,\n                    scale: 2,\n                    translate: 20,\n                },\n                y: {\n                    origin: 0.5,\n                    originPoint: 420,\n                    scale: 0.5,\n                    translate: -70,\n                },\n            },\n        ])\n    })\n\n    test(\"Correctly projects tree with relative nodes\", async () => {\n        const promise = new Promise<Projection[]>((resolve) => {\n            const parent = layoutNode()\n            const childA = layoutNode(\n                {\n                    onProjectionUpdate: () => {\n                        resolve([parent.projection, childA.projection])\n                    },\n                },\n                parent\n            )\n\n            parent.setLayout({\n                left: 100,\n                right: 200,\n                top: 100,\n                bottom: 300,\n            })\n\n            childA.setLayout({\n                left: 110,\n                right: 210,\n                top: 110,\n                bottom: 210,\n            })\n\n            parent.setTarget({\n                left: 300,\n                right: 350,\n                top: 300,\n                bottom: 700,\n            })\n\n            childA.setRelativeTarget({\n                top: 10,\n                left: 10,\n            })\n        })\n\n        return expect(promise).resolves.toEqual([\n            {\n                x: {\n                    origin: 0.5,\n                    originPoint: 150,\n                    scale: 0.5,\n                    translate: 175,\n                },\n                y: {\n                    origin: 0.5,\n                    originPoint: 200,\n                    scale: 2,\n                    translate: 300,\n                },\n            },\n            {\n                x: {\n                    origin: 0.5,\n                    originPoint: 330,\n                    scale: 2,\n                    translate: 30,\n                },\n                y: {\n                    origin: 0.5,\n                    originPoint: 420,\n                    scale: 0.5,\n                    translate: -60,\n                },\n            },\n        ])\n    })\n\n    test(\"Only fires onProjectionUpdate when projection has updated\", () => {\n        const target = {\n            left: 300,\n            right: 400,\n            top: 300,\n            bottom: 400,\n        }\n\n        const promise = new Promise<number>((resolve) => {\n            let updateCount = 0\n\n            const parent = layoutNode()\n            const grandChild = layoutNode(\n                {\n                    onProjectionUpdate: () => {\n                        updateCount++\n                    },\n                },\n                parent\n            )\n\n            parent.setLayout({\n                left: 100,\n                right: 200,\n                top: 100,\n                bottom: 300,\n            })\n\n            grandChild.setLayout({\n                left: 110,\n                right: 210,\n                top: 110,\n                bottom: 210,\n            })\n\n            parent.setTarget({\n                left: 300,\n                right: 350,\n                top: 300,\n                bottom: 700,\n            })\n\n            grandChild.setTarget(target)\n\n            requestAnimationFrame(() => {\n                grandChild.setTarget(target)\n\n                requestAnimationFrame(() => {\n                    grandChild.setTarget(target)\n\n                    requestAnimationFrame(() => {\n                        resolve(updateCount)\n                    })\n                })\n            })\n        })\n\n        return expect(promise).resolves.toBe(1)\n    })\n})\n"
  },
  {
    "path": "packages/projection/src/dom/correct-border-radius.ts",
    "content": "import { Axis } from \"../geometry/types\"\nimport { LayoutNode } from \"../types\"\n\nexport function pixelsToPercent(pixels: number, axis: Axis): number {\n    return (pixels / (axis.max - axis.min)) * 100\n}\n\n/**\n * We always correct borderRadius as a percentage rather than pixels to reduce paints.\n * For example, if you are projecting a box that is 100px wide with a 10px borderRadius\n * into a box that is 200px wide with a 20px borderRadius, that is actually a 10%\n * borderRadius in both states. If we animate between the two in pixels that will trigger\n * a paint each time. If we animate between the two in percentage we'll avoid a paint.\n *\n * Currently accepts a single value for all border radius rather than space-delimited.\n */\nexport function correctBorderRadius(latest: string | number, node: LayoutNode) {\n    /**\n     * If latest is a string, if it's a percentage we can return immediately as it's\n     * going to be stretched appropriately. Otherwise, if it's a pixel, convert it to a number.\n     */\n    if (typeof latest === \"string\") {\n        if (latest.endsWith(\"px\")) {\n            latest = parseFloat(latest)\n        } else {\n            return latest\n        }\n    }\n\n    /**\n     * If latest is a number, it's a pixel value. We use the current viewportBox to calculate that\n     * pixel value as a percentage of each axis\n     */\n    const { x, y } = node.getTarget()\n    return `${pixelsToPercent(latest, x)}% ${pixelsToPercent(latest, y)}%`\n}\n"
  },
  {
    "path": "packages/projection/src/dom/correct-box-shadow.ts",
    "content": "import { LayoutNode } from \"../types\"\nimport { complex } from \"style-value-types\"\nimport { mix } from \"popmotion\"\n\n/**\n * TODO: This is doubled up with Framer Motion\n */\nconst cssVariableRegex = /var\\((--[a-zA-Z0-9-_]+),? ?([a-zA-Z0-9 ()%#.,-]+)?\\)/\n\nconst varToken = \"_$css\"\n\n/**\n * Note: Currently only supports single shadows\n */\nexport function correctBoxShadow(latest: string, node: LayoutNode) {\n    const original = latest\n\n    /**\n     * We need to first strip and store CSS variables from the string.\n     */\n    const containsCSSVariables = latest.includes(\"var(\")\n    const cssVariables: string[] = []\n    if (containsCSSVariables) {\n        latest = latest.replace(cssVariableRegex, (match) => {\n            cssVariables.push(match)\n            return varToken\n        })\n    }\n\n    const shadow = complex.parse(latest)\n\n    // TODO: Doesn't support multiple shadows\n    if (shadow.length > 5) return original\n\n    const template = complex.createTransformer(latest)\n    const offset = typeof shadow[0] !== \"number\" ? 1 : 0\n\n    /**\n     * TODO: Maybe replace with getters\n     */\n    const projection = node.projection\n    const treeScale = node.treeScale\n\n    // Calculate the overall context scale\n    const xScale = projection.x.scale * treeScale.x\n    const yScale = projection.y.scale * treeScale.y\n\n    // Scale x/y\n    ;(shadow[0 + offset] as number) /= xScale\n    ;(shadow[1 + offset] as number) /= yScale\n\n    /**\n     * Ideally we'd correct x and y scales individually, but because blur and\n     * spread apply to both we have to take a scale average and apply that instead.\n     * We could potentially improve the outcome of this by incorporating the ratio between\n     * the two scales.\n     */\n    const averageScale = mix(xScale, yScale, 0.5)\n\n    // Blur\n    if (typeof shadow[2 + offset] === \"number\")\n        (shadow[2 + offset] as number) /= averageScale\n\n    // Spread\n    if (typeof shadow[3 + offset] === \"number\")\n        (shadow[3 + offset] as number) /= averageScale\n\n    let output = template(shadow)\n\n    if (containsCSSVariables) {\n        let i = 0\n        output = output.replace(varToken, () => {\n            const cssVariable = cssVariables[i]\n            i++\n            return cssVariable\n        })\n    }\n\n    return output\n}\n"
  },
  {
    "path": "packages/projection/src/dom/style.ts",
    "content": "import { LayoutNode } from \"../types\"\n\nexport function updateProjectionStyle(\n    element: HTMLElement,\n    { projection, treeScale }: LayoutNode\n) {\n    const { x, y } = projection\n    const xTranslate = x.translate / treeScale.x\n    const yTranslate = y.translate / treeScale.y\n    element.style.transformOrigin = `${x.origin * 100}% ${y.origin * 100}% 0`\n    element.style.transform = `translate3d(${xTranslate}px, ${yTranslate}px, 0) scale(${x.scale}, ${y.scale})`\n}\n"
  },
  {
    "path": "packages/projection/src/geometry/__tests__/apply.test.ts",
    "content": "import {\n    applyAxisProjection,\n    applyPointProjection,\n    resetAxis,\n    resetBox,\n    scalePoint,\n} from \"../apply\"\n\ndescribe(\"resetAxis\", () => {\n    test(\"resets axis a using the values in axis b\", () => {\n        const a = { min: 0, max: 0 }\n        const b = { min: 1, max: 2 }\n        resetAxis(a, b)\n        expect(a).toEqual(b)\n    })\n})\n\ndescribe(\"resetBox\", () => {\n    test(\"reset box a using the values in axis b\", () => {\n        const a = {\n            x: { min: 0, max: 0 },\n            y: { min: 0, max: 0 },\n        }\n        const b = {\n            x: { min: 1, max: 2 },\n            y: { min: 3, max: 4 },\n        }\n        resetBox(a, b)\n        expect(a).toEqual(b)\n    })\n})\n\ndescribe(\"scalePoint\", () => {\n    test(\"correctly scales a point based on a factor and an originPoint\", () => {\n        expect(scalePoint(100, 2, 50)).toBe(150)\n        expect(scalePoint(100, 0.5, 50)).toBe(75)\n        expect(scalePoint(100, 2, 150)).toBe(50)\n        expect(scalePoint(100, 0.5, 150)).toBe(125)\n    })\n})\n\ndescribe(\"applyPointProjection\", () => {\n    test(\"correctly applies a delta to a point\", () => {\n        expect(applyPointProjection(100, 100, 2, 50)).toBe(250)\n        expect(applyPointProjection(100, 100, 2, 150)).toBe(150)\n    })\n\n    test(\"correctly applies a delta to a point with an additional boxScale\", () => {\n        expect(applyPointProjection(100, 100, 2, 50, 2)).toBe(350)\n        expect(applyPointProjection(100, 100, 2, 150, 2)).toBe(50)\n    })\n})\n\ndescribe(\"applyAxisProjection\", () => {\n    test(\"correctly applies a delta to an axis\", () => {\n        const axis = { min: 100, max: 200 }\n        applyAxisProjection(axis, 100, 2, 150)\n        expect(axis).toEqual({ min: 150, max: 350 })\n    })\n\n    test(\"correctly applies a delta to an axis with an additional boxScale\", () => {\n        const axis = { min: 100, max: 200 }\n        applyAxisProjection(axis, 100, 2, 150, 2)\n        expect(axis).toEqual({ min: 50, max: 450 })\n    })\n})\n\n// describe(\"applyAxisTransforms\", () => {\n//     test(\"correctly applies transforms to an axis\", () => {\n//         const target = { min: 0, max: 0 }\n//         const axis = { min: 100, max: 200 }\n//         applyAxisTransforms(\n//             target,\n//             axis,\n//             {\n//                 x: 100,\n//                 scaleX: 2,\n//                 originX: -0.5,\n//             },\n//             [\"x\", \"scaleX\", \"originX\"]\n//         )\n//         expect(target).toEqual({ min: 250, max: 450 })\n//     })\n\n//     test(\"correctly applies transforms with missing scale\", () => {\n//         const target = { min: 0, max: 0 }\n//         const axis = { min: 100, max: 200 }\n//         applyAxisTransforms(target, axis, { x: 100, originX: -0.5 }, [\n//             \"x\",\n//             \"scaleX\",\n//             \"originX\",\n//         ])\n//         expect(target).toEqual({ min: 200, max: 300 })\n//     })\n// })\n\n// describe(\"applyBoxTransform\", () => {\n//     test(\"correctly applies a transform to a box\", () => {\n//         const target = {\n//             x: { min: 0, max: 0 },\n//             y: { min: 0, max: 0 },\n//         }\n\n//         const box = {\n//             x: { min: 100, max: 200 },\n//             y: { min: 300, max: 400 },\n//         }\n\n//         applyBoxTransforms(target, box, {\n//             x: 100,\n//             y: 200,\n//             scaleX: 2,\n//             scaleY: 0.5,\n//             scale: 2,\n//         })\n\n//         expect(target).toEqual({\n//             x: { min: 50, max: 450 },\n//             y: { min: 500, max: 600 },\n//         })\n//     })\n// })\n\n// describe(\"removePointDelta\", () => {\n//     test(\"correctly removes a delta from a point\", () => {\n//         expect(removePointDelta(250, 100, 2, 50)).toBe(100)\n//     })\n//     test(\"correctly removes a delta from a point with an additional boxScale\", () => {\n//         expect(removePointDelta(350, 100, 2, 50, 2)).toBe(100)\n//     })\n// })\n\n// describe(\"removeAxisDelta\", () => {\n//     test(\"correctly removes a delta from an axis\", () => {\n//         const axis = { min: 150, max: 350 }\n//         removeAxisDelta(axis, 100, 2, 0.5)\n//         expect(axis).toEqual({ min: 100, max: 200 })\n//     })\n\n//     test(\"correctly removes a delta from an axis with an additional boxScale\", () => {\n//         const axis = { min: 50, max: 450 }\n//         removeAxisDelta(axis, 100, 2, 0.5, 2)\n//         expect(axis).toEqual({ min: 100, max: 200 })\n//     })\n// })\n\n// describe(\"removeAxisTransforms\", () => {\n//     test(\"correctly removes transforms from an axis\", () => {\n//         const axis = { min: 250, max: 450 }\n//         removeAxisTransforms(\n//             axis,\n//             {\n//                 x: 100,\n//                 scaleX: 2,\n//                 originX: -0.5,\n//             },\n//             [\"x\", \"scaleX\", \"originX\"]\n//         )\n//         expect(axis).toEqual({ min: 100, max: 200 })\n//     })\n// })\n\n// describe(\"removeBoxTransforms\", () => {\n//     const box = {\n//         x: { min: 50, max: 450 },\n//         y: { min: 500, max: 600 },\n//     }\n\n//     removeBoxTransforms(box, {\n//         x: 100,\n//         y: 200,\n//         scaleX: 2,\n//         scaleY: 0.5,\n//         scale: 2,\n//     })\n\n//     expect(box).toEqual({\n//         x: { min: 100, max: 200 },\n//         y: { min: 300, max: 400 },\n//     })\n// })\n"
  },
  {
    "path": "packages/projection/src/geometry/__tests__/calc.test.ts",
    "content": "import { box } from \"..\"\nimport {\n    isNear,\n    calcOrigin,\n    updateAxisProjection,\n    calcRelativeAxis,\n} from \"../calc\"\n\ndescribe(\"isNear\", () => {\n    test(\"Correctly indicate when the provided value is within maxDistance of the provided target\", () => {\n        expect(isNear(10.1, 10, 0.1)).toBe(true)\n        expect(isNear(9.9, 10, 0.1)).toBe(true)\n        expect(isNear(10.2, 10, 0.1)).toBe(false)\n        expect(isNear(9.8, 10, 0.1)).toBe(false)\n    })\n})\n\ndescribe(\"calcOrigin\", () => {\n    test(\"Correctly calculates an origin \", () => {\n        expect(calcOrigin({ min: 0, max: 100 }, { min: 0, max: 100 })).toBe(0.5)\n        expect(calcOrigin({ min: -100, max: 100 }, { min: -50, max: 50 })).toBe(\n            0.5\n        )\n        expect(calcOrigin({ min: -50, max: 50 }, { min: -100, max: 100 })).toBe(\n            0.5\n        )\n        expect(calcOrigin({ min: 200, max: 200 }, { min: 0, max: 100 })).toBe(1)\n        expect(calcOrigin({ min: 200, max: 200 }, { min: 300, max: 500 })).toBe(\n            0\n        )\n    })\n})\n\ndescribe(\"updateAxisProjection\", () => {\n    test(\"Correctly updates the axis delta with a delta that will, when applied, project source onto delta\", () => {\n        const axisDelta = { scale: 1, translate: 0, origin: 0, originPoint: 0 }\n        updateAxisProjection(\n            axisDelta,\n            { min: 100, max: 200 },\n            { min: 300, max: 500 }\n        )\n        expect(axisDelta).toEqual({\n            origin: 0,\n            originPoint: 100,\n            scale: 2,\n            translate: 200,\n        })\n    })\n    test(\"Correctly updates the axis delta with a delta that will, when applied, project source onto delta with a defined origin\", () => {\n        const axisDelta = { scale: 1, translate: 0, origin: 0, originPoint: 0 }\n        updateAxisProjection(\n            axisDelta,\n            { min: 100, max: 200 },\n            { min: 300, max: 500 },\n            1\n        )\n        expect(axisDelta).toEqual({\n            origin: 1,\n            originPoint: 200,\n            scale: 2,\n            translate: 300,\n        })\n    })\n})\n\ndescribe(\"calcRelativeAxis\", () => {\n    test(\"Correctly calculates an axis relative to the parent target\", () => {\n        const target = box()\n        calcRelativeAxis(\n            target.x,\n            { min: 100, max: 200 },\n            { min: 10 },\n            { min: 600, max: 800 }\n        )\n\n        expect(target.x).toEqual({ min: 110, max: 310 })\n    })\n})\n"
  },
  {
    "path": "packages/projection/src/geometry/apply.ts",
    "content": "import { LayoutNode } from \"../types\"\nimport { Axis, Box, Point, Projection } from \"./types\"\n\nexport function resetAxis(axis: Axis, originAxis: Axis) {\n    axis.min = originAxis.min\n    axis.max = originAxis.max\n}\n\nexport function resetBox(box: Box, originBox: Box) {\n    resetAxis(box.x, originBox.x)\n    resetAxis(box.y, originBox.y)\n}\n\n/**\n * Scales a point based on a factor and an originPoint\n */\nexport function scalePoint(point: number, scale: number, originPoint: number) {\n    const distanceFromOrigin = point - originPoint\n    const scaled = scale * distanceFromOrigin\n    return originPoint + scaled\n}\n\n/**\n * Applies a translate/scale delta to a point\n */\nexport function applyPointProjection(\n    point: number,\n    translate: number,\n    scale: number,\n    originPoint: number,\n    boxScale?: number\n): number {\n    if (boxScale !== undefined) {\n        point = scalePoint(point, boxScale, originPoint)\n    }\n\n    return scalePoint(point, scale, originPoint) + translate\n}\n\n/**\n * Applies a translate/scale delta to an axis\n */\nexport function applyAxisProjection(\n    axis: Axis,\n    translate: number = 0,\n    scale: number = 1,\n    originPoint: number,\n    boxScale?: number\n): void {\n    axis.min = applyPointProjection(\n        axis.min,\n        translate,\n        scale,\n        originPoint,\n        boxScale\n    )\n\n    axis.max = applyPointProjection(\n        axis.max,\n        translate,\n        scale,\n        originPoint,\n        boxScale\n    )\n}\n\n/**\n * Applies a translate/scale delta to a box\n */\nexport function applyBoxProjection(box: Box, { x, y }: Projection): void {\n    applyAxisProjection(box.x, x.translate, x.scale, x.originPoint)\n    applyAxisProjection(box.y, y.translate, y.scale, y.originPoint)\n}\n\n/**\n * Apply a tree of deltas to a box. We do this to calculate the effect of all the transforms\n * in a tree upon our box before then calculating how to project it into our desired viewport-relative box\n */\nexport function applyTreeProjection(\n    box: Box,\n    treeScale: Point,\n    path: LayoutNode[]\n) {\n    const pathLength = path.length\n    if (!pathLength) return\n\n    // Reset the treeScale\n    treeScale.x = treeScale.y = 1\n\n    /**\n     * TODO: We already traverse the tree from top-down. Look into whether it's possible to do this\n     * work culmulatively.\n     */\n    for (let i = 0; i < pathLength; i++) {\n        const { projection } = path[i]\n\n        // Incoporate each ancestor's scale into a culmulative treeScale for this component\n        treeScale.x *= projection.x.scale\n        treeScale.y *= projection.y.scale\n\n        // Apply each ancestor's calculated projection into this component's recorded layout box\n        applyBoxProjection(box, projection)\n    }\n}\n"
  },
  {
    "path": "packages/projection/src/geometry/calc.ts",
    "content": "import { Axis, AxisProjection, Box, Projection, RelativeBox } from \"./types\"\nimport { clamp, mix, progress } from \"popmotion\"\n\n/**\n * Returns true if the provided value is within maxDistance of the provided target\n */\nexport function isNear(value: number, target = 0, maxDistance = 0.01): boolean {\n    return Math.abs(value - target) < maxDistance\n}\n\nfunction calcLength(axis: Axis) {\n    return axis.max - axis.min\n}\n\n/**\n * Calculate a transform origin relative to the source axis, between 0-1, that results\n * in an asthetically pleasing scale/transform needed to project from source to target.\n */\nexport function calcOrigin(source: Axis, target: Axis): number {\n    let origin = 0.5\n    const sourceLength = calcLength(source)\n    const targetLength = calcLength(target)\n\n    if (targetLength > sourceLength) {\n        origin = progress(target.min, target.max - sourceLength, source.min)\n    } else if (sourceLength > targetLength) {\n        origin = progress(source.min, source.max - targetLength, target.min)\n    }\n\n    return clamp(0, 1, origin)\n}\n\n/**\n * Update the AxisDelta with a transform that projects source into target.\n *\n * The transform `origin` is optional. If not provided, it'll be automatically\n * calculated based on the relative positions of the two bounding boxes.\n */\nexport function updateAxisProjection(\n    projection: AxisProjection,\n    source: Axis,\n    target: Axis,\n    origin?: number\n) {\n    projection.origin =\n        origin === undefined ? calcOrigin(source, target) : origin\n    projection.originPoint = mix(source.min, source.max, projection.origin)\n\n    projection.scale = calcLength(target) / calcLength(source)\n    if (isNear(projection.scale, 1, 0.0001)) projection.scale = 1\n\n    projection.translate =\n        mix(target.min, target.max, projection.origin) - projection.originPoint\n    if (isNear(projection.translate)) projection.translate = 0\n}\n\n/**\n * Update the projection with a transform that projects the source into the target.\n *\n * The transform `origin` is optional. If not provided, it'll be automatically\n * calculated based on the relative positions of the two bounding boxes.\n */\nexport function updateBoxProjection(\n    projection: Projection,\n    source: Box,\n    target: Box,\n    origin?: number\n): void {\n    updateAxisProjection(projection.x, source.x, target.x, origin)\n    updateAxisProjection(projection.y, source.y, target.y, origin)\n}\n\nexport function calcRelativeAxis(\n    target: Axis,\n    parent: Axis,\n    relative: Partial<Axis>,\n    layout: Axis\n) {\n    target.min = parent.min + relative.min\n    target.max = target.min + (layout.max - layout.min)\n}\n\nexport function calcRelativeBox(\n    target: Box,\n    parent: Box,\n    relative: RelativeBox,\n    layout: Box\n) {\n    calcRelativeAxis(target.x, parent.x, relative.x, layout.x)\n    calcRelativeAxis(target.y, parent.y, relative.y, layout.y)\n}\n"
  },
  {
    "path": "packages/projection/src/geometry/index.ts",
    "content": "import { BoundingBox, Box, Projection } from \"./types\"\n\nconst identityProjection = () => ({\n    translate: 0,\n    scale: 1,\n    origin: 0,\n    originPoint: 0,\n})\n\nexport const projection = (): Projection => ({\n    x: identityProjection(),\n    y: identityProjection(),\n})\n\nexport const box = (): Box => ({\n    x: { min: 0, max: 0 },\n    y: { min: 0, max: 0 },\n})\n\nexport const convertBoundingBox = ({\n    top,\n    left,\n    right,\n    bottom,\n}: BoundingBox): Box => ({\n    x: { min: left, max: right },\n    y: { min: top, max: bottom },\n})\n"
  },
  {
    "path": "packages/projection/src/geometry/types.ts",
    "content": "export interface Axis {\n    min: number\n    max: number\n    length?: number\n}\n\nexport interface Box {\n    x: Axis\n    y: Axis\n}\n\nexport interface RelativeBox {\n    x: Partial<Axis>\n    y: Partial<Axis>\n}\n\nexport interface BoundingBox {\n    top: number\n    right: number\n    bottom: number\n    left: number\n}\n\nexport interface Point {\n    x: number\n    y: number\n}\n\nexport interface AxisProjection {\n    translate: number\n    scale: number\n    origin: number\n    originPoint: number\n}\n\nexport interface Projection {\n    x: AxisProjection\n    y: AxisProjection\n}\n"
  },
  {
    "path": "packages/projection/src/index.ts",
    "content": "export { LayoutNode } from \"./types\"\nexport { layoutNode } from \"./node\"\nexport { updateProjectionStyle } from \"./dom/style\"\nexport { correctBorderRadius } from \"./dom/correct-border-radius\"\nexport { correctBoxShadow } from \"./dom/correct-box-shadow\"\n"
  },
  {
    "path": "packages/projection/src/node.ts",
    "content": "import { LayoutNode, NodeOptions } from \"./types\"\nimport sync, { cancelSync } from \"framesync\"\nimport { applyTreeProjection, resetBox } from \"./geometry/apply\"\nimport { calcRelativeBox, updateBoxProjection } from \"./geometry/calc\"\nimport { BoundingBox, Box, RelativeBox } from \"./geometry/types\"\nimport { box, convertBoundingBox, projection } from \"./geometry\"\n\nexport function layoutNode(\n    { onLayoutMeasure, onProjectionUpdate }: NodeOptions = {},\n    parent?: LayoutNode\n): LayoutNode {\n    /**\n     *\n     */\n    let layout: Box\n\n    /**\n     *\n     */\n    let layoutCorrected: Box\n\n    /**\n     *\n     */\n    let target: Box\n\n    /**\n     *\n     */\n    let relativeTarget: RelativeBox\n\n    /**\n     *\n     */\n    let projectionString = \"\"\n\n    /**\n     *\n     */\n    let resolveRelativeToParent = false\n\n    /**\n     *\n     */\n    let relativeParent = parent\n\n    /**\n     *\n     */\n    function setBoundingBoxToTarget(\n        target: Box | RelativeBox,\n        { left, right, top, bottom }: Partial<BoundingBox>\n    ) {\n        target.x.min = left\n        target.x.max = right\n        target.y.min = top\n        target.y.max = bottom\n        node.scheduleUpdateProjection()\n    }\n\n    function updateTreeProjection() {\n        node.treeNodes.forEach(fireUpdateProjection)\n    }\n\n    const node: LayoutNode = {\n        parent,\n\n        treeNodes: parent ? parent.treeNodes : new Set<LayoutNode>(),\n\n        path: parent ? [...parent.path, parent] : [],\n\n        depth: parent ? parent.depth + 1 : 0,\n\n        projection: projection(),\n\n        treeScale: { x: 1, y: 1 },\n\n        /**\n         *\n         */\n        scheduleUpdateProjection: parent\n            ? parent.scheduleUpdateProjection\n            : () => sync.preRender(updateTreeProjection, false, true),\n\n        /**\n         *\n         */\n        updateProjection() {\n            resetBox(layoutCorrected, layout)\n\n            const prevProjectionString = projectionString\n            const { x: prevTreeScaleX, y: prevTreeScaleY } = node.treeScale\n\n            /**\n             * Apply all the parent deltas to this box to produce the corrected box. This\n             * is the layout box, as it will appear on screen as a result of the transforms of its parents.\n             */\n            applyTreeProjection(layoutCorrected, node.treeScale, node.path)\n\n            /**\n             *\n             */\n            if (resolveRelativeToParent) {\n                calcRelativeBox(\n                    target,\n                    relativeParent.getTarget(),\n                    relativeTarget,\n                    layout\n                )\n            }\n\n            /**\n             * Update the delta between the corrected box and the target box before user-set transforms were applied.\n             * This will allow us to calculate the corrected borderRadius and boxShadow to compensate\n             * for our layout reprojection, but still allow them to be scaled correctly by the user.\n             * It might be that to simplify this we may want to accept that user-set scale is also corrected\n             * and we wouldn't have to keep and calc both deltas, OR we could support a user setting\n             * to allow people to choose whether these styles are corrected based on just the\n             * layout reprojection or the final bounding box.\n             */\n            updateBoxProjection(node.projection, layoutCorrected, target, 0.5)\n\n            projectionString = JSON.stringify(node.projection)\n\n            if (\n                prevProjectionString !== projectionString ||\n                // Also compare calculated treeScale, for values that rely on only this for scale correction.\n                prevTreeScaleX !== node.treeScale.x ||\n                prevTreeScaleY !== node.treeScale.y\n            ) {\n                onProjectionUpdate?.()\n            }\n        },\n\n        /**\n         *\n         */\n        setLayout(newLayout) {\n            layout = convertBoundingBox(newLayout)\n\n            if (!target) {\n                layoutCorrected = box()\n                target = box()\n                relativeTarget = box()\n            }\n\n            // TODO: Might need to rebase target box here if not animating\n        },\n\n        invalidateLayout() {},\n\n        /**\n         * This will only provide accurate measurements if projection transform\n         * and all parent transforms have been temporarily disabled.\n         */\n        measureLayout() {\n            node.setLayout(element.getBoundingClientRect())\n            onLayoutMeasure?.(layout)\n        },\n\n        /**\n         *\n         */\n        setTarget(newTarget) {\n            resolveRelativeToParent = false\n            setBoundingBoxToTarget(target, newTarget)\n        },\n\n        /**\n         *\n         */\n        getTarget() {\n            return target\n        },\n\n        /**\n         *\n         */\n        setRelativeTarget(newTarget) {\n            resolveRelativeToParent = true\n            setBoundingBoxToTarget(relativeTarget, newTarget)\n        },\n\n        setRelativeParent(newRelativeParent: LayoutNode) {\n            // TODO: Check that this is in the path\n            relativeParent = newRelativeParent\n        },\n\n        /**\n         *\n         */\n        destroy() {\n            node.treeNodes.delete(node)\n            cancelSync.preRender(node.updateProjection)\n        },\n    }\n\n    node.treeNodes.add(node)\n\n    return node\n}\n\nfunction fireUpdateProjection(node: LayoutNode) {\n    node.updateProjection()\n}\n"
  },
  {
    "path": "packages/projection/src/types.ts",
    "content": "import { BoundingBox, Box, Point, Projection } from \"./geometry/types\"\n\nexport interface LayoutNode {\n    parent?: LayoutNode\n\n    path: LayoutNode[]\n\n    treeNodes: Set<LayoutNode>\n\n    depth: number\n\n    projection: Projection\n\n    treeScale: Point\n\n    scheduleUpdateProjection(): void\n\n    updateProjection(): void\n\n    setLayout(box: BoundingBox): void\n\n    setTarget(box: BoundingBox): void\n\n    getTarget(): Box\n\n    setRelativeTarget(box: Partial<BoundingBox>): void\n\n    setRelativeParent(parent: LayoutNode): void\n\n    destroy(): void\n}\n\nexport interface NodeOptions {\n    onLayoutMeasure?: (layout: Box) => void\n    onProjectionUpdate?: () => void\n}\n"
  },
  {
    "path": "packages/projection/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"rootDir\": \"src\",\n    \"outDir\": \"lib\"\n  },\n  \"include\": [\"src/**/*\"]\n}"
  },
  {
    "path": "packages/site/.babelrc",
    "content": "// {\n//   \"presets\": [\n//     \"next/babel\",\n//     \"react\",\n//     \"stage-0\"\n//   ],\n//   \"plugins\": [\n//     \"transform-react-remove-prop-types\",\n//     \"transform-export-extensions\",\n//     \"transform-react-jsx\",\n//     \"transform-react-constant-elements\",\n//     \"transform-strict-mode\",\n//     [\"babel-plugin-root-import\"],\n//     [\"transform-runtime\", {\n//       \"helpers\": false,\n//       \"polyfill\": false\n//     }],\n//   ],\n//   \"env\": {\n//     \"development\": {\n//       \"sourceMaps\": \"inline\"\n//     }\n//   }\n// }\n{\n  \"presets\": [\"next/babel\"],\n  \"plugins\": [\n    [\"babel-plugin-root-import\"],\n    [\"styled-components\", {\n      \"ssr\": true\n    }]\n  ]\n}"
  },
  {
    "path": "packages/site/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n\n# testing\n/coverage\n\n# next.js\n/.next/\n/out/\n\n# production\n/build\n\n# misc\n.DS_Store\n.env*\n\n# debug\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n"
  },
  {
    "path": "packages/site/components/examples/Ball.js",
    "content": "import styled from 'styled-components';\nimport { ActionButton } from '~/templates/global/styled';\nimport { verticalGradient, PINK, PINK_BURN, cols } from '~/styles/vars';\n\nconst Container = styled.div`\n  height: 100%;\n  width: 100%;\n  display: flex;\n  flex-direction: column;\n  justify-content: space-around;\n  align-content: space-around;\n  padding: ${cols(1)};\n`;\n\nconst Box = styled.span`\n  width: 50px;\n  height: 50px;\n  background: ${verticalGradient(PINK, PINK_BURN)};\n  border-radius: 50px;\n`;\n\nexport default ({ autostart, start, id }) => (\n  <Container id={id} ref={autostart ? start : null}>\n    <Box className=\"ball\" />\n    {!autostart ? <ActionButton onClick={start}>Start</ActionButton> : null}\n  </Container>\n);\n"
  },
  {
    "path": "packages/site/components/examples/CodePen.js",
    "content": "import { Centered } from '~/templates/global/grid';\nimport { cols, LIGHT_GREY } from '~/styles/vars';\nimport styled from 'styled-components';\n\nconst FrameContainer = styled(Centered.withComponent('div'))`\n  margin-top: ${cols(2)};\n  margin-bottom: ${cols(2)};\n  border: 2px solid ${LIGHT_GREY};\n`;\n\nexport default ({ id, height = 447 }) => (\n  <FrameContainer>\n    <iframe\n      height={height}\n      scrolling=\"no\"\n      title=\"\"\n      src={`https://codepen.io/popmotion/embed/${id}/?height=${height}&theme-id=17364&default-tab=result&embed-version=2`}\n      frameBorder=\"no\"\n      allowTransparency=\"true\"\n      allowFullScreen=\"true\"\n      style={{ width: '100%' }}\n    />\n  </FrameContainer>\n);\n"
  },
  {
    "path": "packages/site/components/examples/CodeSandbox.js",
    "content": "import React from 'react';\nimport styled from 'styled-components';\nimport { MajorCentered } from '~/templates/global/grid';\nimport { cols } from '~/styles/vars';\nimport { IntersectionElement } from 'react-intersection';\n\nconst FrameContainer = styled(MajorCentered.withComponent('div'))`\n  margin-top: ${cols(2)};\n  margin-bottom: ${cols(2)};\n`;\n\nexport default class CodeSandbox extends React.Component {\n  state = { isVisible: false };\n\n  setVisibility = ({ isIntersecting }) => {\n    isIntersecting &&\n      !this.state.isVisible &&\n      this.setState({ isVisible: true });\n  };\n\n  render() {\n    const { id, height = 500, vue = false, ...props } = this.props;\n    const suffix = vue ? '?module=%2Fsrc%2FApp.vue' : '';\n\n    return (\n      <IntersectionElement onChange={this.setVisibility}>\n        <FrameContainer style={{ height: height + 'px' }}>\n          {this.state.isVisible && (\n            <iframe\n              height={height}\n              scrolling=\"no\"\n              title=\"\"\n              src={`https://codesandbox.io/embed/${id}${suffix}`}\n              frameBorder=\"no\"\n              allowtransparency=\"true\"\n              allowfullScreen=\"true\"\n              style={{ width: '100%' }}\n              {...props}\n            />\n          )}\n        </FrameContainer>\n      </IntersectionElement>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/site/components/examples/Counter.js",
    "content": "import styled from 'styled-components';\nimport { ActionButton } from '~/templates/global/styled';\nimport { fontBold } from '~/styles/fonts';\n\nconst CounterContainer = styled.div`\n  height: 100%;\n  display: flex;\n  flex-direction: column;\n  justify-content: space-around;\n  align-content: space-around;\n`;\nconst Counter = styled.span`\n  font-size: 42px;\n  text-align: center;\n  ${fontBold}\n`;\n\nexport default ({ code, autostart, start, id }) => (\n  <CounterContainer id={id} ref={autostart ? start : null}>\n    <Counter className=\"counter\">0</Counter>\n    {!autostart ? <ActionButton onClick={start}>Start</ActionButton> : null}\n  </CounterContainer>\n);\n"
  },
  {
    "path": "packages/site/components/examples/Example.js",
    "content": "import React from 'react';\n\nexport default () => {\n  return <div>Live demos of legacy libraries have been removed.</div>;\n\n  // const Component = templates[template];\n\n  // return (\n  //   <StyledLiveContainer\n  //     transformCode={isReactComponent ? undefined : injectRender}\n  //     code={stripFirstReturn(children)}\n  //     scope={{\n  //       action,\n  //       value,\n  //       decay,\n  //       keyframes,\n  //       physics,\n  //       spring,\n  //       tween,\n  //       listen,\n  //       pointer,\n  //       mouse,\n  //       multitouch,\n  //       multicast,\n  //       composite,\n  //       parallel,\n  //       calc,\n  //       easing,\n  //       transform,\n  //       styler,\n  //       Component,\n  //       id,\n  //       autostart\n  //     }}\n  //     mountStylesheet={false}\n  //     noInline={!isReactComponent}\n  //   >\n  //     <StyledLivePreview />\n  //     <CodeContainer>\n  //       <LiveEditorWrapper>\n  //         <LiveEditorHeader>Live editor</LiveEditorHeader>\n  //         <LiveEditor />\n  //       </LiveEditorWrapper>\n  //     </CodeContainer>\n  //   </StyledLiveContainer>\n  // );\n};\n"
  },
  {
    "path": "packages/site/components/examples/Swatch.js",
    "content": "import styled from 'styled-components';\nimport { ActionButton } from '~/templates/global/styled';\n\nconst Container = styled.div`\n  height: 100%;\n  display: flex;\n  flex-direction: column;\n  justify-content: space-around;\n  align-content: space-around;\n`;\nconst Swatch = styled.div`\n  flex: 0 0 30%;\n`;\n\nexport default ({ start, id }) => (\n  <Container id={id}>\n    <Swatch className=\"swatch\" />\n    <ActionButton onClick={start}>Start</ActionButton>\n  </Container>\n);\n"
  },
  {
    "path": "packages/site/components/examples/templates.js",
    "content": "import Counter from './Counter';\nimport Ball from './Ball';\nimport Swatch from './Swatch';\n\nexport default {\n  Counter,\n  Ball,\n  Swatch\n};\n"
  },
  {
    "path": "packages/site/components/icons/BrandGradientDef.js",
    "content": "import { BRAND, BRAND_BURN } from '~/styles/vars';\n\nexport default ({ id }) => (\n  <defs>\n    <linearGradient x1=\"50%\" y1=\"0%\" x2=\"50%\" y2=\"100%\" id={id}>\n      <stop stopColor=\"#FF1C68\" offset=\"20%\" />\n      <stop stopColor=\"#810066\" offset=\"100%\" />\n    </linearGradient>\n  </defs>\n);\n"
  },
  {
    "path": "packages/site/components/icons/DropDownArrow.js",
    "content": "import { ENTITY } from '~/styles/vars';\n\nexport default ({ color = ENTITY, className }) => (\n  <svg width=\"10px\" height=\"7px\" viewBox=\"0 0 10 7\" className={className}>\n    <g id=\"Page-1\" stroke=\"none\" strokeWidth=\"1\" fill=\"none\" fillRule=\"evenodd\">\n      <polygon fill={color} points=\"5 6.66 0 0 10 0\" />\n    </g>\n  </svg>\n);\n"
  },
  {
    "path": "packages/site/components/icons/FramesyncLogo.js",
    "content": "export default ({ width = 195, height = 46 }) => (\n  <svg\n    width={width}\n    height={height}\n    viewBox=\"0 0 195 46\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n  >\n    <defs>\n      <path\n        d=\"M3 19.5l.6-6.2h2.9l.2-2.5C7.1 7 10 3 16.2 3H18l-.6 5.5c-2.5 0-3.8 1-4 2.9l-.3 2H17l-.6 6h-3.8l-1.5 14.3H4.3l1.5-14.2H3zm30-6l-.8 6.6s-1.7-.7-3.8-.7c-2.3 0-4.3 1-4.7 5.7l-1 8.6H16l2-20.4h6.3v2.5s2.2-2.8 5.4-2.8c1.7 0 3.1.4 3.1.4zm21.9-.2l-2.2 20.4h-6.2v-2.2s-1.8 2.6-5.8 2.6c-4.7 0-8.4-3.9-8.4-9.5C32.3 17.7 37.5 13 43 13c4 0 5.2 2.5 5.2 2.5l.4-2H55zm-11.7 5.8a4.9 4.9 0 0 0-4.8 5c0 2.1 1.4 3.9 3.9 3.9 2.6 0 3.9-2 3.9-2l.5-4.9s-.9-2-3.5-2zm17-3.6zm13.6 0S77 13 80.4 13c4.5 0 6.6 2.5 6.6 6.7v1.6l-1.4 12.4H79l1-11.6v-.9c0-1.4-.7-2-1.8-2-1.7 0-3.3 1.6-3.3 1.6l-1.3 13h-6.8l1.3-12.1V21c0-1.2-.6-1.8-1.8-1.8-1.6 0-3.4 1.5-3.4 1.5l-1.3 13h-6.8L57 13.3h6.4l.1 2s2.8-2.3 6-2.3c3.3 0 4.3 2.5 4.3 2.5zm35 10H94.9c.3 1.6 1.9 3 4.5 3 4 0 7.6-1.3 7.6-1.3l-.6 5.4S103 34 98 34c-6 .1-10-4-10-9.3 0-7.1 5.7-11.8 12.4-11.8 6.3 0 9 4.6 9 8.9 0 2-.6 3.7-.5 3.7zm-8.8-7.3c-2.1 0-4 1.6-4.7 3.4h8.4c0-1.6-1.4-3.4-3.7-3.4zm27.3-4l-.6 5.8s-3.3-1.7-7.1-1.7c-1.3 0-2 .5-2 1.2 0 2.1 10 .9 10 7.3 0 4-3.7 7.3-10.4 7.3-4.5 0-7.8-1.8-7.8-1.8l.6-5.8s3.8 2.3 7.8 2.3c1.2 0 2.7-.2 2.7-1.3 0-2.1-10-.8-10-7.4 0-4.5 4.5-7.2 9.5-7.2 4.3 0 7.3 1.4 7.3 1.4zm18.4-.9h7l-16 29H130l5.6-10.2-6.6-18.8h7.4l3.3 11.7 6-11.7zm27.2 8.3l-1.2 12.1h-6.8l1.2-11.3v-.9c0-1.4-.7-2.5-2.4-2.5-2.3 0-4.1 1.9-4.1 1.9l-1.4 12.8h-6.7l2-20.4h6.6v2.2s2.7-2.6 6-2.6c3.7 0 6.9 2.4 6.9 7.3v1.4zm18.5-7.2l-.7 6.4s-2.2-1.5-5.1-1.5c-3.2 0-5.3 2.4-5.3 4.8 0 2.2 1.6 4 4.4 4a10 10 0 0 0 5.6-1.6l-.7 6.4s-2.7 1.4-6.2 1.4a9.4 9.4 0 0 1-9.8-9.7c0-6.6 5.4-11.5 12-11.5a13 13 0 0 1 5.8 1.3z\"\n        id=\"framesync-path\"\n      />\n      <mask id=\"framesync-clippath\">\n        <path fill=\"#fff\" d=\"M0 0h195v46H0z\" />\n        <use href=\"#framesync-path\" />\n      </mask>\n    </defs>\n    <g mask=\"url(#framesync-clippath)\">\n      <use transform=\"translate(-3 -3)\" href=\"#framesync-path\" fill=\"#FF1C68\" />\n      <use transform=\"translate(3 3)\" href=\"#framesync-path\" fill=\"#00CBFF\" />\n    </g>\n  </svg>\n);\n"
  },
  {
    "path": "packages/site/components/icons/GitHub.js",
    "content": "import { ACTION, ACTION_BURN } from '~/styles/vars';\n\nexport default ({ className }) => (\n  <svg width=\"27\" height=\"26\" viewBox=\"0 0 27 26\" xmlns=\"http://www.w3.org/2000/svg\" className={className}>\n    <defs>\n      <linearGradient x1=\"50%\" y1=\"100%\" x2=\"50%\" y2=\"0%\" id=\"github-gradient\">\n        <stop stopColor={ACTION_BURN} offset=\"0%\"/>\n        <stop stopColor={ACTION} offset=\"100%\"/>\n      </linearGradient>\n    </defs>\n    <path d=\"M0 13.33c0 5.9 3.82 10.88 9.12 12.65.66.12.9-.3.9-.64v-2.5c-3.72.82-4.5-1.56-4.5-1.56-.6-1.54-1.48-1.95-1.48-1.95-1.2-.83.1-.8.1-.8 1.33.1 2.03 1.36 2.03 1.36 1.2 2.03 3.12 1.44 3.88 1.1.12-.86.47-1.45.85-1.78-2.96-.34-6.08-1.48-6.08-6.6 0-1.44.52-2.63 1.38-3.56-.14-.34-.6-1.7.13-3.53 0 0 1.12-.36 3.66 1.36 1.06-.3 2.2-.45 3.33-.45s2.27.15 3.34.44c2.54-1.73 3.66-1.37 3.66-1.37.73 1.83.27 3.2.13 3.53.86.93 1.37 2.12 1.37 3.57 0 5.12-3.12 6.25-6.08 6.58.47.42.9 1.23.9 2.48l-.02 3.66c0 .35.24.77.92.64 5.3-1.77 9.1-6.76 9.1-12.65C26.66 5.97 20.7 0 13.34 0S0 5.97 0 13.33z\" fill=\"url(#github-gradient)\" fillRule=\"nonzero\"/>\n  </svg>\n);\n"
  },
  {
    "path": "packages/site/components/icons/Logo.js",
    "content": "import BrandGradient from './BrandGradientDef';\n\nexport default ({\n  className,\n  id='logo-gradient',\n  pathId,\n  width=165,\n  height=41,\n  ...pathAttrs\n}) => {\n  return (\n    <svg className={className} width={width} height={height} viewBox=\"0 0 200 41\">\n      <BrandGradient id={id} />\n      <path\n        fill={`url(#${id})`}\n        d=\"M15.65.85c6.3 0 9.6 4.17 9.6 9.4 0 5.93-4.3 11.33-11.78 11.33H8.8l-1.04 10.2H.28L3.48.85h12.17zm-5.4 7.03l-.77 7.03h4.26c2.54 0 4.04-1.67 4.04-3.9 0-1.58-1-3.12-3.13-3.12h-4.4zM23.36 21.85c0-7 5.85-12.2 12.8-12.2 5.98 0 10.65 4.4 10.65 10.43 0 7.03-6.02 12.15-12.78 12.15-6.12 0-10.66-4.35-10.66-10.38zm16.28-1.27c0-2.4-1.58-4.4-4.03-4.4-2.85 0-5.03 2.4-5.03 5.2 0 2.33 1.55 4.32 4 4.32 2.9 0 5.07-2.4 5.07-5.12zM55.66 10.1l.1 2.3s1.86-2.75 6.12-2.75c4.94 0 8.8 4.17 8.8 10.25 0 7.03-5.36 12.33-11.02 12.33-3.9 0-5.5-2.35-5.5-2.35l-1.13 10.97h-7.2l3.2-30.75h6.63zm8 10.3c0-2.32-1.55-4.22-4.14-4.22-2.77 0-4.13 2.18-4.13 2.18l-.55 5.12s.9 2.18 3.67 2.18c2.95 0 5.13-2.45 5.13-5.26zM91.18 31.78h-7.2l1.35-12.8c0-.13.05-.4.05-.67 0-1.26-.64-1.98-1.95-1.98-1.68 0-3.54 1.67-3.54 1.67l-1.46 13.78h-7.2L73.5 10.1h6.8l.1 2.18s2.98-2.54 6.3-2.54c3.53 0 4.66 2.63 4.66 2.63s3.27-2.63 6.94-2.63c4.86 0 7.08 2.72 7.08 7.12 0 .54-.05 1.13-.1 1.68l-1.35 13.24H96.7l1.33-12.38c.05-.45.05-.64.05-.9 0-1.5-.77-2.18-1.95-2.18-1.77 0-3.5 1.72-3.5 1.72l-1.45 13.74M106.16 21.85c0-7 5.85-12.2 12.8-12.2 5.98 0 10.65 4.4 10.65 10.43 0 7.03-6.02 12.15-12.78 12.15-6.13 0-10.66-4.35-10.66-10.38zm16.28-1.27c0-2.4-1.6-4.4-4.03-4.4-2.85 0-5.03 2.4-5.03 5.2 0 2.33 1.54 4.32 4 4.32 2.9 0 5.07-2.4 5.07-5.12zM140.4 10.1l.5-4.76h-7.2l-.5 4.76h-3.13l-.68 6.53h3.12l-1.6 15.15h7.23l1.58-15.15h5.18l-1.57 15.15h7.26l2.25-21.68H140.4M146.46.9l-.64 6.16h7.5l.62-6.16h-7.48M153.05 21.85c0-7 5.85-12.2 12.8-12.2 5.97 0 10.65 4.4 10.65 10.43 0 7.03-6.04 12.15-12.8 12.15-6.12 0-10.65-4.35-10.65-10.38zm16.28-1.27c0-2.4-1.6-4.4-4.04-4.4-2.86 0-5.04 2.4-5.04 5.2 0 2.33 1.54 4.32 4 4.32 2.9 0 5.07-2.4 5.07-5.12zM198 31.78h-7.2l1.26-12.02c.05-.4.05-.63.05-.95 0-1.5-.76-2.62-2.62-2.62-2.4 0-4.36 1.95-4.36 1.95l-1.4 13.65h-7.2l2.25-21.68h6.9v2.3s2.9-2.7 6.44-2.7c3.95 0 7.3 2.53 7.3 7.75 0 .4-.04 1-.08 1.5L198 31.77\"\n        id={pathId}\n        {...pathAttrs}\n      />\n    </svg>\n  );\n};\n"
  },
  {
    "path": "packages/site/components/icons/PopcornLogo.js",
    "content": "export default ({ width, height }) => (\n  <svg\n    width={width}\n    height={height}\n    viewBox=\"0 0 846 196\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n  >\n    <defs>\n      <linearGradient id=\"a\" x1=\"50%\" x2=\"50%\" y1=\"0%\" y2=\"96.4%\">\n        <stop offset=\"0%\" stopColor=\"#95FF13\" />\n        <stop offset=\"100%\" stopColor=\"#00CF93\" />\n      </linearGradient>\n      <linearGradient id=\"b\" x1=\"50%\" x2=\"50%\" y1=\"0%\" y2=\"100%\">\n        <stop offset=\"0%\" stopColor=\"#FF1C68\" />\n        <stop offset=\"100%\" stopColor=\"#DB0068\" />\n      </linearGradient>\n    </defs>\n    <g fill=\"none\" fillRule=\"evenodd\">\n      <path\n        fill=\"url(#a)\"\n        d=\"M564.8 107.8a64.5 64.5 0 0 1-62.7 45.7c-31.1 0-54.1-22-54.1-52.6 0-35.5 29.7-61.9 64.9-61.9a52.3 52.3 0 0 1 54 49.5l4.9-47.7h33.8l.2 13.6s11.8-15.4 29-15.4c9.2 0 16.8 2.3 16.8 2.3l-4.1 36.1s-8.8-3.9-20-3.9c-12.5 0-23.3 5.8-25.8 31l-4.8 46.3h-36.6l4.5-43zm-321.6-16l5.3-50.5H282l.4 11.7s9.4-14 31-14c22.8 0 41 17.3 44.2 43.5A63.9 63.9 0 0 1 419.5 39c17.7 0 31 7.4 31 7.4l-3.7 34.5s-11.5-8.6-27.3-8.6c-17.5 0-28.8 13.2-28.8 26.3 0 12 9 21.6 23.7 21.6 19 0 30.4-8.5 30.4-8.5l-3.7 34.5s-14.7 7.3-33.6 7.3c-27.5 0-48.1-18-52-43.5-7.5 25.8-29.8 43.5-53.2 43.5-19.8 0-27.8-12-27.8-12l-5.8 55.7h-36.5l9.6-92.5a64.2 64.2 0 0 1-63.5 48.8c-29.4 0-51.6-19.8-53.8-48-6.2 28.2-29.7 48-54.3 48-19.8 0-27.9-12-27.9-12l-5.7 55.7H0L16.3 41.3H50l.5 11.7s9.4-14 31-14c24 0 42.8 19.3 44.5 47.8A63.9 63.9 0 0 1 189.2 39c30.3 0 54 22.2 54 52.7zm518.5-5.9L755 151h-36.5l6.4-61c.2-2 .2-3.2.2-4.8 0-7.6-3.9-13.3-13.3-13.3-12.2 0-22.1 9.9-22.1 9.9l-7.1 69.2H646l11.5-110h35v11.8S707.2 39 725 39c20 0 37 12.9 37 39.3 0 2.1-.2 5-.4 7.6zM64.4 120.2c15 0 26-12.4 26-26.7 0-11.7-7.8-21.4-21-21.4-14 0-20.9 11-20.9 11l-2.7 26s4.6 11 18.6 11zm116.7.2a26 26 0 0 0 25.8-26c0-12.2-8-22.3-20.5-22.3a26 26 0 0 0-25.5 26.5c0 11.7 7.8 21.8 20.2 21.8zm115.5-.2c14.9 0 26-12.4 26-26.7 0-11.7-7.9-21.4-21-21.4-14 0-21 11-21 11l-2.7 26s4.6 11 18.7 11zm207.6.1a26 26 0 0 0 25.8-26c0-12.2-8-22.3-20.5-22.3A26 26 0 0 0 484 98.5c0 11.7 7.8 21.8 20.2 21.8z\"\n        transform=\"translate(0 -2)\"\n      />\n      <g fill=\"url(#b)\" transform=\"translate(770 -2)\">\n        <path d=\"M37.6 2l-7 69.2h16.8l2.4-23.5h10.5c5.8 0 10.8-1.5 14.8-4A38 38 0 0 1 37.6 79 38 38 0 0 1 0 40.5 38 38 0 0 1 37.6 2.1z\" />\n        <path d=\"M63 16.2c4.7 0 7 3.6 7 7.2 0 5.1-3.4 9-9.1 9h-9.6L53 16.2h10z\" />\n      </g>\n    </g>\n  </svg>\n);\n"
  },
  {
    "path": "packages/site/components/icons/PopmotionIcon.js",
    "content": "import BrandGradient from \"./BrandGradientDef\";\n\nexport default ({ className, width = 41, height = 37 }) => (\n  <svg\n    width={width}\n    height={height}\n    viewBox=\"0 0 41 37\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n    className={className}\n  >\n    <BrandGradient id=\"icon-gradient\" />\n    <g fill=\"none\" fillRule=\"evenodd\">\n      <ellipse\n        fill=\"url(#icon-gradient)\"\n        cx=\"17.73\"\n        cy=\"18.99\"\n        rx=\"17.73\"\n        ry=\"18.01\"\n      />\n      <path\n        d=\"M17.82.02h12.9c6.67 0 10.18 4.5 10.18 10.12 0 6.4-4.57 12.2-12.5 12.2h-4.95l-1.1 11H14.4L17.82.02zM29.65 7.6h-4.67l-.8 7.57h4.5c2.7 0 4.3-1.8 4.3-4.2 0-1.7-1.07-3.37-3.33-3.37z\"\n        fill=\"#FFF\"\n      />\n    </g>\n  </svg>\n);\n"
  },
  {
    "path": "packages/site/components/icons/PopmotionPure.js",
    "content": "import BrandGradient from './BrandGradientDef';\n\nexport default ({ width = 510, height = 238 }) => (\n  <svg\n    width={width}\n    height={height}\n    viewBox=\"0 0 510 238\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n  >\n    <defs>\n      <BrandGradient id=\"pure-logo-gradient\" />\n      <path\n        d=\"M16.5 78.1h61.7c32 0 48.7 21.2 48.7 47.7 0 30-21.8 57.5-59.8 57.5H43.4L38.1 235H.1L16.6 78.1zm56.6 35.7H50.8l-4 35.6h21.7c12.9 0 20.5-8.5 20.5-19.7 0-8-5-16-15.9-16zm308.2 108.7l15-144.4H510l-3.7 35.7h-75.7l-2.5 24.6h64.4l-3.7 35h-64.4l-2.7 26h77L495 235H342.5l-39-69.5-7 69.5h-38l16.3-156.9h61.5c32.8 0 49.6 19.4 49.6 45.1 0 23-16.3 42.3-35.2 50.2l30.6 49zM173.6 78l-9.2 87c-.3 2.5-.7 6.2-.7 11.3 0 15.8 11.5 24.3 25.5 24.3 20 0 30.1-13.3 32-31.3l9.6-91.3h38.4l-9.8 93.4c-4.9 45.6-36.2 65.8-72.3 65.8-30 0-61.4-17.7-61.4-58.2 0-4.6.5-10.6.7-13.3l9.2-87.7h38zM309 113.6l-3.7 34.5h21a19.5 19.5 0 0 0 20.4-19.1c0-7.6-5-15.4-16.8-15.4h-20.9zM46.2 0C57 0 62.6 7 62.6 16c0 10-7.3 19.2-20 19.2h-8l-1.8 17.4H20L25.5 0h20.7zM37 12l-1.3 11.9H43c4.3 0 6.9-2.8 6.9-6.6 0-2.7-1.7-5.3-5.4-5.3H37zm22.4 23.7c0-11.9 10-20.7 21.9-20.7 10.2 0 18.1 7.4 18.1 17.7 0 12-10.2 20.6-21.8 20.6-10.4 0-18.2-7.3-18.2-17.6zm27.8-2.2c0-4-2.7-7.4-6.9-7.4-4.8 0-8.6 4-8.6 8.8 0 4 2.7 7.3 6.9 7.3 5 0 8.6-4 8.6-8.7zm27.4-17.8l.1 4S118 15 125.2 15c8.4 0 15 7 15 17.4 0 12-9.2 21-18.8 21-6.7 0-9.4-4-9.4-4L110 68H97.9l5.4-52.3h11.4zm13.6 17.5c0-4-2.6-7.1-7-7.1-4.8 0-7.1 3.7-7.1 3.7l-1 8.7s1.6 3.7 6.3 3.7c5 0 8.8-4.2 8.8-9zm47 19.4h-12.3l2.3-21.8v-1.1c0-2.2-1-3.4-3.2-3.4-2.9 0-6 2.9-6 2.9l-2.6 23.4h-12.3l4-36.9h11.5l.2 3.7s5-4.3 10.7-4.3c6 0 8 4.5 8 4.5s5.6-4.5 11.9-4.5c8.3 0 12 4.6 12 12.1l-.1 2.9-2.3 22.5h-12.4l2.3-21V30c0-2.5-1.2-3.7-3.3-3.7-3 0-6 3-6 3l-2.4 23.3zm25.6-16.9c0-11.9 10-20.7 21.8-20.7 10.2 0 18.2 7.4 18.2 17.7 0 12-10.3 20.6-21.8 20.6-10.5 0-18.2-7.3-18.2-17.6zm27.8-2.2c0-4-2.8-7.4-7-7.4-4.8 0-8.5 4-8.5 8.8 0 4 2.6 7.3 6.8 7.3 5 0 8.7-4 8.7-8.7zm30.6-17.8l.9-8h-12.3l-.9 8h-5.3l-1.2 11.1h5.4L243 52.6h12.4l2.7-25.8h8.8l-2.7 25.8h12.4l3.9-36.9h-21.3zM269.6.1l-1.1 10.5h12.8l1-10.5h-12.7zm11.2 35.6c0-11.9 10-20.7 21.9-20.7 10.2 0 18.2 7.4 18.2 17.7 0 12-10.3 20.6-21.9 20.6-10.4 0-18.2-7.3-18.2-17.6zm27.8-2.2c0-4-2.7-7.4-6.9-7.4-4.9 0-8.6 4-8.6 8.8 0 4 2.7 7.3 6.9 7.3 4.9 0 8.6-4 8.6-8.7zm49 19h-12.3l2.1-20.4.1-1.6c0-2.5-1.3-4.4-4.5-4.4-4 0-7.4 3.3-7.4 3.3l-2.4 23.2H321l3.9-36.9h11.7v4s5-4.6 11-4.6c6.8 0 12.5 4.3 12.5 13.1l-.1 2.6-2.3 21.8z\"\n        id=\"pose-logo-outline\"\n      />\n    </defs>\n    <use fill=\"url(#pure-logo-gradient)\" xlinkHref=\"#pose-logo-outline\" />\n  </svg>\n);\n"
  },
  {
    "path": "packages/site/components/icons/PoseLogo.js",
    "content": "export default ({ className, width=613, height=192 }) => (\n  <svg width={width} height={height} viewBox=\"0 0 613 192\" xmlns=\"http://www.w3.org/2000/svg\" className={className}>\n    <defs>\n      <linearGradient x1=\"8.5%\" y1=\"0%\" x2=\"8.5%\" y2=\"81.7%\" id=\"posepurple\" xlinkHref=\"posepurple\">\n        <stop stopColor=\"#ED00BB\" offset=\"0%\" />\n        <stop stopColor=\"#A100F6\" offset=\"100%\" />\n      </linearGradient>\n      <linearGradient x1=\"50%\" y1=\"0%\" x2=\"50%\" y2=\"100%\" id=\"posered\" xlinkHref=\"posered\">\n        <stop stopColor=\"#FF1C68\" offset=\"0%\" />\n        <stop stopColor=\"#DB0068\" offset=\"100%\" />\n      </linearGradient>\n    </defs>\n    <g fill=\"none\" fillRule=\"evenodd\">\n      <path fill=\"url(#posepurple)\" transform=\"translate(0 -1)\" d=\"M17.2 33.1h61.6c32 0 48.8 21.2 48.8 47.6 0 30.2-21.9 57.5-59.8 57.5H44L38.8 190H.8L17.2 33.1zm56.5 35.7H51.4l-3.9 35.6h21.6c13 0 20.5-8.5 20.5-19.7 0-8-5-16-15.9-16zm140.5-38c42.5 0 74.7 31.3 74.7 72.3a89.4 89.4 0 0 1-90.1 89.2c-42.1 0-74.3-31.5-74.3-72.2 0-49.5 40-89.3 89.7-89.3zm-3 36.4c-25.8 0-48.3 22-48.3 49.2a38.7 38.7 0 0 0 38.9 39.6c25.3 0 48.7-22.1 48.7-49.3a39 39 0 0 0-39.3-39.5zm187.3-26.7l-4.1 37.3S375 66.5 350.2 66.5c-9 0-18.6 3.4-18.6 11.3 0 17.4 68.8 13.5 68.8 62.3 0 29.2-21.6 52.2-66.3 52.2-30.1 0-51.7-12.2-51.7-12.2l4.1-38.4s23.7 14.7 48.6 14.7c12.6 0 24.8-3.4 24.8-13.3 0-19.6-67-14.7-67-62.8 0-32.4 30-49.5 60.8-49.5a100 100 0 0 1 44.8 9.7zm121.2 113.8h-77l2.8-26h64.4l3.6-34.9h-64.4l2.6-24.6h75.6L531 33H417.4L401 190h115l3.6-35.7z\" />\n      <g transform=\"translate(549 -1)\" fill=\"url(#posered)\">\n        <path d=\"M31.6 1.7A31.9 31.9 0 0 0 0 34 31.9 31.9 0 0 0 31.6 66C48.2 66 61.7 53 63 36.5a23.2 23.2 0 0 1-12.4 3.4h-8.9l-2 19.6h-14l5.9-57.8z\"/>\n        <path d=\"M52.8 13.5c4 0 5.9 3 5.9 6 0 4.3-2.8 7.6-7.6 7.6h-8l1.4-13.6h8.3z\"/>\n      </g>\n    </g>\n  </svg>\n);"
  },
  {
    "path": "packages/site/components/icons/StylefireLogo.js",
    "content": "export default ({ width, height }) => (\n  <svg\n    width={width}\n    height={height}\n    viewBox=\"0 0 301 83\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n  >\n    <defs>\n      <linearGradient x1=\"-1.1%\" y1=\"0%\" y2=\"50%\" id=\"sf-a\">\n        <stop stopColor=\"#FFE42B\" offset=\"0%\" />\n        <stop stopColor=\"#F30\" offset=\"100%\" />\n      </linearGradient>\n      <linearGradient x1=\"100%\" y1=\"50%\" x2=\"0%\" y2=\"50%\" id=\"sf-b\">\n        <stop stopColor=\"#FF3500\" offset=\"0%\" />\n        <stop stopColor=\"#FF5000\" offset=\"100%\" />\n      </linearGradient>\n    </defs>\n    <g fill=\"none\" fillRule=\"evenodd\">\n      <path\n        d=\"M239.6 41.7L232 28.4l-1.3 12.8-12 .8 2.6-24.4-16.4-1.2 16.6-1.2L223.1 1h19.2a16 16 0 0 1 11.9 4.2L230 6.5l26.2 1.4c1.1 2 1.7 4.5 1.7 7.2 0 4.2-1.8 8-4.4 11L235 27.4l15.8 1.2c-1.2.9-2.6 1.6-4 2.2l9.6 15.3L261.1 1h35.6l-.5 4.2L277 6.6l19 1.3-.5 4.3h-23.7l-.8 7.7h20.2l-1.1 11h-20.2l-.9 8h24.2l-.7 6.1-19.5 1.4 19.2 1.4-.2 2.3h-47.7l-3.3-5.8-18.5-1.4 17-1.2zm-22.7.4L205 43l11.7.8-.6 6.3H204l3.3-32 12 .9L217 42zm13.5 2.7l-.5 5.3H218l.6-6.1 11.8.8zm-45-28.3h-.4.4l-.4 4.2h18.8l-1.2 11h-18.8L182 50h-12L175.1 1h32.7l-1.2 11.2H186l-.5 4.3zM220 14l-12.2.9L209 1h12.1L220 14zm-89.7 24.8l4-37.8h35.5l-1.2 11.2h-23.7l-.8 7.7h20.2l-1.1 11h-20.2l-.9 8h24.2L165 50.1h-36V50H98.8L103 8.2 87.8 30.9l-2 19.2H74l2-19.5-8.7-18.4h-8.7l-4 37.9H42.9l4-38H34s-5-1-12.8-1c-2.8 0-5.8 1.1-5.8 3.6 0 5.5 21.5 4.2 21.5 19.5 0 9.1-6.7 16.3-20.7 16.3C6.8 50.5 0 46.7 0 46.7l1.3-12s7.4 4.6 15.2 4.6c4 0 7.8-1 7.8-4.2 0-6-21-4.6-21-19.6C3.3 5.3 12.7 0 22.3 0 31 0 36 1 36 1h39.3L83 21 94.7 1h21.1l-4 37.8h18.4zm103.6-26.7l-1.1 10.8h6.5c4.4 0 6.4-3.3 6.4-6 0-2.4-1.5-4.8-5.2-4.8h-6.6z\"\n        transform=\"translate(0 14)\"\n        fill=\"url(#sf-a)\"\n      />\n      <path fill=\"#FF3900\" d=\"M300 71l-.5 5-46.5-2.5z\" />\n      <path fill=\"#FF4700\" d=\"M263 80l-.3 3-28-1.5z\" />\n      <path fill=\"#FF5D00\" d=\"M242 68l-.4 4-37.2-2z\" />\n      <path fill=\"url(#sf-b)\" d=\"M301 6l-.5 5L254 8.5z\" />\n      <path fill=\"#FF4700\" d=\"M275.2 0l-.3 3L247 1.5z\" />\n      <path fill=\"#FF6200\" d=\"M240 8l-.4 4-36.6-2z\" />\n    </g>\n  </svg>\n);\n"
  },
  {
    "path": "packages/site/components/icons/Twitter.js",
    "content": "import { ACTION, ACTION_BURN } from '~/styles/vars';\n\nexport default ({ className }) => (\n  <svg width=\"28\" height=\"23\" viewBox=\"0 0 28 23\" xmlns=\"http://www.w3.org/2000/svg\" className={className}>\n    <defs>\n      <linearGradient x1=\"50%\" y1=\"0%\" x2=\"50%\" y2=\"100%\" id=\"twitter-gradient\">\n        <stop stopColor={ACTION_BURN} offset=\"0%\" />\n        <stop stopColor={ACTION} offset=\"100%\" />\n      </linearGradient>\n    </defs>\n    <path d=\"M24 18.6c1.16.7 2.04 1.8 2.46 3.1-1.08-.64-2.28-1.1-3.55-1.35-1 1.08-2.46 1.76-4.06 1.76-3.08 0-5.58-2.5-5.58-5.57 0-.44.05-.86.14-1.27-4.64.23-8.75 2.45-11.5 5.83-.48-.83-.76-1.8-.76-2.82 0-1.93 1-3.64 2.48-4.64-.9.03-1.77.28-2.53.7v-.07C1.1 11.57 3 9.3 5.56 8.8c-.47-.14-.96-.2-1.47-.2-.36 0-.7.03-1.05.1.7-2.22 2.77-3.84 5.22-3.88-1.92-1.5-4.32-2.4-6.94-2.4-.45 0-.9.04-1.33.1C2.47.9 5.4 0 8.56 0c10.26 0 15.88 8.5 15.88 15.88 0 .24 0 .48-.02.72 1.1.8 2.04 1.77 2.8 2.9-1-.45-2.1-.75-3.22-.9z\" fill=\"url(#twitter-gradient)\" fillRule=\"nonzero\" transform=\"matrix(1 0 0 -1 0 22.11)\" />\n  </svg>\n);\n"
  },
  {
    "path": "packages/site/components/layout/Content.js",
    "content": "import GlobalTemplate from '~/components/layout/GlobalTemplate';\n\nexport default ({ children, id, section, category, title, description }) => (\n  <GlobalTemplate\n    id={id}\n    title={title}\n    description={description}\n    section={section}\n    category={category}\n  >\n    {children}\n  </GlobalTemplate>\n);\n"
  },
  {
    "path": "packages/site/components/layout/SiteLink.js",
    "content": "import { withTheme } from 'styled-components';\nimport Link from 'next/link';\n\nconst makeSiteUrl = (root, href) =>\n  root === '/' || root === '/pure' || href.substring(0, 4) === 'http'\n    ? href\n    : `${root}${href}`;\n\nconst SiteLink = ({ href, children, theme, name, ...props }) => (\n  <Link href={makeSiteUrl(theme.data.rootUrl, href)} {...props}>\n    <a name={name}>{children}</a>\n  </Link>\n);\n\nexport default withTheme(SiteLink);\n"
  },
  {
    "path": "packages/site/components/layout/grid.js",
    "content": "import styled from 'styled-components';\nimport { verticalGradient, MAIN, MAIN_FADE, WHITE, cols, media } from '~/styles/vars';\n\nexport const Container = styled.div`\n  display: grid;\n  grid-template-columns: ${cols(1)} ${cols(16)} ${cols(56)} 1fr;\n  grid-template-rows: 75px auto;\n  grid-template-areas:\n    \"left-margin header header header\"\n    \"left-margin content-nav content right-margin\"\n    \"left-margin content-nav footer right-margin\";\n  grid-row-gap: 65px;\n  min-height: 100vh;\n\n  ${media.large`\n    grid-template-columns: ${cols(1)} ${cols(12)} 1fr 0;\n    grid-row-gap: ${cols(3)};\n  `}\n\n  ${media.medium`\n    grid-template-columns: 5px 1fr;\n    grid-template-areas:\n      \"left-margin header\"\n      \"left-margin content-nav\"\n      \"left-margin content\"\n      \"left-margin footer\";\n    grid-row-gap: ${cols(2)};\n  `}\n`;\n\nexport const LeftMargin = styled.div`\n  background: ${verticalGradient(MAIN_FADE, MAIN)};\n  grid-area: left-margin;\n`;\n\nexport const RightMargin = styled.div`\n  background: ${WHITE};\n  grid-area: right-margin;\n`;\n\nexport const HeaderArea = styled.div`\n  grid-area: header;\n`;\n\nexport const ContentArea = styled.article`\n  grid-area: content;\n  padding: 0 ${cols(3)} ${cols(3)} ${cols(1)};\n\n  ${media.medium`\n    padding: 0 ${cols(1)} ${cols(1)};\n  `}\n`;\n\nexport const ContentNavArea = styled.div`\n  grid-area: content-nav;\n  padding: 0 ${cols(2)} ${cols(3)};\n\n  ${media.medium`\n    padding: 0 ${cols(1)};\n    margin: ${cols(1)} 0 ${cols(2)};\n  `}\n`;\n"
  },
  {
    "path": "packages/site/components/template.js",
    "content": "import PopmotionLogo from '~/components/icons/Logo';\nimport Link from 'next/link';\nimport Head from 'next/head';\nimport reset from '~/styles/reset';\nimport { Fragment, useRef, useEffect, useState } from 'react';\nimport styled, { createGlobalStyle } from 'styled-components';\nimport { animate } from 'popmotion';\n\nconst Global = createGlobalStyle`\n  ${reset}\n`;\n\nconst tagline = 'The animator’s JavaScript toolbox.'.split('');\n\nfunction TaglineCharacter({ character, index }) {\n  const ref = useRef(null);\n\n  useEffect(() => {\n    const controls = animate({\n      from: 0,\n      to: 0,\n      velocity: -500,\n      stiffness: 120,\n      elapsed: -index * 20,\n      onUpdate: (y) =>\n        (ref.current.style.transform = `translateY(${y}px) translateZ(0)`),\n    });\n\n    return () => controls.stop();\n  }, []);\n\n  return (\n    <span\n      ref={ref}\n      className=\"hl\"\n      style={{\n        display: 'inline-block',\n        width: character === ' ' ? 8 : 'auto',\n      }}\n    >\n      {character}\n    </span>\n  );\n}\n\nexport default function ({ children, tableOfContents }) {\n  return (\n    <Fragment>\n      <Global />\n      <Head>\n        <title>Popmotion: The animator's JavaScript toolbox</title>\n        <link rel=\"icon\" href=\"https://popmotion.io/layout/favicon.png\"></link>\n        <meta name=\"twitter:card\" content=\"summary_large_image\"></meta>\n        <meta name=\"twitter:site\" content=\"@mattgperry\"></meta>\n        <meta name=\"twitter:creator\" content=\"@mattgperry\"></meta>\n        <meta name=\"twitter:title\" content=\"Popmotion\"></meta>\n        <meta\n          name=\"twitter:description\"\n          content=\"Popmotion is a collection of low-level JavaScript animation functions and utils for advanced animators.\"\n        ></meta>\n        <meta\n          name=\"twitter:image\"\n          content={`https://popmotion.io/images/twitter-share-2020.png`}\n        ></meta>\n        <link\n          href=\"https://fonts.googleapis.com/css2?family=IBM+Plex+Mono&display=swap\"\n          rel=\"stylesheet\"\n        ></link>\n      </Head>\n      <Container>\n        <header>\n          <h1>\n            <Link href=\"/\">\n              <a name=\"Homepage\">\n                <PopmotionLogo width={128} />\n              </a>\n            </Link>\n          </h1>\n          <a href=\"https://github.com/popmotion/popmotion\" className=\"button\">\n            View on GitHub\n          </a>\n        </header>\n        <main>\n          <div className=\"cg\">\n            <h2 className=\"tagline\">\n              {tagline.map((character, i) => (\n                <TaglineCharacter index={i} key={i} character={character} />\n              ))}\n            </h2>\n            <ul className=\"usp-container\">\n              <USP title=\"Powerful\">\n                Supports <strong>keyframes</strong>, <strong>spring</strong> and{' '}\n                <strong>inertia</strong> animations on <strong>numbers</strong>,{' '}\n                <strong>colors</strong>, and <strong>complex strings</strong>.\n              </USP>\n              <USP title=\"Low level\">\n                Simple, composable functions, portable to any JS environment.\n                The library behind the library, it powers the animations in{' '}\n                <a href=\"https://framer.com/motion\">Framer Motion</a>.\n              </USP>\n              <USP title=\"Stable\">\n                Written in TypeScript and enjoys over 95% test coverage.\n              </USP>\n              <USP title=\"Tiny\">\n                The <code>animate</code> function is less than 5kb, and every\n                utility function is individually importable.\n              </USP>\n            </ul>\n          </div>\n          <article>\n            <TOC contents={tableOfContents} />\n            <div className=\"content-container\">{children}</div>\n          </article>\n        </main>\n        <footer>\n          <nav>\n            <ul>\n              <li className=\"hl\">More libraries</li>\n              <li>\n                <a href=\"/stylefire\">Stylefire</a>\n              </li>\n              <li>\n                <a href=\"/api/framesync\">Framesync</a>\n              </li>\n              <li>\n                <a href=\"/pose\">Pose</a>\n              </li>\n              <li>\n                <a href=\"/pure\">Popmotion 8</a>\n              </li>\n            </ul>\n            <div>\n              <p>\n                Created by{' '}\n                <a href=\"https://twitter.com/mattgperry\">Matt Perry</a> and{' '}\n                <a href=\"https://framer.com\">Framer</a>\n              </p>\n              <p>{`© 2014-2020 Framer BV`}</p>\n            </div>\n          </nav>\n        </footer>\n        <div className=\"frame\" />\n      </Container>\n    </Fragment>\n  );\n}\n\nfunction USP({ title, children }) {\n  return (\n    <li className=\"usp\">\n      <Tick />\n      <span className=\"title\">{title}</span>\n      {children}\n    </li>\n  );\n}\n\nfunction Tick() {\n  return (\n    <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"15\" height=\"11\">\n      <path\n        d=\"M 2 6 L 5.5 9.5 L 13 2\"\n        fill=\"transparent\"\n        strokeWidth=\"2\"\n        stroke=\"rgb(250, 25, 108)\"\n        strokeLinecap=\"round\"\n        strokeMiterlimit=\"10\"\n      ></path>\n    </svg>\n  );\n}\n\nconst generateSection = (list, filter) => (\n  <ul>{list.map((item) => generateLink(item, filter))}</ul>\n);\n\nconst generateLink = ({ title, id, children }, filter) => {\n  if (!filter || title.toLowerCase().includes(filter.toLowerCase())) {\n    return (\n      <li key={id}>\n        <Link href={`#${id}`}>{title}</Link>\n        {Boolean(children && children.length) &&\n          generateSection(children, filter)}\n      </li>\n    );\n  } else {\n    return (\n      Boolean(children && children.length) && generateSection(children, filter)\n    );\n  }\n};\n\nconst TOC = ({ contents }) => {\n  const [filter, setFilter] = useState('');\n\n  return (\n    <div className=\"toc\">\n      <nav>\n        <input\n          type=\"text\"\n          placeholder=\"Filter...\"\n          value={filter}\n          onChange={(e) => setFilter(e.currentTarget.value)}\n        />\n        {generateSection(contents[0].children, filter)}\n      </nav>\n    </div>\n  );\n};\n\nconst Container = styled.div`\n  .usp-container {\n    margin-top: 80px;\n    margin-bottom: 100px;\n  }\n\n  .usp {\n    position: relative;\n    font-size: 18px;\n    padding-left: 30px;\n    margin-bottom: 25px;\n    line-height: 1.5;\n\n    .title {\n      display: block;\n      font-weight: bold;\n      font-size: 24px;\n      margin-bottom: 10px;\n    }\n\n    svg {\n      position: absolute;\n      left: 0px;\n      top: 6px;\n    }\n  }\n\n  .toc {\n    padding: 18px 20px;\n    border-radius: 10px;\n    margin-top: 40px;\n    overflow-y: auto;\n    font-size: 24px;\n    position: sticky;\n    top: 40px;\n    left: 40px;\n    background: var(--color-shade);\n    max-width: 300px;\n    max-height: 80vh;\n\n    input {\n      padding: 10px;\n      background: rgba(255, 255, 255, 0.6);\n      width: 100%;\n      border-bottom: 1px solid rgba(0, 0, 0, 0.2);\n      margin-bottom: 40px;\n      font-size: 18px;\n    }\n\n    li a {\n      display: inline-block;\n      margin-bottom: 10px;\n    }\n\n    ul {\n      margin-bottom: 10px;\n    }\n\n    nav > ul {\n      font-size: 24px;\n\n      > li > ul {\n        font-size: 22px;\n        margin-left: 10px;\n\n        > li > ul {\n          font-size: 18px;\n          margin-left: 10px;\n\n          > li > ul {\n            font-size: 14px;\n            margin-left: 10px;\n          }\n        }\n      }\n    }\n  }\n\n  header {\n    padding: 40px;\n    display: flex;\n    justify-content: space-between;\n\n    path {\n      fill: var(--color-popmotion) !important;\n    }\n\n    .button {\n      height: 39px;\n      overflow: visible;\n      background-color: var(--color-shade);\n      border-radius: 20px;\n      padding: 12px 20px;\n      color: var(--color-black);\n    }\n  }\n\n  footer {\n    margin: 100px 40px 0 40px;\n    border-top: 1px solid var(--color-shade);\n    padding: 40px;\n\n    nav {\n      max-width: 660px;\n      margin: auto;\n      display: flex;\n      justify-content: space-between;\n    }\n\n    li,\n    p {\n      margin-bottom: 10px;\n      font-size: 16px;\n    }\n  }\n\n  header {\n    margin-bottom: 100px;\n  }\n\n  .tagline {\n    font-size: 28px;\n    letter-spacing: -0.6px;\n    display: block;\n  }\n\n  .frame {\n    position: fixed;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    border: 10px solid var(--color-popmotion);\n    pointer-events: none;\n    z-index: 2;\n  }\n\n  article {\n    display: grid;\n    grid-template-columns: 1fr [a] 250px [b] 60px [c] 650px [d] 1fr;\n\n    .toc {\n      grid-column: a / b;\n    }\n\n    .content-container {\n      grid-column: c / d;\n    }\n  }\n\n  .cg {\n    display: grid;\n    grid-template-columns: 40px [lo-start] 1fr [lo-end] 40px [c-start] 650px [c-end] 1fr [ro-end] 40px [end];\n\n    > * {\n      grid-column: c-start / c-end;\n    }\n  }\n\n  @media screen and (max-width: 960px) {\n    article {\n      display: block;\n\n      .content-container,\n      .toc {\n        width: 100%;\n        max-width: 650px;\n        margin-left: auto;\n        margin-right: auto;\n      }\n\n      .toc {\n        max-height: 200px;\n        box-shadow: 0px 10px 20px rgba(0, 0, 0, 0.2);\n      }\n    }\n\n    .cg {\n      display: block;\n      width: 100%;\n      max-width: 650px;\n      margin-left: auto;\n      margin-right: auto;\n    }\n  }\n\n  @media screen and (max-width: 740px) {\n    .frame {\n      border: 5px solid var(--color-popmotion);\n    }\n\n    header {\n      margin-bottom: 0;\n    }\n\n    .cg {\n    }\n\n    footer nav {\n      flex-direction: row;\n      justify-content: stretch;\n      flex-wrap: wrap;\n\n      ul {\n        margin-bottom: 20px;\n      }\n    }\n  }\n\n  @media screen and (max-width: 670px) {\n    article {\n      display: block;\n\n      .content-container,\n      .toc {\n        width: calc(100vw - 40px);\n        margin-left: 20px;\n        margin-right: 20px;\n      }\n\n      .toc {\n        top: 20px;\n      }\n    }\n  }\n\n  @media screen and (max-width: 600px) {\n    header {\n      svg {\n        width: 110px;\n      }\n\n      .button {\n        font-size: 14px;\n      }\n    }\n\n    .cg,\n    footer,\n    header {\n      padding: 20px !important;\n    }\n\n    .usp-container {\n      margin-top: 40px;\n    }\n\n    .usp {\n      font-size: 14px;\n      margin-bottom: 20px;\n\n      .title {\n        font-size: 18px;\n        margin-bottom: 10px;\n      }\n    }\n\n    .tagline {\n      font-size: 24px;\n      letter-spacing: -0.4px;\n    }\n\n    article {\n      margin-top: 80px;\n    }\n  }\n\n  @media screen and (max-width: 400px) {\n    .tagline {\n      font-size: 18px;\n      letter-spacing: -0.2px;\n    }\n  }\n`;\n"
  },
  {
    "path": "packages/site/data/authors.json",
    "content": "{\n  \"mattperry\": {\n    \"name\": \"Matt Perry\",\n    \"avatar\": \"/images/mattperry.jpg\"\n  }\n}\n"
  },
  {
    "path": "packages/site/data/category-names.json",
    "content": "{\n  \"action\": \"Action\",\n  \"animation\": \"Animation\",\n  \"compositors\": \"Compositors\",\n  \"input\": \"Input\",\n  \"how-to\": \"How to...\",\n  \"stylefire\": \"Styler\",\n  \"basics\": \"Basics\",\n  \"advanced\": \"Advanced\",\n  \"plugins\": \"Plugins\",\n  \"projects\": \"Projects\",\n  \"reactions\": \"Reactions\",\n  \"dom\": \"DOM\",\n  \"react\": \"React\",\n  \"react-native\": \"React Native\",\n  \"stylers\": \"Stylers\",\n  \"vanilla\": \"Vanilla\",\n  \"vue\": \"Vue\",\n  \"functions\": \"Utilities\"\n}\n"
  },
  {
    "path": "packages/site/data/route-paths.json",
    "content": "{\n  \"api\": \"/api\",\n  \"learn\": \"/learn/get-started\",\n  \"blog\": \"/blog\",\n  \"examples\": \"/examples\"\n}\n"
  },
  {
    "path": "packages/site/data/section-names.json",
    "content": "{\n  \"api\": \"API\",\n  \"learn\": \"Learn\",\n  \"blog\": \"Blog\",\n  \"support\": \"Support us\",\n  \"examples\": \"Examples\"\n}\n"
  },
  {
    "path": "packages/site/data/settings.json",
    "content": "{\n  \"siteName\": \"Popmotion\",\n  \"githubUrl\": \"https://github.com/popmotion/popmotion\",\n  \"stackOverflowUrl\": \"https://stackoverflow.com/questions/tagged/popmotion\",\n  \"twitterUrl\": \"https://twitter.com/popmotionjs\",\n  \"twitterUsername\": \"popmotionjs\"\n}\n"
  },
  {
    "path": "packages/site/data/site-names.json",
    "content": "{\n  \"popcorn\": \"popcorn\",\n  \"popmotion\": \"pure\",\n  \"popmotion-pose\": \"pose\",\n  \"stylefire\": \"stylefire\"\n}\n"
  },
  {
    "path": "packages/site/docs/popcorn/index.md",
    "content": "# Popcorn\n\nPopcorn is the Lodash of animation.\n\nIt contains utility functions to help animation and UI developers manipulate values over time and space.\n\n## Features\n\n- **Powerful interpolation:** [The powerful `interpolate`](/api/interpolate) function can map a range of numbers onto another range of numbers, colors and complex strings.\n- **Linear RGB mixing:** Hex and RGB values are mixed as linear RGB, which avoids the usual brightness dips in many animation libraries. [Learn more](https://www.youtube.com/watch?v=LKnqECcg6Gw)\n- **Tiny:** Import only what you need with ES6 imports.\n\n## Install\n\n### Package managers\n\nPopcorn is currently available as `@popmotion/popcorn` on npm.\n\n```bash\nnpm install @popmotion/popcorn\n```\n\n```bash\nyarn add @popmotion/popcorn\n```\n\n### File download\n\nDownload or link to the [latest version of Popcorn](https://unpkg.com/@popmotion/popcorn/dist/popcorn.min.js). All functions will be available on the `popcorn` global variable (e.g. `popcorn.velocityPerSecond`).\n"
  },
  {
    "path": "packages/site/docs/stylefire/index.md",
    "content": "## Features\n\n* **Render batching:** Prevents layout thrashing and unnecessary renders by batching all UI changes once per frame.\n* **Individual transform props:** Set and animate `transform` props independently from one another.\n* **Easy SVG transforms:** Replaces the complex SVG transform model with the user-friendly CSS equivalent.\n* **Path drawing:** Set `path` length and offset as a percentage, simplifying the 'drawing' effect.\n* **Scrolling:** `scrollTop` and `scrollLeft` support for the viewport and HTML elements.\n* **Vendor prefixes:** Tests and detects rules for prefixed support.\n* **Tiny:** At 3.5kb, it's the perfect fit for any animation library or website.\n\n## Install\n\n```bash\nnpm install stylefire\n```\n"
  },
  {
    "path": "packages/site/package.json",
    "content": "{\n  \"name\": \"popmotion-site\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"npm run build-content && next dev\",\n    \"build\": \"npm run build-content && next build && next export\",\n    \"start\": \"next start\",\n    \"build-content\": \"node scripts/generate-content.js\",\n    \"s3-upload\": \"aws s3 cp public s3://popmotion.io --recursive\",\n    \"invalidate-cloudfront\": \"aws configure set preview.cloudfront true && aws cloudfront create-invalidation --distribution-id E31YV8NBB5M5N4 --paths /*\",\n    \"publish-site\": \"npm run build && npm run s3-upload && npm run invalidate-cloudfront\"\n  },\n  \"dependencies\": {\n    \"file-loader\": \"^1.1.11\",\n    \"front-matter\": \"^3.0.2\",\n    \"fs\": \"0.0.1-security\",\n    \"live-on-stage\": \"^2.0.19\",\n    \"marksy\": \"^8.0.0\",\n    \"next\": \"9.1.3\",\n    \"nprogress\": \"^0.2.0\",\n    \"path\": \"^0.12.7\",\n    \"prismjs\": \"^1.6.0\",\n    \"raw-loader\": \"^0.5.1\",\n    \"react\": \"16.11.0\",\n    \"react-dom\": \"16.11.0\",\n    \"react-intersection\": \"^1.0.5\",\n    \"react-live\": \"^1.7.0\",\n    \"react-pose\": \"^4.0.10\",\n    \"react-pose-text\": \"^3.1.0\",\n    \"react-syntax-highlighter\": \"^5.8.0\",\n    \"styled-components\": \"^4.4.1\",\n    \"three\": \"^0.110.0\"\n  },\n  \"devDependencies\": {\n    \"babel-plugin-root-import\": \"^6.4.1\",\n    \"babel-plugin-styled-components\": \"^1.10.6\",\n    \"s3\": \"^4.4.0\"\n  }\n}\n"
  },
  {
    "path": "packages/site/pages/_document.js",
    "content": "import React from 'react';\nimport Document, { Head, Main, NextScript } from 'next/document';\nimport { ServerStyleSheet } from 'styled-components';\nimport Analytics from '~/templates/global/Analytics';\n\nexport default class PageTemplate extends Document {\n  render() {\n    const stylesheet = new ServerStyleSheet();\n    const main = stylesheet.collectStyles(<Main />);\n    const styleTags = stylesheet.getStyleElement();\n\n    return (\n      <html lang=\"en\">\n        <Head>\n          <meta charSet=\"UTF-8\" />\n          <meta name=\"viewport\" content=\"initial-scale=1.0, width=device-width\" />\n          <meta name=\"og:locale\" property=\"og:locale\" content=\"en_US\" />\n          <link href=\"https://fonts.googleapis.com/css?family=Inconsolata:400|PT+Sans:400,700\" rel=\"stylesheet\" />\n          <link rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/images/favicon-32x32.png\" />\n          <link rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/images/favicon-16x16.png\" />\n          <meta name=\"twitter:card\" content=\"summary\" />\n          <meta name=\"twitter:site\" content=\"@popmotionjs\" />\n          <link rel=\"shortcut icon\" href=\"/images/favicon.ico\" />\n          {styleTags}\n          <Analytics />\n        </Head>\n        <body id=\"root\">\n          {main}\n          <NextScript />\n        </body>\n      </html>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/site/pages/_error.js",
    "content": "import GlobalTemplate from '~/templates/global/Template';\nimport ContentPage from '~/templates/global-new/ContentPage';\nimport { Section, PageHeader } from '~/templates/global-new/styled';\nimport Link from 'next/link';\n\nexport default () => (\n  <GlobalTemplate\n    title=\"Lost? | Popmotion\"\n    description=\"Popmotion is a functional, reactive JavaScript motion library.\"\n    theme=\"popmotion\"\n  >\n    <ContentPage>\n      <Section>\n        <PageHeader>Page not found</PageHeader>\n        <Link href=\"/\">\n          <a>Go home</a>\n        </Link>\n      </Section>\n    </ContentPage>\n  </GlobalTemplate>\n);\n"
  },
  {
    "path": "packages/site/pages/api.js",
    "content": "import { Fragment } from 'react';\nimport GlobalTemplate from '~/templates/global/Template';\nimport ContentPage from '~/templates/global-new/ContentPage';\nimport { Section, PageHeader } from '~/templates/global-new/styled';\nimport MenuPage from '~/templates/content/MenuPage';\n\nexport default () => (\n  <GlobalTemplate\n    title=\"API | Popmotion Pure\"\n    description=\"Popmotion Pure is a functional, flexible JavaScript motion library.\"\n    theme=\"pure\"\n  >\n    <ContentPage section=\"api\">\n      <Section>\n        <PageHeader>API</PageHeader>\n        <MenuPage section=\"api\" />\n      </Section>\n    </ContentPage>\n  </GlobalTemplate>\n);\n"
  },
  {
    "path": "packages/site/pages/blog.js",
    "content": "import { Fragment } from 'react';\nimport GlobalTemplate from '~/templates/global/Template';\nimport ContentPage from '~/templates/global-new/ContentPage';\nimport { Section, PageHeader } from '~/templates/global-new/styled';\nimport BlogList from '~/templates/blog';\n\nexport default () => (\n  <GlobalTemplate\n    title=\"Blog | Popmotion\"\n    description=\"Popmotion makes simple and powerful JavaScript animation libraries for HTML, SVG, React and React Native.\"\n    theme=\"popmotion\"\n  >\n    <ContentPage section=\"blog\">\n      <Section>\n        <PageHeader>Blog</PageHeader>\n        <BlogList />\n      </Section>\n    </ContentPage>\n  </GlobalTemplate>\n);\n"
  },
  {
    "path": "packages/site/pages/index.js",
    "content": "\nimport marksy from 'marksy';\nimport Homepage from '~/components/template';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { createElement } from 'react';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    blockquote: Blockquote,\n  }\n});\n\nconst Page = ({ section }) => (\n  <Homepage tableOfContents={content.toc}>\n    {content.tree}\n  </Homepage>\n);\n\nconst content = convertMarkdown(`\n\n## Quick start\n\n\\`\\`\\`bash\nnpm install popmotion\n\\`\\`\\`\n\n\\`\\`\\`javascript\nimport { animate } from \"popmotion\"\n\nanimate({\n  from: 0,\n  to: 100,\n  onUpdate: latest => console.log(latest)\n})\n\\`\\`\\`\n\n## Animation\n\n### animate\n\n\\`animate\\` performs a keyframes or spring animation.\n\n\\`\\`\\`javascript\nimport { animate } from \"popmotion\"\n\nanimate({\n  from: 0, \n  to: 100,\n  onUpdate: latest => console.log(latest)\n})\n\\`\\`\\`\n\nIt can animate numbers:\n\n\\`\\`\\`javascript\nanimate({ from: 0, to: 100 })\n\\`\\`\\`\n\nOr strings of the same type:\n\n\\`\\`\\`javascript\nanimate({ from: \"0px\", to: \"100px\" })\nanimate({ from: \"#fff\", to: \"#000\" })\n\\`\\`\\`\n\nThe strings can be pretty complex, for instance box shadows or SVG path definitions. The only limitation is that the numbers and colors contained within must be in the same order:\n\n\\`\\`\\`javascript\nanimate({\n  from: \"0px 0px 0px rgba(0, 0, 0, 0)\",\n  to: \"10px 10px 0px rgba(0, 0, 0, 0.2)\"\n})\n\\`\\`\\`\n\n<!--\nArrays of the above:\n\n\\`\\`\\`javascript\nanimate({\n  from: [0, \"#fff\"],\n  to: [100, \"#000\"]\n})\n\\`\\`\\`\n\nAnd objects of the above:\n\n\\`\\`\\`javascript\nanimate({\n  from: { x: 0, backgroundColor: \"#fff\" },\n  to: { x: 100, backgroundColor: \"#000\" }\n})\n\\`\\`\\`\n-->\n\nThe type of animation performed will be automatically detected from the provided options, or can be chosen manually by defining \\`type\\` as \\`\"keyframes\"\\`, \\`\"spring\"\\` or \\`\"decay\"\\`.\n\n#### Options\n\nThese options can be set for **all animations**:\n\n##### from\n\nAn initial value to start the animation from.\n\nDefaults to \\`0\\`\n\n\\`\\`\\`javascript\nanimate({\n  from: \"linear-gradient(#e66465, #9198e5)\",\n  to: \"linear-gradient(#9198e5, #e66465)\"\n})\n\\`\\`\\`\n\n##### elapsed\n\nSets an initial elapsed time, in milliseconds. Set to a negative value for a delay.\n\n\\`\\`\\`javascript\nanimate({\n  to: 100,\n  elapsed: -300\n})\n\\`\\`\\`\n\n##### repeat\n\nThe number of times to repeat the animation. Set to \\`Infinity\\` to repeat forever.\n\n\\`\\`\\`javascript\nanimate({\n  to: 100,\n  repeat: 2\n})\n\\`\\`\\`\n\n##### repeatDelay\n\nThe duration, in milliseconds, to wait before repeating the animation.\n\n\\`\\`\\`javascript\nanimate({\n  to: 100,\n  repeat: 2,\n  repeatDelay: 200\n})\n\\`\\`\\`\n\n##### repeatType\n\nEither \\`\"loop\"\\`, \\`\"mirror\"\\` or \\`\"reverse\"\\`. Defaults to \\`\"loop\"\\`.\n\n- \\`\"loop\"\\`: Repeats the animation from \\`0\\`.\n- \\`\"mirror\":\\` Swaps the \\`from\\`/\\`to\\` values alternately.\n- \\`\"reverse\":\\` Reverses the animation alternately.\n\n\\`\\`\\`javascript\nanimate({\n  to: 100,\n  repeat: 2,\n  repeatType: \"reverse\"\n})\n\\`\\`\\`\n\n##### driver\n\nBy default, the animation will be driven by a \\`requestAnimationFrame\\` loop. \\`driver\\` can specify a different source.\n\nA \\`Driver\\` is a function that accepts the animations \\`update\\` function. This is a function that can be called with a time delta from the previous frame. The \\`Driver\\` must return a function that will be called when the animation is stopped.\n\n\\`\\`\\`javascript\nconst xrDriver = session => update => {\n  let latestRequestId = 0\n  let prevTimestamp = performance.now()\n  \n  const step = timestamp => {\n    const delta = timestamp - prevTimestamp\n    prevTimestamp = timestamp\n\n    update(delta)\n\n    latestRequestId = session.requestAnimationFrame(step)\n  }\n\n  let latestRequestId = session.requestAnimationFrame(step)\n\n  return () => session.cancelRequestAnimationFrame(latestRequestId)\n}\n\nanimate({\n  to: 100,\n  driver: xrDriver(xrSession)\n})\n\\`\\`\\`\n\n##### type\n\n\\`animate\\` will automatically detect the type of animation to use based on the options provided. But a specific type can be chosen manually by defining \\`type\\` as \\`\"keyframes\"\\`, \\`\"spring\"\\` or \\`\"decay\"\\`.\n\n\\`\\`\\`jsx\nanimate({\n  to: 100,\n  type: \"spring\"\n})\n\\`\\`\\`\n\n#### Lifecycle events\n\nThe following lifecycle events are available for **all animations**:\n\n##### onUpdate\n\nThis is called every frame the animation fires with the latest computed value.\n\n\\`\\`\\`javascript\nanimate({\n  to: 100,\n  onUpdate: latest => console.log(latest)\n})\n\\`\\`\\`\n\n##### onPlay\n\nThis is called when the animation starts. Currently this automatically when \\`animate\\` is called.\n\n\\`\\`\\`javascript\nanimate({\n  to: 100,\n  onPlay: () => {}\n})\n\\`\\`\\`\n\n##### onComplete\n\nThis is called when the animation successfully completes.\n\n\\`\\`\\`javascript\nanimate({\n  to: 100,\n  onComplete:() => {}\n})\n\\`\\`\\`\n\n##### onRepeat\n\nThis is called when an animation repeats.\n\n\\`\\`\\`javascript\nanimate({\n  to: 100,\n  repeat: 2,\n  onRepeat: () => {}\n})\n\\`\\`\\`\n\n##### onStop\n\nThis is called when the animation is stopped by the \\`stop\\` control.\n\n\\`\\`\\`javascript\nconst animation = animate({\n  to: 100,\n  onStop: () => {}\n})\n\nanimation.stop()\n\\`\\`\\`\n\n#### Keyframes options\n\nA keyframes animation is the default animation type and it can be defined either with a \\`from\\` and \\`to\\` option:\n\n\\`\\`\\`javascript\nanimate({ from: 0, to: 100 })\n\\`\\`\\`\n\nOr as a series of keyframes provided to the \\`to\\` option:\n\n\\`\\`\\`javascript\nanimate({ to: [0, 100, 200] })\n\\`\\`\\`\n\n##### to\n\nA single value to animate to, or an array of values to animate through.\n\n\\`\\`\\`javascript\nanimate({\n  to: [\"#0ff\", \"#f00\", \"#0f0\"]\n})\n\\`\\`\\`\n\nIf \\`to\\` is an array, any defined \\`from\\` will be ignored.\n\n##### duration\n\nThis defines the duration of the animation, in milliseconds.\n\n\\`\\`\\`javascript\nanimate({\n  to: 100,\n  duration: 300\n})\n\\`\\`\\`\n\n##### ease\n\nThis is an easing function, or array of functions, to use when easing between each keyframe.\n\n\\`\\`\\`javascript\nimport { animate, linear, easeInOut } from \"popmotion\"\n\nanimate({\n  to: 100,\n  ease: linear\n})\n\nanimate({\n  to: [\"#fff\", \"#000\", \"#f00\"],\n  ease: [linear, easeInOut]\n})\n\\`\\`\\`\n\nIf set as any array, the length of this array must be one shorter than the number of values being animated between.\n\n##### offset\n\nThis is an array of values between \\`0\\` and \\`1\\` that defines at which point throughout the animation each keyframe should be reached.\n\nThis array should be the same length as the number of defined keyframes.\n\n\\`\\`\\`javascript\nanimate({\n  to: [\"#fff\", \"#000\", \"#f00\"],\n  offset: [0, 0.2, 1]\n})\n\\`\\`\\`\n\n#### Spring options\n\nSprings are great for creating natural-feeling interfaces and dynamic interruptable animations.\n\nA spring animation will be used if any of the \\`stiffness\\`, \\`damping\\` or \\`mass\\` options are detected.\n\n**Note:** A spring simulation is inherently numerical so if it's given a color, array or object, it runs the animation from \\`0\\` to \\`100\\` and interpolates that to the given values. This strategy is likely to be tweaked before the official release so animations made this way may change in feel.\n\n##### to\n\nA single value to animate to.\n\n\\`\\`\\`javascript\nanimate({\n  to: 100,\n  type: \"spring\"\n})\n\\`\\`\\`\n\nIf \\`to\\` is an array, any defined \\`from\\` will be ignored.\n\n##### stiffness\n\nThis defines the stiffness of the spring. A higher stiffness will result in a snappier animation.\n\nDefaults to \\`100\\`\n\n\\`\\`\\`javascript\nanimate({\n  to: 100,\n  stiffness: 1000\n})\n\\`\\`\\`\n\n##### damping\n\nThis is the opposing force to \\`stiffness\\`. As you reduce this value, relative to \\`stiffness\\`, the spring will become bouncier and the animation will last longer. Likewise, higher relative values will have less bounciness and result in shorter animations.\n\nDefaults to \\`10\\`\n\n\\`\\`\\`javascript\nanimate({\n  to: 100,\n  damping: 50\n})\n\\`\\`\\`\n\n##### mass\n\nThis is the mass of the animating object. Heavier objects will take longer to speed up and slow down.\n\nDefaults to \\`1\\`.\n\n\\`\\`\\`javascript\nanimate({\n  to: 100,\n  mass: 2\n})\n\\`\\`\\`\n\n##### velocity\n\nThe initial velocity, in units per second, of the animation.\n\n\\`\\`\\`javascript\nanimate({\n  to: 100,\n  velocity: 1000\n})\n\\`\\`\\`\n\n##### duration\n\nThe duration of the spring, in milliseconds.\n\nWill be overridden by \\`stiffness\\`, \\`mass\\` or \\`damping\\`.\n\n\\`\\`\\`javascript\nanimate({\n  to: 100,\n  duration: 1000\n})\n\\`\\`\\`\n\n##### bounce\n\nThe bounciness of the spring, as a value between \\`0\\` and \\`1\\`, where \\`0\\` is no bounce.\n\nWill be overridden by \\`stiffness\\`, \\`mass\\` or \\`damping\\`.\n\n\\`\\`\\`javascript\nanimate({\n  to: 100,\n  bounce: 0.2\n})\n\\`\\`\\`\n\n##### restDelta\n\nThe distance from the animation target at which the animation can be considered complete. When both \\`restDelta\\` and \\`restSpeed\\` are met, the animation completes.\n\n\\`\\`\\`javascript\nanimate({\n  to: 100,\n  restDelta: 0.5\n})\n\\`\\`\\`\n\n##### restSpeed\n\nThe absolute velocity, in units per second, below which the animation can be considered complete. When both \\`restDelta\\` and \\`restSpeed\\` are met, the animation completes. Defaults to \\`10\\`.\n\n\\`\\`\\`javascript\nanimate({\n  to: 100,\n  restSpeed: 5\n})\n\\`\\`\\`\n\n#### Playback controls\n\n\\`animate\\` returns \\`PlaybackControls\\`, which can be used to control the playback of the animation.\n\nCurrently this only includes a \\`stop\\` method, but may expand with more.\n\n##### stop\n\nStops the animation.\n\n\\`\\`\\`javascript\nconst playback = animate({ from: 0, to: 100 })\nplayback.stop()\n\\`\\`\\`\n\n### inertia\n\nThe \\`inertia\\` animation is used to gradually decelerate a number. Think smartphone scroll momentum.\n\n#### Options\n\nIn addition to \\`animate\\`'s \\`from\\`, \\`onUpdate\\` and \\`onComplete\\` options, \\`inertia\\` also supports the following:\n\n##### velocity\n\nThe initial velocity, in units per second, of the animation.\n\n\\`\\`\\`javascript\ninertia({\n  from: 0,\n  velocity: 100\n})\n\\`\\`\\`\n\n##### power\n\nA constant with which to calculate a target value. Higher power = further target.\n\nDefaults to \\`0.8\\`.\n\n\\`\\`\\`javascript\ninertia({\n  from: 0,\n  power: 0.3\n})\n\\`\\`\\`\n\n##### timeConstant\n\nAdjusting the time constant will change the duration of the deceleration, thereby affecting its feel.\n\nDefaults to \\`350\\`.\n\n\\`\\`\\`javascript\ninertia({\n  from: 0,\n  velocity: 100,\n  timeConstant: 400\n})\n\\`\\`\\`\n\n##### modifyTarget\n\nA function that receives the calculated target and returns a new one. Useful for snapping the target to a grid.\n\n\\`\\`\\`javascript\nconst roundToNearest = target => v => Math.ceil(v / target) * target\n\ninertia({\n  from: 0,\n  velocity: 100,\n  modifyTarget: roundToNearest(100)\n})\n\\`\\`\\`\n\n##### min\n\nThe minimum value at which the animation will switch from gradual deceleration and use a spring animation to snap to this point.\n\n\\`\\`\\`javascript\ninertia({\n  from: 50,\n  velocity: -100,\n  min: 0\n})\n\\`\\`\\`\n\n##### max\n\nThe maximum value at which the animation will switch from gradual deceleration and use a spring animation to snap to this point.\n\n\\`\\`\\`javascript\ninertia({\n  from: 50,\n  velocity: 100,\n  max: 100\n})\n\\`\\`\\`\n\n##### bounceStiffness\n\nThis defines the stiffness of the spring when the animation hits either \\`min\\` or \\`max\\`. A higher stiffness will result in a snappier animation.\n\nDefaults to \\`500\\`\n\n\\`\\`\\`javascript\ninertia({\n  from: 0,\n  velocity: 100,\n  max: 50,\n  bounceStiffness: 1000\n})\n\\`\\`\\`\n\n##### bounceDamping\n\nThis is the opposing force to \\`bounceStiffness\\`. As you reduce this value, relative to \\`bounceStiffness\\`, the spring will become bouncier and the animation will last longer. Likewise, higher relative values will have less bounciness and result in shorter animations.\n\nDefaults to \\`10\\`\n\n\\`\\`\\`javascript\ninertia({\n  from: 0,\n  velocity: 100,\n  max: 50,\n  bounceDamping: 300\n})\n\\`\\`\\`\n\n##### restDelta\n\nThe distance from the animation target at which the animation can be considered complete.\n\n\\`\\`\\`javascript\ninertia({\n  from: 0,\n  velocity: 100,\n  restDelta: 0.5\n})\n\\`\\`\\`\n\n### Iterators\n\nPowering \\`animate\\` and \\`inertia\\` are the \\`keyframes\\`, \\`spring\\`, and \\`decay\\` [iterators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#The_iterator_protocol).\n\n\\`\\`\\`javascript\nimport { keyframes, spring, decay } from \"popmotion\";\n\\`\\`\\`\n\nIterators give you the ability to run an animation with a high degree of control. For example, [Framer](https://framer.com) uses the \\`spring\\` iterator to draw its animation editor visualiser by running it synchronously.\n\nEach can be initialised with the matching options above (\\`decay\\` with a subset of \\`inertia\\`'s options, excluding the \\`bounce-\\` options):\n\n\\`\\`\\`javascript\nconst animation = spring({\n  from: 0,\n  to: 100,\n  stiffness: 200\n})\n\\`\\`\\`\n\nWith the returned iterator, you can resolve the animation at a specific timestamp with its \\`next\\` method.\n\n\\`\\`\\`javascript\n// Resolve the animation at 200ms\nconst { value, done } = animation.next(200)\n\\`\\`\\`\n\n## Easing\n\nPopmotion includes a number of in-built easing functions, as well as factory functions to make entirely new ones.\n\n### Functions\n\nEach easing function can be imported like so:\n\n\\`\\`\\`javascript\nimport { linear } from \"popmotion\"\n\\`\\`\\`\n\nEach function accepts a progress value between \\`0\\` and \\`1\\`, and returns a new one:\n\n\\`\\`\\`javascript\nconst progress = 0.5\nconst easedProgress = easeInOut(progress)\n\\`\\`\\`\n\n - \\`linear\\`\n - \\`easeIn\\`\n - \\`easeInOut\\`\n - \\`easeOut\\`\n - \\`circIn\\`\n - \\`circInOut\\`\n - \\`circOut\\`\n - \\`backIn\\`\n - \\`backInOut\\`\n - \\`backOut\\`\n - \\`anticipate\\`\n - \\`bounceIn\\`\n - \\`bounceInOut\\`\n - \\`bounceOut\\`\n\n### Factories\n\n#### cubicBezier\n\n\\`\\`\\`javascript\nimport { cubicBezier } from \"popmotion\"\n\nconst easing = cubicBezier(0, .42, 0, 1)\n\\`\\`\\`\n\nNew cubic bezier definitions can be created in the [Framer](https://framer.com) animation editor and copy/pasted directly into this function.\n\n#### steps\n\n\\`steps\\` returns an easing function that will convert the animation into a discrete series of steps.\n\n\\`\\`\\`javascript\nimport { steps } from \"popmotion\"\n\nconst easing = steps(5)\n\\`\\`\\`\n\nIt optionally accepts a second parameter, either \\`\"start\"\\` or \\`\"end\"\\` (default)that decides whether the steps are aligned with the start or end of the animation.\n\n\\`\\`\\`javascript\nsteps(5, \"start\")\n\\`\\`\\`\n\n#### mirrorEasing\n\nMirrors an existing easing function. \n\n#### reverseEasing\n\nReverses an existing easing function. For instance, providing it \\`easeIn\\` would return an \\`easeOut\\`.\n\n\\`\\`\\`javascript\nimport { reverseEasing, linear } from \"popmotion\"\n\nconst reversed = reverseEasing(linear)\nreversed(1) // 0\nreversed(0.5) // 0.5\nreversed(0) // 1\n\\`\\`\\`\n\n#### createExpoIn\n\nCreates an easing function based on the exponent of the provided \\`power\\`. The higher the \\`power\\`, the stronger the easing.\n\n\\`\\`\\`javascript\nimport { createExpoIn } from \"popmotion\"\n\nconst expoIn = createExpoIn(4)\n\\`\\`\\`\n\nThe returned easing function is an ease in, which means it starts slow and finished fast. \\`mirrorEasing\\` and \\`reverseEasing\\` can be used to create ease in out, and ease out variations:\n\n\\`\\`\\`javascript\nconst expoIn = createExpoIn(4)\nconst expoOut = mirrorEasing(easeIn)\nconst expoInOut = reverseEasing(easeIn)\n\\`\\`\\`\n\n#### createBackIn\n\nCreates an easing function with an overshoot. It accepts a \\`power\\` value, the higher the \\`power\\` the stronger the overshoot.\n\n\\`\\`\\`javascript\nimport { createBackIn } from \"popmotion\"\n\nconst backIn = createBackIn(4)\n\\`\\`\\`\n\nThe returned easing function is an ease in, which means the overshoot happens at the start of the animation. \\`mirrorEasing\\` and \\`reverseEasing\\` can be used to create ease in out, and ease out variations:\n\n\\`\\`\\`javascript\nconst backIn = createBackIn(4)\nconst backOut = mirrorEasing(easeIn)\nconst backInOut = reverseEasing(easeIn)\n\\`\\`\\`\n\n#### createAnticipate\n\nCreates an easing that pulls back a little before animating out with an overshoot. The stronger the \\`power\\` the bigger the overshoot.\n\n\\`\\`\\`javascript\nimport { createAnticipate } from \"popmotion\"\n\nconst anticipate = createAnticipate(4)\n\\`\\`\\`\n\n## Utils\n\n#### angle\n\nReturns an angle between two points, in degrees.\n\n\\`\\`\\`javascript\nimport { angle } from \"popmotion\"\n\nangle(\n  { x: 0, y: 0 },\n  { x: 45, y: 100 }\n)\n\\`\\`\\`\n\n#### attract\n\n\n\\`\\`\\`javascript\nimport { attract } from \"popmotion\"\n\nattract(5, 10, 12)\n\\`\\`\\`\n\n#### attractExpo\n\n\\`\\`\\`javascript\nimport { attractExpo } from \"popmotion\"\n\nattractExpo(5, 10, 12)\n\\`\\`\\`\n\n#### clamp\n\nClamp a value to within the given range.\n\n\\`\\`\\`javascript\nimport { clamp } from \"popmotion\"\n\nconst min = 50\nconst max = 100\nclamp(min, max, 150) // 100\n\\`\\`\\`\n\n#### degreesToRadians\n\nConverts degrees to radians.\n\n\\`\\`\\`javascript\nimport { degreesToRadians } from \"popmotion\"\n\ndegreesToRadians(45) // 0.785...\n\\`\\`\\`\n\n#### distance\n\nReturns the distance between two numbers, two 2D points, or two 3D points.\n\n\\`\\`\\`javascript\nimport { distance } from \"popmotion\"\n\ndistance(10, 50)\ndistance({ x: 0, y: 0 }, { x: 45, y: 100 })\ndistance({ x: 0, y: 0, z: 100 }, { x: 45, y: 100, z: 0 })\n\\`\\`\\`\n\n#### interpolate\n\nCreates a function that will interpolate from an linear series of numbers, to a non-linear series of numbers, strings of the same numerical format, colours, or arrays/objects of those.\n\n\\`\\`\\`javascript\nimport { interpolate } from \"popmotion\"\n\nconst mapXToOpacity = interpolate(\n  [-100, 0, 100],\n  [0, 1, 0]\n)\nmapXToOpacity(-50) // 0.5\n\nconst mapProgressToValues = interpolate(\n  [0, 1],\n  [\n    { x: 0, color: \"#fff\" },\n    { x: 100, color: \"#000\" }\n  ]\n)\nmapProgressToValues(0.5) // { x: 50, color: \"#888\" }\n\nconst rescale = interpolate(\n  [0, 1],\n  [100, 200],\n  { clamp: false }\n)\nrescale(2) // 300\n\\`\\`\\`\n\n#### Options\n\n\\`interpolate\\` accepts an optional third argument, an object of options.\n\n- \\`clamp\\`: Clamps values to within given range. Defaults to \\`true\\`.\n- \\`ease\\`: An \\`Easing\\` function, or array of easing functions, to ease the interpolation of each segment.\n- \\`mixer\\`: A function that, when provided a \\`from\\` and \\`to\\` value, will return a new function that accepts a progress value between \\`0\\` and \\`1\\` to mix between those two values. For integration with libraries like Flubber.\n\n#### isPoint\n\nReturns \\`true\\` if the provided argument is a 2D point.\n\n\\`\\`\\`javascript\nimport { isPoint } from \"popmotion\"\n\nisPoint({ x: 0 }) // false\nisPoint({ x: 0, y: 0 }) // true\n\\`\\`\\`\n\n#### isPoint3D\n\nReturns \\`true\\` if the provided argument is a 3D point.\n\n\\`\\`\\`javascript\nimport { isPoint3D } from \"popmotion\"\n\nisPoint3D({ x: 0 }) // false\nisPoint3D({ x: 0, y: 0 }) // false\nisPoint3D({ x: 0, y: 0, z: 0 }) // true\n\\`\\`\\`\n\n#### mix\n\nWill mix between two values, given \\`progress\\` as a third argument.\n\n\\`\\`\\`javascript\nimport { mix } from \"popmotion\"\n\nmix(0, 100, 0.5) // 50\nmix(0, 100, 2) // 200\n\\`\\`\\`\n\n#### mixColor\n\nReturns a function that, when provided a \\`progress\\` value, will mix between two colors. Accepts hex, rgba and hsla colors.\n\n\\`\\`\\`javascript\nimport { mixColor } from \"popmotion\"\n\nmixColor(\"#000\", \"#fff\")(0.5) // \"rgba(125, 125, 125, 1)\"\n\\`\\`\\`\n\n#### mixComplex\n\nReturns a function that, when provided a \\`progress\\` value, will mix between two strings with the same order of numbers and colors.\n\n\\`\\`\\`javascript\nimport { mixComplex } from \"popmotion\"\n\nmixComplex(\"100px #fff\", \"0px #000\")(0.5) // \"50px rgba(125, 125, 125, 1)\"\n\\`\\`\\`\n\n#### pointFromVector\n\nGiven a point, angle in degrees, and distance, will return a new point.\n\n\\`\\`\\`javascript\nimport { pointFromVector } from \"popmotion\"\n\nconst point = { x: 0, y: 0 }\nconst angle = 45\nconst distance = 100\n\npointFromVector(point, angle, distance)\n\\`\\`\\`\n\n#### progress\n\nGiven a min and a max range, and a value, will return the \\`progress\\` of the value within the range as normalised to a \\`0\\`-\\`1\\` range.\n\n\\`\\`\\`javascript\nimport { progress } from \"popmotion\"\n\nconst min = 100\nconst max = 200\nprogress(min, max, 150) // 0.5\n\\`\\`\\`\n\n#### radiansToDegrees\n\nConverts radians to degrees.\n\n\\`\\`\\`javascript\nimport { radiansToDegrees } from \"popmotion\"\n\nradiansToDegrees(0.785) // 45\n\\`\\`\\`\n\n#### snap\n\nCreates a function that will snap numbers to the nearest in a provided array or to a regular interval.\n\n\\`\\`\\`javascript\nimport { snap } from \"popmotion\"\n\n// Snap to regular intervals\nconst snapTo = snap(45);\n\nsnapTo(1); // 0\nsnapTo(40); // 45\nsnapTo(50); // 45\nsnapTo(80); // 90\n\n// Snap to values in an array\nconst snapTo = snap([-100, -50, 100, 200]);\n\nsnapTo(-200); // -100\nsnapTo(-76); // -100\nsnapTo(-74); // -50\n\\`\\`\\`\n\n#### toDecimal\n\nRounds a number to a specific decimal place.\n\n\\`\\`\\`javascript\nimport { toDecimal } from \"popmotion\"\n\ntoDecimal(3.3333); // 3.33\ntoDecimal(6.6666, 1); // 6.67\n\\`\\`\\`\n\n#### velocityPerFrame\n\n\\`\\`\\`javascript\nimport { velocityPerFrame } from \"popmotion\"\n\nvelocityPerFrame(50, 16.7); // 0.835\n\\`\\`\\`\n\n#### velocityPerSecond\n\n\\`\\`\\`javascript\nimport { velocityPerSecond } from \"popmotion\"\n\nvelocityPerSecond(1, 16.7); // 59.880...\n\\`\\`\\`\n\n#### wrap\n\n\\`\\`\\`javascript\nimport { wrap } from \"popmotion\"\n\nwrap(0, 1, 0.5); // 0.5\nwrap(0, 1, 1.5); // 0.5\n\\`\\`\\`\n\n`);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/popcorn/index.js",
    "content": "import PopcornHomepage from '~/templates/Popcorn';\n\nexport default () => <PopcornHomepage />;\n"
  },
  {
    "path": "packages/site/pages/pose/api.js",
    "content": "import { Fragment } from 'react';\nimport GlobalTemplate from '~/templates/global/Template';\nimport ContentPage from '~/templates/global-new/ContentPage';\nimport { Section, PageHeader } from '~/templates/global-new/styled';\nimport MenuPage from '~/templates/content/MenuPage';\n\nexport default () => (\n  <GlobalTemplate\n    title=\"API | Pose\"\n    description=\"Popmotion Pose is a declarative motion library for HTML, SVG and React\"\n    theme=\"pose\"\n  >\n    <ContentPage section=\"api\">\n      <Section>\n        <PageHeader>API</PageHeader>\n        <MenuPage section=\"api\" />\n      </Section>\n    </ContentPage>\n  </GlobalTemplate>\n);\n"
  },
  {
    "path": "packages/site/pages/pose/examples.js",
    "content": "import ContentTemplate from '~/templates/content/Template';\nimport { Centered } from '~/templates/global/grid';\nimport styled from 'styled-components';\n\nconst Choose = styled(Centered.withComponent('h2'))`\n  color: #333;\n  margin: 0 auto;\n  display: block;\n  text-align: center;\n  font-size: 36px;\n  font-weight: bold;\n  border: 2px dashed #333;\n  margin-top: 50px;\n  padding: 40px;\n  border-radius: 20px;\n`;\n\nexport default () => (\n  <ContentTemplate\n    title=\"Examples\"\n    theme=\"pose\"\n    description=\"Interactive examples for the Pose animation library\"\n    section=\"examples\"\n  >\n    <Choose>Choose an example from the menu</Choose>\n  </ContentTemplate>\n);\n"
  },
  {
    "path": "packages/site/pages/pose/index.js",
    "content": "import PoseHomepage from '~/templates/Pose';\n\nexport default () => <PoseHomepage />;"
  },
  {
    "path": "packages/site/pages/pure/api/action.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Action\n\nAction is a simplified Rx-inspired reactive stream focused on animation.\n\n**Every Popmotion animation and input is an action.**\n\nWhen an action is started, it returns a simple interface that includes **at least** a \\`stop\\` method.\n\n## Import\n\n\\`\\`\\`javascript\nimport { action } from 'popmotion';\n\\`\\`\\`\n\n## Usage\n\n### Definition\n\nThe \\`action\\` factory takes one argument, an \\`init\\` function.\n\nThis is a function that is provided an object of \\`update\\`, \\`complete\\`, and \\`error\\` functions.\n\nUsage of these functions is optional. Your action may call all or just some of them:\n\n\\`\\`\\`javascript\naction(({ update, complete, error }) => {\n  update(1);\n});\n\\`\\`\\`\n\n### Initialisation\n\n\\`action\\` returns a \\`start\\` method. This also accepts an object of \\`update\\`, \\`complete\\`, and \\`error\\` functions.\n\nWhen called, the \\`init\\` function is provided these functions, and a **new instance** of the action is created.\n\nCalling \\`start\\` multiple times will create multiple, separate instances of the action.\n\nFor example:\n\n\\`\\`\\`javascript\nconst foo = action(({ update }) => {\n  let i = 0;\n  setInterval(() => update(i++), 50);\n});\n\nfoo.start({\n  update: (v) => console.log(v)\n}); // 0, 1, 2...\n\\`\\`\\`\n\nIf \\`start\\` is passed **only a function**, that is assigned to the \\`update\\` function:\n\n\\`\\`\\`javascript\nfoo.start((v) => console.log(v)); // 0, 1, 2...\n\\`\\`\\`\n\nWe can also listen for the \\`complete\\` event like this:\n\n\\`\\`\\`javascript\nconst foo = action(({ update, complete }) => {\n  let i = 0;\n  setInterval(() => {\n    update(i++);\n    if (i === 10) complete();\n  }, 50);\n});\n\nfoo.start({\n  update: (v) => console.log(v), // ...8, 9, 10\n  complete: () => console.log('complete!')\n});\n\\`\\`\\`\n\n### Interface\n\nThe \\`init\\` function can **optionally** return an API.\n\nFor instance, we might use this to stop a timer:\n\n\\`\\`\\`javascript\nconst foo = action(({ update }) => {\n  const interval = setInterval(() => update('ping!'), 100);\n\n  return {\n    stop: () => clearInterval(interval)\n  };\n});\n\nconst bar = foo.start(console.log);\nsetTimeout(() => bar.stop(), 1000);\n\\`\\`\\`\n\nAny method returned by the action \\`init\\` function will be exposed when an action instance is created.\n\n### Modification\n\n\\`action\\` is **chainable**, which means it offers methods that can alter the behaviour of the base action. Currently, these are \\`while\\` and \\`pipe\\` (see [Methods](#methods)).\n\nWhen an action is chained, a **new action** is returned. For instance:\n\n\\`\\`\\`javascript\nconst foo = action(({ update }) => {\n  let i = 0;\n  setInterval(() => update(i++), 50);\n});\n\nconst lessThanTen = (v) => v < 10;\nconst log = (v) => console.log(v);\n\nfoo.start(log); // ...8, 9, 10, 11...\nfoo.while(lessThanTen).start(log); // ...8, 9\n\\`\\`\\`\n\n## Methods\n\n### \\`pipe\\`\n\n\\`\\`\\`typescript\npipe(...funcs: (v: any) => any)\n\\`\\`\\`\n\nReturns a **new** action that passes the output of the original action's \\`update\\` through the provided functions, from left to right.\n\n#### Example\n\n\\`\\`\\`javascript\nconst init = ({ update }) => update(10);\nconst double = (v) => v * 2;\nconst px = (v) => v + 'px';\n\naction(init)\n  .pipe(double, px)\n  .start((v) => console.log(v)); // '20px'\n\\`\\`\\`\n\n### \\`start\\`\n\n\\`\\`\\`typescript\nstart(update: (v: any) => void)\nstart({\n  complete? () => void,\n  error?: (err: any) => void,\n  update?: (v: any) => void\n})\nstart(reaction)\n\\`\\`\\`\n\nStarts the action by running its initiation function, and returning its API.\n\nEvery interface returned by a \\`start\\` call, **regardless of the API returned from the observable**, will return at least a \\`stop\\` function.\n\nIt can be provided either an \\`update\\` function, or an object with \\`update\\`, \\`complete\\` and \\`error\\` functions.\n\n#### Example\n\n\\`\\`\\`javascript\n// Doesn't return an API\nconst foo = action(({ update }) => update(1)).start();\nfoo.stop();\n\n// Returns a custom API\nconst bar = action(({ update }) => {\n  let i = 0;\n  setInterval(() => update(i), 100);\n\n  return {\n    setOutput: (v) => i = v\n  };\n}).start();\nbar.setOutput(2);\nsetTimeout(() => bar.stop(), 1000);\n\\`\\`\\`\n\n### \\`while\\`\n\n\\`\\`\\`typescript\nwhile(predicate: (v: any) => boolean)\n\\`\\`\\`\n\nReturns a new action, that will continue to run **while** the updated values match the provided predicate.\n\nWhen the predicate function returns \\`false\\`, the action will \\`complete\\`.\n\n### Example\n\n\\`\\`\\`javascript\nlet latest = 0;\n\nconst init = ({ update }) => {\n  let i = latest;\n  setInterval(() => update(i++), 50);\n};\n\naction(init)\n  .while((v) => v < 10)\n  .start({\n    update: (v) => latest = v,\n    complete: () => console.log(latest) // 9\n  });\n\\`\\`\\`\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"action\"\n    section=\"api\"\n    undefined\n    title=\"Action\"\n    description=\"Create a reactive stream of values.\"\n    published=\"\"\n    theme=\"pure\"\n    next=\"animations\"\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/calc.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Calculators\n\nPopmotion provides a series of simple functions useful in UI calculations.\n\n## Import\n\n\\`\\`\\`javascript\nimport { calc } from 'popmotion';\n\\`\\`\\`\n\n## Methods\n\n### \\`angle\\`\nCalculate the angle between two 2D points, in degrees.\n\n\\`type Point = { x: number, y: number }\\`\n\n\\`angle(a: Point, b: Point)\\`\n\n\\`\\`\\`javascript\nconst a = { x: 0, y: 0 };\nconst b = { x: 1, y: 1 };\ncalc.angle(a, b); // 45\n\\`\\`\\`\n\n### \\`degreesToRadians\\`\nConvert degrees to radians.\n\n\\`degreesToRadians(degrees: number)\\`\n\n\\`\\`\\`javascript\ncalc.degreesToRadians(45); // 0.7853981633974483\n\\`\\`\\`\n\n### \\`dilate\\`\nDilate the difference between two values.\n\n\\`dilate(a: number, b: number, dilation: number)\\`\n\n\\`\\`\\`javascript\ncalc.dilate(0, 80, .5); // 40\ncalc.dilate(100, 200, 2); // 300\n\\`\\`\\`\n\n### \\`distance\\`\nCalculate the distance between 1D, 2D or 3D points.\n\n\\`type Point = { x: number, y: number, z?: number }\\`\n\n\\`distance(a: number | Point, b: number | Point)\\`\n\n\\`\\`\\`javascript\ncalc.distance(-100, 100); // 200\ncalc.distance({ x: 0, y: 0 }, { x: 1, y: 1}); // 1.4142135623730951\ncalc.distance({ x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 10 }); // 10\n\\`\\`\\`\n\n### \\`getProgressFromValue\\`\nCalculate a progress (0 - 1) from a value and range.\n\n\\`getProgressFromValue(min: number, max: number, value: number)\\`\n\n\\`\\`\\`javascript\ncalc.getProgressFromValue(0, 100, 50); // 0.5\ncalc.getProgressFromValue(100, 200, 50); // -0.5\n\\`\\`\\`\n\n### \\`getValueFromProgress\\`\nCalculate a value from a progress (0 - 1) and range.\n\n\\`getValueFromProgress(min: number, max: number, value: number)\\`\n\n\\`\\`\\`javascript\ncalc.getValueFromProgress(100, 200, 0.5); // 150\ncalc.getValueFromProgress(100, 200, -1); // 0\n\\`\\`\\`\n\n### \\`pointFromAngleAndDistance\\`\nGiven an origin point, angle in degrees and distance, returns a new point.\n\n\\`pointFromAngleAndDistance(origin: Point, angle: number, distance: number)\\`\n\n\\`\\`\\`javascript\ncalc.pointFromAngleAndDistance({ x: 0, y: 0 }, 45, 100);\n/*\n  {\n    x: 70.71067811865476,\n    y: 70.71067811865474\n  }\n*/\n\\`\\`\\`\n\n### \\`radiansToDegrees\\`\nConvert radians to degrees.\n\n\\`radiansToDegrees(radians: number)\\`\n\n\\`\\`\\`javascript\ncalc.radiansToDegrees(0.7853981633974483); // 45\n\\`\\`\\`\n\n### \\`smooth\\`\nFramerate-independent value smoothing.\n\n\\`smooth(newValue: number, oldValue: number, frameDuration: number, smoothing: number)\\`\n\n### \\`speedPerFrame\\`\nConvert speed per second into speed per frame.\n\n\\`speedPerFrame(speedPerSecond: number, frameDuration: number)\\`\n\n### \\`speedPerSecond\\`\nConvert speed per frame into speed per second.\n\n\\`speedPerSecond(speedPerFrame: number, frameDuration: number)\\`\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"calc\"\n    section=\"api\"\n    undefined\n    title=\"Calculators\"\n    description=\"Simple functions useful in UI calculations.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/chain.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Chain\n\nChain a sequence of actions, move to the next when the current one completes.\n\n## Import\n\n\\`\\`\\`javascript\nimport { chain } from 'popmotion';\n\\`\\`\\`\n\n## Usage\n\n\\`\\`\\`javascript\nchain(\n  tween({ to: 300 }),\n  spring({ from: 300, to: 0 })\n).start({\n  update: (v) => console.log(v),\n  complete: () => console.log('All actions complete')\n})\n\\`\\`\\`\n\n## Methods\n\n### Action methods\n\n\\`chain()\\` returns:\n\n- \\`filter((v: any) => boolean)\\`: Returns a new action that filters out values when the provided function returns \\`false\\`.\n- \\`pipe(...funcs: Array<(v) => v)\\`: Returns a new action that will run \\`update\\` values through this sequence of functions.\n- \\`start(update | { update, complete })\\`: Starts the action and returns a subscription.\n- \\`while((v: any) => boolean)\\`: Returns a new action that will \\`complete\\` when the provided function returns \\`false\\`.\n\n\n### Subscription methods\n\n\\`chain().start()\\` returns:\n\n- \\`stop(): void\\`\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"chain\"\n    section=\"api\"\n    category=\"compositors\"\n    title=\"Chain\"\n    description=\"Chain a sequence of actions, move to the next when the current one completes.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/composite.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Composite\n\nControl a named map of actions, and output to the same structure.\n\n## Import\n\n\\`\\`\\`javascript\nimport { composite } from 'popmotion';\n\\`\\`\\`\n\n## Usage\n\n\\`\\`\\`javascript\ncomposite({\n  x: tween({ from: 60, to: 400 }),\n  y: physics({ from: 60, velocity: 300 })\n}).start(({ x, y }) => {});\n\\`\\`\\`\n\n\\`composite\\` outputs at most once per frame.\n\n## Methods\n\n### Action methods\n\n\\`composite()\\` returns:\n\n- \\`filter((v: any) => boolean)\\`: Returns a new action that filters out values when the provided function returns \\`false\\`.\n- \\`pipe(...funcs: Array<(v) => v)\\`: Returns a new action that will run \\`update\\` values through this sequence of functions.\n- \\`start(update | { update, complete })\\`: Starts the action and returns a subscription.\n- \\`while((v: any) => boolean)\\`: Returns a new action that will \\`complete\\` when the provided function returns \\`false\\`.\n\n### Subscription methods\n\n\\`composite().start()\\` returns:\n\n- \\`stop(): void\\`\n\n**Note:** If all actions return the same API, for instance all composed actions are \\`tween\\`s, the \\`composite\\` subscription will also return a version of that API that controls all child actions.\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"composite\"\n    section=\"api\"\n    category=\"compositors\"\n    title=\"Composite\"\n    description=\"Control a map of actions and output to that same structure.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/crossfade.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Crossfade\n\nFade between two numerical actions.\n\n## Import\n\n\\`\\`\\`javascript\nimport { crossfade } from 'popmotion';\n\\`\\`\\`\n\n## Usage\n\nExample: blend from one tween to another:\n\n\\`\\`\\`javascript\nconst blendTweens = crossfade(\n  tween({ from: 0, to: 500, elapsed: 200 }),\n  tween({ from: 500, to: 0 })\n).start((v) => console.log(v));\n\ntween({ duration: 100 }).start(blendTweens.setBalance);\n\\`\\`\\`\n\n## Methods\n\n### Action methods\n\n\\`crossfade()\\` returns:\n\n- \\`filter((v: any) => boolean)\\`: Returns a new action that filters out values when the provided function returns \\`false\\`.\n- \\`pipe(...funcs: Array<(v) => v)\\`: Returns a new action that will run \\`update\\` values through this sequence of functions.\n- \\`start(update | { update, complete })\\`: Starts the action and returns a subscription.\n- \\`while((v: any) => boolean)\\`: Returns a new action that will \\`complete\\` when the provided function returns \\`false\\`.\n\n\n### Subscription methods\n\n\\`crossfade().start()\\` returns:\n\n- \\`setBalance(): this\\`: Sets the balance of blended output from the first action (\\`0\\`) to the second (\\`1\\`).\n- \\`stop(): void\\`\n\n## Example\n\n<CodePen id=\"ooPjxj\" />\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"crossfade\"\n    section=\"api\"\n    category=\"compositors\"\n    title=\"Crossfade\"\n    description=\"Fade between two numerical actions.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/css.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n[Moved to the Stylefire docs](/stylefire/api/html).`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"css\"\n    section=\"api\"\n    category=\"stylefire\"\n    title=\"CSS\"\n    description=\"CSS Styler optimised for animation.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/decay.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Decay\n\n\\`decay\\` returns an [action](/api/action) that exponentially decelerates a number and velocity to an automatically generated target value. This target can be modified by the user.\n\nThis animation is particularly useful for implementing momentum scrolling.\n\n## Import\n\n\\`\\`\\`javascript\nimport { decay } from 'popmotion';\n\\`\\`\\`\n\n## Usage\n\n\\`\\`\\`javascript\ndecay({ velocity: 200, from: 50 })\n  .start((v) => console.log(v));\n\\`\\`\\`\n\n## Props\n\n- \\`velocity: number = 0\\`: Initial velocity to decelerate from.\n- \\`from: number = 0\\`: Number to apply movement to.\n- \\`power: number = 0.8\\`: A constant with which to calculate a target value. Higher power = further target. \\`0.8\\` should be okay.\n- \\`timeConstant: number = 350\\`: Adjusting the time constant will change the duration of the deceleration, thereby affecting its feel.\n- \\`restDelta: number = 0.5\\`: Automatically completes the action when the calculated value is this far away from the target.\n- \\`modifyTarget: (v: number) => number\\`: A function that receives the calculated target and returns a new one. Useful for snapping the target to a grid, for example.\n\n## Methods\n\n### Action methods\n\n\\`decay()\\` returns:\n\n- \\`filter((v: any) => boolean)\\`: Returns a new action that filters out values when the provided function returns \\`false\\`.\n- \\`pipe(...funcs: Array<(v) => v)\\`: Returns a new action that will run \\`update\\` values through this sequence of functions.\n- \\`start(update | { update, complete })\\`: Starts the action and returns a subscription.\n- \\`while((v: any) => boolean)\\`: Returns a new action that will \\`complete\\` when the provided function returns \\`false\\`.\n\n\n### Subscription methods\n\n\\`decay().start()\\` returns:\n\n- \\`stop(): void\\`\n\n## Example\n\n<CodePen id=\"Kyewbv\" />\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"decay\"\n    section=\"api\"\n    category=\"animation\"\n    title=\"Decay\"\n    description=\"Exponential deceleration, primarily for use in momentum scrolling.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/delay.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Delay\n\nFires \\`complete\\` after the defined interval.\n\n## Import\n\n\\`\\`\\`javascript\nimport { delay } from 'popmotion';\n\\`\\`\\`\n\n## Usage\n\n\\`\\`\\`javascript\ndelay(100).start({\n  complete: () => console.log('complete!')\n});\n\\`\\`\\`\n\nUseful for delaying actions in a \\`chain\\`.\n\n\\`\\`\\`javascript\nchain(\n  delay(100),\n  tween({ to: 400, duration: 500 })\n);\n\\`\\`\\`\n\n### Action methods\n\n\\`delay()\\` returns:\n\n- \\`start(update | { update, complete })\\`: Starts the action and returns a subscription.\n\n### Subscription methods\n\n\\`delay().start()\\` returns:\n\n- \\`stop(): void\\`\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"delay\"\n    section=\"api\"\n    category=\"compositors\"\n    title=\"Delay\"\n    description=\"Fires complete after the defined interval.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/easing.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Easing\n\nEasing functions make tweened motion look more natural by emulating the changes in velocity experienced by objects in the real world.\n\nThey work by accepting a progress value from \\`0\\` to \\`1\\`, and returning a new one.\n\nPopmotion comes with a number of preset easing functions, and provides methods to create new easing functions.\n\n## Import\n\n\\`\\`\\`javascript\nimport { easing } from 'popmotion';\n\\`\\`\\`\n\n## Example\n\n\\`\\`\\`javascript\nimport { tween, easing } from 'popmotion';\n\ntween({\n  ease: easing.easeOut\n}).start();\n\\`\\`\\`\n\n## Presets\n\nPopmotion comes with the following preset easing functions:\n\n- \\`cubicBezier\\`\n- \\`linear\\`\n- \\`easeIn\\`, \\`easeOut\\`, \\`easeInOut\\`\n- \\`circIn\\`, \\`circOut\\`, \\`circInOut\\`\n- \\`backIn\\`, \\`backOut\\`, \\`backInOut\\`\n- \\`anticipate\\`\n\nTry them out by editing this live example:\n\n\\`\\`\\`marksy\n<Example template=\"Ball\" id=\"b\">{\\`\nconst ball = document.querySelector('#b .ball');\nconst ballStyler = styler(ball);\n\ntween({\n  to: 300,\n  duration: 300,\n  ease: easing.linear\n}).start(ballStyler.set('x'));\n\\`}</Example>\n\\`\\`\\`\n\n## Easing creation\n\nPopmotion provides the following functions to create your own easing functions:\n\n### \\`cubicBezier\\`\nCreates cubic bezier curve easing function.\n\n\\`\\`\\`javascript\nconst { cubicBezier } = easing;\nconst longTail = cubicBezier(0, .42, 0, 1);\n\\`\\`\\`\n\n### \\`createReversedEasing\\`\nReverses the provided easing function.\n\n\\`\\`\\`javascript\nconst { anticipate, createReversedEasing } = easing;\nconst anticipateOut = createReversedEasing(anticipate);\n\\`\\`\\`\n\n### \\`createMirroredEasing\\`\nMirrors the provided easing function.\n\n\\`\\`\\`javascript\nconst { anticipate, createMirroredEasing } = easing;\nconst anticipateInAndOut = createMirroredEasing(anticipate);\n\\`\\`\\`\n\n### \\`createExpoIn\\`\nCreates an easing function based on the exponent function \\`progress ** exponent\\`. \\`easeIn\\` is \\`createExpoIn(2)\\`.\n\n\\`\\`\\`javascript\nconst { createExpoIn } = easing;\nconst strongerEaseIn = createExpoIn(3);\n\\`\\`\\`\n\n### \\`createBackIn\\`\nCreates an easing function with an overshoot. \\`backIn\\` is \\`createBackIn(1.525)\\`.\n\n\\`\\`\\`javascript\nconst { createBackIn, createReversedEasing } = easing;\nconst strongerBackOut = createReversedEasing(createBackIn(3));\n\\`\\`\\`\n\n### \\`createAnticipateEasing\\`\nCreates an easing function with a small anticipate and ease out. \\`anticipate\\` is \\`createAnticipateEasing(1.525)\\`.\n\n\\`\\`\\`javascript\nconst { createAnticipateEasing } = easing;\nconst strongerAnticipate = createAnticipateEasing(3);\n\\`\\`\\`\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"easing\"\n    section=\"api\"\n    undefined\n    title=\"Easing\"\n    description=\"Functions that speed or slow a tween over time.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/every-frame.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Every Frame\n\n\\`everyFrame\\` fires once per frame, and provides \\`update\\` with the duration of time since it started.\n\n## Import\n\n\\`\\`\\`javascript\nimport { everyFrame } from 'popmotion';\n\\`\\`\\`\n\n## Usage\n\n\\`\\`\\`javascript\neveryFrame()\n  .start((timeSinceStart) => console.log(timeSinceStart));\n\\`\\`\\`\n\n## Methods\n\n### Action methods\n\n\\`everyFrame()\\` returns:\n\n- \\`filter((v: any) => boolean)\\`: Returns a new action that filters out values when the provided function returns \\`false\\`.\n- \\`pipe(...funcs: Array<(v) => v)\\`: Returns a new action that will run \\`update\\` values through this sequence of functions.\n- \\`start(update | { update, complete })\\`: Starts the action and returns a subscription.\n- \\`while((v: any) => boolean)\\`: Returns a new action that will \\`complete\\` when the provided function returns \\`false\\`.\n\n\n### Subscription methods\n\n\\`everyFrame().start()\\` returns:\n\n- \\`stop(): void\\`\n\n## Example\n\n<CodePen id=\"XzYJvP\" />\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"every-frame\"\n    section=\"api\"\n    category=\"animation\"\n    title=\"Every Frame\"\n    description=\"Fires with timestamp, once every frame.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/framesync.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Framesync\n\nA tiny frame scheduler for performantly batching reads and renders.\n\nSegregating actions that read and write to the DOM will avoid [layout thrashing](https://developers.google.com/web/fundamentals/performance/rendering/avoid-large-complex-layouts-and-layout-thrashing).\n\nPopmotion batches updates on the \\`frameUpdate\\` step, and Stylefire batches renders on the \\`frameRender\\` step.\n\n## Install\n\n**Framesync is installed as part of Popmotion.**\n\nTo use as a standalone library, install with:\n\n\\`\\`\\`bash\nnpm install framesync --save\n\\`\\`\\`\n\n## Usage\n\nThe Framesync render loop executes four sequential steps, once per frame.\n\n- \\`frameStart\\`\n- \\`frameUpdate\\`\n- \\`frameRender\\`\n- \\`frameEnd\\`\n\nDevelopers can set any function to run at any of these steps using the \\`on\\` and \\`cancel\\` callbacks:\n\n- \\`onFrameStart\\`, \\`cancelOnFrameStart\\`\n- \\`onFrameUpdate\\`, \\`cancelOnFrameUpdate\\`\n- \\`onFrameRender\\`, \\`cancelOnFrameRender\\`\n- \\`onFrameEnd\\`, \\`cancelOnFrameEnd\\`\n\nFramesync also exports some time-measurement methods:\n- \\`currentTime\\`: The current time as measured by the host platform's most accurate \\`now\\` function.\n- \\`currentFrameTime\\`: The time the current \\`requestAnimationFrame\\` was initiated.\n- \\`timeSinceLastFrame\\`: The duration between the previous frame and the current \\`currentFrameTime\\`\n\n### Example\n\n\\`\\`\\`javascript\nimport {\n  timeSinceLastFrame,\n  onFrameStart,\n  cancelFrameStart\n} from 'framesync';\n\nfunction logTimeSinceLastFrame() {\n  console.log(timeSinceLastFrame());\n  onFrameStart(logTimeSinceLastFrame);\n}\n\nonFrameStart(logTimeSinceLastFrame);\n\nfunction stopLogging() {\n  cancelOnFrameStart(logTimeSinceLastFrame);\n}\n\nsetTimeout(stopLogging, 5000);\n\\`\\`\\``);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"framesync\"\n    section=\"api\"\n    undefined\n    title=\"Framesync\"\n    description=\"Schedule functions to run at specific steps on the render loop.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/keyframes.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Keyframes\n\nKeyframes accepts an array of \\`values\\` and will animate between each in sequence.\n\nTiming is defined with a combination of \\`duration\\`, \\`easings\\` and \\`times\\` properties (see [Methods](#methods))\n\nIt returns a [\\`tween\\`](/api/tween), which allows the use of \\`ease\\`, \\`loop\\`, \\`flip\\` and \\`yoyo\\` props, as well as tween methods like \\`pause\\` and \\`resume\\`.\n\n## Import\n\n\\`\\`\\`javascript\nimport { keyframes } from 'popmotion';\n\\`\\`\\`\n\n## Usage\n\n\\`keyframes\\` accepts numbers:\n\n\\`\\`\\`javascript\nkeyframes({\n  values: [0, 100, 200],\n  duration: 1000,\n  times: [0, 0.2, 1],\n  easings: [ease.linear, ease.cubicBezier(.17,.67,.83,.67)]\n}).start((v) => console.log(v));\n\\`\\`\\`\n\nColors:\n\n\\`\\`\\`javascript\nkeyframes({\n  values: ['#f00', '#e533a1', 'rgba(0, 0, 0, 0)']\n})\n\\`\\`\\`\n\nObjects:\n\n\\`\\`\\`javascript\nkeyframes({\n  values: [\n    {\n      x: 100,\n      background: '#f00'\n    },\n    {\n      x: 200,\n      background: '#000'\n    }\n  ]\n});\n\\`\\`\\`\n\nAnd arrays:\n\n\\`\\`\\`javascript\nkeyframes({\n  values: [\n    [0, 100, 300],\n    [100, 45, 0]\n  ]\n})\n\\`\\`\\`\n\n## Props\n\n- \\`values: number[]\\`: An array of numbers to animate between.\n- \\`duration?: number = 300\\`: Total duration of animation, in milliseconds.\n- \\`easings?: Easing | Easing[]\\`: An array of easing functions for each generated tween, or a single easing function applied to all tweens. This array should be \\`values.length - 1\\`. Defaults to \\`easeOut\\`.\n- \\`times?: number[]\\`: An array of numbers between \\`0\\` and \\`1\\`, representing \\`0\\` to \\`duration\\`, that represent at which point each number should be hit. Defaults to an array of evenly-spread durations will be calculated.\n- \\`elapsed?: number = 0\\`: Duration of animation already elapsed, in milliseconds.\n- \\`ease?: Easing | Vector[Easing] = easeOut\\`: A function, given a progress between \\`0\\` and \\`1\\`, that returns a new progress value. Used to affect the rate of playback across the duration of the animation.\n- \\`loop?: number = 0\\`: Number of times to loop animation on \\`complete\\`.\n- \\`flip?: number = 0\\`: Number of times to flip animation on \\`complete\\`.\n- \\`yoyo?: number = 0\\`: Number of times to reverse tween on \\`complete\\`.\n\n### Tween props\n\nAs \\`keyframes\\` returns a [\\`tween\\`](/api/tween), the following properties can also be provided:\n\n- \\`loop: number = 0\\`: Number of times to loop animation on \\`complete\\`.\n- \\`flip: number = 0\\`: Number of times to flip animation on \\`complete\\`.\n- \\`yoyo: number = 0\\`: Number of times to reverse tween on \\`complete\\`.\n\n## Methods\n\n### Action methods\n\n\\`keyframes()\\` returns:\n\n- \\`filter((v: any) => boolean)\\`: Returns a new action that filters out values when the provided function returns \\`false\\`.\n- \\`pipe(...funcs: Array<(v) => v)\\`: Returns a new action that will run \\`update\\` values through this sequence of functions.\n- \\`start(update | { update, complete })\\`: Starts the action and returns a subscription.\n- \\`while((v: any) => boolean)\\`: Returns a new action that will \\`complete\\` when the provided function returns \\`false\\`.\n\n### Subscription methods\n\n\\`keyframes().start()\\` returns:\n\n- \\`getElapsed(): number\\`: Returns time elapsed in milliseconds.\n- \\`getProgress(): number\\`: Returns animation progress as a value of \\`0\\`-\\`1\\`.\n- \\`seek(progress: number): this\\`: Seeks animation to this position as a value of \\`0\\`-\\`1\\`.\n- \\`pause(): this\\`\n- \\`resume(): this\\`\n- \\`reverse(): this\\`: Reverses the direction of playback. \n- \\`stop(): void\\`\n\n## Example\n\n<CodePen id=\"JOZGdp\" />\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"keyframes\"\n    section=\"api\"\n    category=\"animation\"\n    title=\"Keyframes\"\n    description=\"Animate through a sequence of states.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/listen.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Listen\n\n\\`listen\\` creates DOM event listeners as an action stream.\n\n## Import\n\n\\`\\`\\`javascript\nimport { listen } from 'popmotion';\n\\`\\`\\`\n\n## Usage\n\nTo listen to an event, provide a DOM element and an event name to \\`listen\\`:\n\n\\`\\`\\`javascript\nlisten(document, 'mousemove')\n  .start((e) => console.log(e));\n\\`\\`\\`\n\n### Multiple events\n\nMultiple events can be subscribed to by providing a space-delimited string:\n\n\\`\\`\\`javascript\nlisten(document, 'touchstart touchend')\n\\`\\`\\`\n\n### Chainable actions\n\nThe primary benefit of using \\`listen\\` is passing each event through the chainable actions like \\`filter\\`. For instance, here's an event listener that only fires when two or more touches are detected:\n\n\\`\\`\\`javascript\nconst onMultitouch = listen(document, 'touchstart')\n  .filter(({ touches }) => touches.length > 1);\n\nonMultitouch.start((e) => ...);\n\\`\\`\\`\n\n### Options\n\n\\`listen\\` optionally accepts a third argument of options:\n\n\\`\\`\\`typescript\ntype EventOpts = boolean | {\n  capture?: boolean;\n  passive?: boolean;\n  once?: boolean;\n};\n\nlisten(element: Element, eventNames: string, opts?: EventOpts): Action\n\\`\\`\\`\n\n## Methods\n\n### Action methods\n\n\\`listen()\\` returns:\n\n- \\`filter((v: any) => boolean)\\`: Returns a new action that filters out values when the provided function returns \\`false\\`.\n- \\`pipe(...funcs: Array<(v) => v)\\`: Returns a new action that will run \\`update\\` values through this sequence of functions.\n- \\`start(update | { update, complete })\\`: Starts the action and returns a subscription.\n- \\`while((v: any) => boolean)\\`: Returns a new action that will \\`complete\\` when the provided function returns \\`false\\`.\n\n### Subscription methods\n\n\\`listen().start()\\` returns:\n\n- \\`stop(): void\\`\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"listen\"\n    section=\"api\"\n    category=\"input\"\n    title=\"Listen\"\n    description=\"Creates a DOM event listener as an action stream.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/merge.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Merge\n\nCombine multiple actions into one output.\n\n## Import\n\n\\`\\`\\`javascript\nimport { merge } from 'popmotion';\n\\`\\`\\`\n\n## Usage\n\n\\`\\`\\`javascript\nmerge(\n  tween(),\n  action(({ update }) => update(1)),\n  physics({ velocity: 1000 })\n).start((v) => console.log(v));\n\\`\\`\\`\n\n## Methods\n\n### Action methods\n\n\\`merge()\\` returns:\n\n- \\`filter((v: any) => boolean)\\`: Returns a new action that filters out values when the provided function returns \\`false\\`.\n- \\`pipe(...funcs: Array<(v) => v)\\`: Returns a new action that will run \\`update\\` values through this sequence of functions.\n- \\`start(update | { update, complete })\\`: Starts the action and returns a subscription.\n- \\`while((v: any) => boolean)\\`: Returns a new action that will \\`complete\\` when the provided function returns \\`false\\`.\n\n\n### Subscription methods\n\n\\`merge().start()\\` returns:\n\n- \\`stop(): void\\`\n\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"merge\"\n    section=\"api\"\n    category=\"compositors\"\n    title=\"Merge\"\n    description=\"Combine multiple actions into one output.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/multicast.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Multicast\n\nThe multicast reaction provides a reaction that many other reactions can \\`subscribe\\` to.\n\nIt also helps manage actions: if a \\`multicast\\` reaction is passed to another \\`action\\`, the first \\`action\\` will automatically \\`stop\\`.\n\n## Import\n\n\\`\\`\\`javascript\nimport { multicast } from 'popmotion';\n\\`\\`\\`\n\n## Usage\n\n### Subscription\n\nProvide a reactions to \\`mulitcast.subscribe()\\`:\n\n\\`\\`\\`javascript\nconst foo = multicast();\nfoo.subscribe((v) => console.log('first subscriber', v));\nfoo.subscribe((v) => console.log('second subscriber', v));\n\\`\\`\\`\n\nWhen the multicast reaction is \\`update\\`d, all listeners will fire:\n\n\\`\\`\\`javascript\nfoo.update(5);\n// first subscriber, 5\n// second subscriber, 5\n\\`\\`\\`\n\n### Automatically stop previous action\n\nPassing the multicast reaction to a new action will stop the previous one:\n\n\\`\\`\\`javascript\ntween().start(foo);\nspring().start(foo); // This will stop \\`tween\\`\n\\`\\`\\`\n\n### Chain methods\n\n\\`multicast\\` can be chained in the same way as [actions](/api/action).\n\n\\`\\`\\`javascript\nconst double = (v) => v * 2;\nconst px = (v) => v + 'px';\n\nconst foo = multicast().pipe(double, px);\n\nfoo.update(5); // 10px\n\\`\\`\\`\n\n### Unsubscribe\n\n\\`subscribe\\` returns an \\`unsubscribe\\` method:\n\n\\`\\`\\`javascript\nconst foo = multicast();\nconst sub = foo.subcribe(console.log);\n\nsub.unsubscribe();\n\\`\\`\\`\n\n## Methods\n\n### Multicast methods\n\n\\`multicast()\\` returns:\n\n- \\`filter((v: any) => boolean)\\`: Returns a new action that filters out values when the provided function returns \\`false\\`.\n- \\`pipe(...funcs: Array<(v) => v)\\`: Returns a new reaction that will run \\`update\\` values through this sequence of functions.\n- \\`subscribe(update | { update, complete, error })\\`: Returns a subscription.\n- \\`stop()\\`: Stops current parent action.\n- \\`while((v: any) => boolean)\\`: Returns a new reaction that will \\`complete\\` when the provided function returns \\`false\\`.\n\n### Subscription methods\n\n\\`multicast().subscribe()\\` returns:\n\n- \\`unsubscribe()\\`\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"multicast\"\n    section=\"api\"\n    category=\"reactions\"\n    title=\"Multicast\"\n    description=\"A reaction that multiple reactions can subscribe to.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/multitouch.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Multitouch\n\nTracks multitouch input and outputs a list of active touches, plus scale and rotation delta between the first two touch points.\n\nFor single-point input, generally [pointer](/api/pointer) is more appropriate as it provides a simple, cross-platform interface.\n\n## Import\n\n\\`\\`\\`javascript\nimport { multitouch } from 'popmotion';\n\\`\\`\\`\n\n## Usage\n\n\\`\\`\\`typescript\nmultitouch({\n  preventDefault?: boolean = true,\n  scale?: number,\n  rotate?: number\n})\n\\`\\`\\`\n\n\\`\\`\\`javascript\nmultitouch().start(({ touches, scale, rotate }) => {\n  touches.forEach(({ x, y }) => console.log(x, y))\n});\n\\`\\`\\`\n\n\\`multitouch\\` provides:\n\n- \\`touches: { x: number, y: number }[]\\`: An array of \\`x\\`/\\`y\\` coordinates representing each active finger.\n- \\`scale: number\\`: The distance between the first two fingers since \\`start\\`, represented as a multiplier of the original distance. \\`scale\\` starts from \\`1.0\\`, or the initially provided \\`scale\\`.\n- \\`rotate: number\\`: The angle rotation of the first two fingers as a delta of the original rotation. \\`rotate\\` starts from \\`0.0\\`, or the initially provided \\`rotate\\`.\n\n### Commonly-used properties\n\nIf you often use, for instance, \\`rotate\\`, you can easily create a new action that returns only that value:\n\n\\`\\`\\`javascript\nconst touchRotation = (initialRotate = 0) => multitouch({ rotate: initialRotate })\n  .pipe(({ rotate }) => rotate);\n\ntouchRotation(45).start((rotate) => console.log(rotate));\n\\`\\`\\`\n\n## Props\n\n- \\`preventDefault?: boolean = true\\`\n- \\`scale?: number = 1.0\\`\n- \\`rotate?: number = 0.0\\`\n\n## Methods\n\n### Action methods\n\n\\`multitouch()\\` returns:\n\n- \\`filter((v: any) => boolean)\\`: Returns a new action that filters out values when the provided function returns \\`false\\`.\n- \\`pipe(...funcs: Array<(v) => v)\\`: Returns a new action that will run \\`update\\` values through this sequence of functions.\n- \\`start(update | { update, complete })\\`: Starts the action and returns a subscription.\n- \\`while((v: any) => boolean)\\`: Returns a new action that will \\`complete\\` when the provided function returns \\`false\\`.\n\n### Subscription methods\n\n\\`multitouch().start()\\` returns:\n\n- \\`stop(): void\\`\n\n## Example\n\n<CodePen id=\"LOBjxQ\" />\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"multitouch\"\n    section=\"api\"\n    category=\"input\"\n    title=\"Multitouch\"\n    description=\"Tracks multitouch input.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/parallel.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Parallel\n\nControl an n-dimensional array of actions in parallel, and output as an array.\n\n## Import\n\n\\`\\`\\`javascript\nimport { parallel } from 'popmotion';\n\\`\\`\\`\n\n## Usage\n\n\\`\\`\\`javascript\nparallel(\n  tween({ from: 40, to: 50 }),\n  spring({ to: 500 })\n).start(([ tweenOutput, springOutput ]) => {});\n\\`\\`\\`\n\n\\`parallel\\` outputs max once per frame.\n\n## Methods\n\n### Action methods\n\n\\`parallel()\\` returns:\n\n- \\`filter((v: any) => boolean)\\`: Returns a new action that filters out values when the provided function returns \\`false\\`.\n- \\`pipe(...funcs: Array<(v) => v)\\`: Returns a new action that will run \\`update\\` values through this sequence of functions.\n- \\`start(update | { update, complete })\\`: Starts the action and returns a subscription.\n- \\`while((v: any) => boolean)\\`: Returns a new action that will \\`complete\\` when the provided function returns \\`false\\`.\n\n### Subscription methods\n\n\\`parallel().start()\\` returns:\n\n- \\`stop(): void\\`\n\n**Note:** If all actions return the same API, for instance all composed actions are \\`tween\\`s, the \\`parallel\\` subscription will also return a version of that API that controls all child actions.\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"parallel\"\n    section=\"api\"\n    category=\"compositors\"\n    title=\"Parallel\"\n    description=\"Control multiple actions in parallel and output as an array.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/physics.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Physics\n\nIntegrated simulation of velocity, acceleration, friction and springs.\n\nBecause the simulation is integrated, we can expose \\`set\\` methods that can change the simulation while it is still running.\n\nThis is unlike the differential equations in [decay](/api/decay) and [spring](/api/spring), which can't be changed while in motion (although both offer higher-accuracy simulations which lead to smoother animations).\n\n## Import\n\n\\`\\`\\`javascript\nimport { physics } from 'popmotion';\n\\`\\`\\`\n\n## Usage\n\nTo simulate velocity, we just need to provide a \\`velocity\\` property:\n\n\\`\\`\\`javascript\nphysics({ velocity: 1000 })\n  .start((v) => console.log(v));\n\\`\\`\\`\n\nTo slow down over a duration of time, we can provide a \\`friction\\` prop between \\`0\\` (no friction) and \\`1\\` (dead stop):\n\n\\`\\`\\`javascript\nphysics({ velocity: 1000, friction: 0.8 })\n  .start((v) => console.log(v));\n\\`\\`\\`\n\nFinally, to simulate a spring we need to add \\`to\\` and \\`springStrength\\` properties:\n\n\\`\\`\\`javascript\nphysics({\n  velocity: 1000,\n  friction: 0.8,\n  to: 400,\n  springStrength: 500\n}).start((v) => console.log(v));\n\\`\\`\\`\n\nWe can also provide many properties as \\`Vector\\` types, which are maps or arrays of numbers:\n\n\\`\\`\\`javascript\nphysics({\n  from: 100,\n  to: { x: 30, y: 100, z: 20 },\n  springStrength: 500\n})\n\\`\\`\\`\n\n## Props\n\n- \\`acceleration: number | Vector = 0\\`: Increase \\`velocity\\` by this amount every second.\n- \\`restSpeed: number = 0.001\\`: When absolute speed drops below this value, \\`complete\\` is fired.\n- \\`friction: number | Vector = 0\\`: Amount of friction to apply per frame, from \\`0\\` to \\`1\\`.\n- \\`from: number | Vector = 0\\`: Start simulation from this number.\n- \\`springStrength: number | Vector = 0\\`: If set with \\`to\\`, will spring towards target with this strength.\n- \\`to: number | Vector = 0\\`: If set with \\`springStrength\\`, will gradually \"spring\" towards this value.\n- \\`velocity: number | Vector = 0\\`: Velocity in units per second.\n\n## Methods\n\n### Action methods\n\n\\`physics()\\` returns:\n\n- \\`filter((v: any) => boolean)\\`: Returns a new action that filters out values when the provided function returns \\`false\\`.\n- \\`pipe(...funcs: Array<(v) => v)\\`: Returns a new action that will run \\`update\\` values through this sequence of functions.\n- \\`start(update | { update, complete })\\`: Starts the action and returns a subscription.\n- \\`while((v: any) => boolean)\\`: Returns a new action that will \\`complete\\` when the provided function returns \\`false\\`.\n\n\n### Subscription methods\n\n\\`physics().start()\\` returns:\n\n- \\`set(current: number): this\\`\n- \\`setAcceleration(acceleration: number): this\\`\n- \\`setFriction(friction: number): this\\`\n- \\`setSpringStrength(strength: number): this\\`\n- \\`setSpringTarget(target: number): this\\`\n- \\`setVelocity(velocity: number): this\\`\n- \\`stop(): void\\`\n\n## Example\n\n<CodePen id=\"ooybYP\" />\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"physics\"\n    section=\"api\"\n    category=\"animation\"\n    title=\"Physics\"\n    description=\"Integrated simulation of velocity, acceleration, friction and springs.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/pointer.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Pointer\n\nOutputs the screen position of a single mouse or touch point.\n\n## Import\n\n\\`\\`\\`javascript\nimport { pointer } from 'popmotion';\n\\`\\`\\`\n\n## Usage\n\n### Absolute position\n\n\\`\\`\\`javascript\npointer()\n  .start(({ x, y }) => console.log(x, y));\n\\`\\`\\`\n\n### Relative position\n\nProvide initial \\`x\\` and \\`y\\` properties to output pointer movement **applied to this initial point**.\n\n\\`\\`\\`javascript\npointer({ x: 200, y: 175 })\n  .start(({ x, y }) => console.log(x, y));\n\\`\\`\\`\n\n\nReactions are provided the following pointer data:\n\n- \\`x\\`, \\`y\\`: Alias of \\`clientX\\` / \\`clientY\\`, or \n- \\`clientX\\`, \\`clientY\\`: Position relative to the viewport.\n- \\`pageX\\`, \\`pageY\\`: Position relative to the document.\n\nTo apply the change in pointer movement to, for instance, a slider, you can use the [\\`deltaOffset\\`](/api/delta-pointer) action.\n\n## Props\n\n- \\`preventDefault: boolean = true\\`\n- \\`x?: number\\`: If defined, apply pointer \\`y\\` movement to this number.\n- \\`y?: number\\`: If defined, apply pointer \\`y\\` movement to this number.\n\n## Methods\n\n### Action methods\n\n\\`pointer()\\` returns:\n\n- \\`filter((v: any) => boolean)\\`: Returns a new action that filters out values when the provided function returns \\`false\\`.\n- \\`pipe(...funcs: Array<(v) => v)\\`: Returns a new action that will run \\`update\\` values through this sequence of functions.\n- \\`start(update | { update, complete })\\`: Starts the action and returns a subscription.\n- \\`while((v: any) => boolean)\\`: Returns a new action that will \\`complete\\` when the provided function returns \\`false\\`.\n\n### Subscription methods\n\n\\`pointer().start()\\` returns:\n\n- \\`stop(): void\\`\n\n## Example\n\n<CodePen id=\"RjBZoe\" />\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"pointer\"\n    section=\"api\"\n    category=\"input\"\n    title=\"Pointer\"\n    description=\"Outputs the screen position of a single mouse or touch point.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/schedule.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Schedule\n\n\\`schedule\\` can use one action to control the output of another.\n\nFor instance, by default \\`pointer\\` outputs only when the pointer updates.\n\nWith \\`schedule\\`, you could compose it with \\`everyFrame\\` to output the latest \\`pointer\\` value every frame.\n\n## Import\n\n\\`\\`\\`javascript\nimport { schedule } from 'popmotion';\n\\`\\`\\`\n\n## Usage\n\n\\`\\`\\`typescript\nschedule(scheduler: Action, subject: Action): Action\n\\`\\`\\`\n\n\\`\\`\\`javascript\n// \\`pointer\\` will output at most once every frame\nschedule(\n  everyFrame(),\n  pointer()\n).start(({ x, y }) => {});\n\\`\\`\\`\n\n## Methods\n\n### Action methods\n\n\\`schedule()\\` returns:\n\n- \\`filter((v: any) => boolean)\\`: Returns a new action that filters out values when the provided function returns \\`false\\`.\n- \\`pipe(...funcs: Array<(v) => v)\\`: Returns a new action that will run \\`update\\` values through this sequence of functions.\n- \\`start(update | { update, complete })\\`: Starts the action and returns a subscription.\n- \\`while((v: any) => boolean)\\`: Returns a new action that will \\`complete\\` when the provided function returns \\`false\\`.\n\n### Subscription methods\n\n\\`schedule().start()\\` returns:\n\n- \\`stop(): void\\`\n\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"schedule\"\n    section=\"api\"\n    category=\"compositors\"\n    title=\"Schedule\"\n    description=\"Use an action to control the output of another.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/scroll.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n[Moved to the Stylefire docs](/stylefire/api/viewport).`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"scroll\"\n    section=\"api\"\n    category=\"stylefire\"\n    title=\"DOM Scroll\"\n    description=\"Scroll viewport and DOM elements.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/spring.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Spring\n\nA spring animation based on \\`stiffness\\`, \\`damping\\` and \\`mass\\`.\n\nThis simulation offers smoother motion and a greater variety of spring-feels than the basic spring integration found in [physics](/api/physics).\n\nIt's based on the differential equations governing a [damped harmonic oscillator](https://en.wikipedia.org/wiki/Harmonic_oscillator#Damped_harmonic_oscillator), the same as those underlying Apple's \\`CASpringAnimation\\`.\n\n## Import\n\n\\`\\`\\`javascript\nimport { spring } from 'popmotion';\n\\`\\`\\`\n\n## Usage\n\nAnimate numbers:\n\n\\`\\`\\`javascript\nspring({ to: 500, stiffness: 200, damping: 20 })\n  .start((v) => console.log(v))\n\\`\\`\\`\n\nOr optionally provide vectors:\n\n\\`\\`\\`javascript\nspring({\n  to: [500, 100],\n  stiffness: 300,\n  damping: [20, 10]\n})\n\\`\\`\\`\n\n\\`\\`\\`javascript\nspring({\n  to: { x: 200, y: 300, z: 25 }\n})\n\\`\\`\\`\n\n## Props\n\n- \\`from: number | Vector = 0.0\\`: Value to start from.\n- \\`to: number | Vector = 0.0\\`: Value to spring to.\n- \\`stiffness: number | Vector = 100\\`: Spring stiffness.\n- \\`damping: number | Vector = 10\\`: Strength of opposing force.\n- \\`mass: number | Vector = 1.0\\`: Mass of the moving object.\n- \\`velocity: number | Vector = 0.0\\`: Initial velocity of spring.\n- \\`restDelta: number = 0.01\\`: End animation if distance to \\`to\\` is below this value **and** \\`restSpeed\\` is \\`true\\`.\n- \\`restSpeed: number = 0.01\\`: End animation if speed drops below this value **and** \\`restDelta\\` is \\`true\\`.\n\n## Methods\n\n### Action methods\n\n\\`spring()\\` returns:\n\n- \\`filter((v: any) => boolean)\\`: Returns a new action that filters out values when the provided function returns \\`false\\`.\n- \\`pipe(...funcs: Array<(v) => v)\\`: Returns a new action that will run \\`update\\` values through this sequence of functions.\n- \\`start(update | { update, complete })\\`: Starts the action and returns a subscription.\n- \\`while((v: any) => boolean)\\`: Returns a new action that will \\`complete\\` when the provided function returns \\`false\\`.\n\n### Subscription methods\n\n\\`spring().start()\\` returns:\n\n- \\`stop(): void\\`\n\n## Example\n\n<CodePen id=\"mqKyjd\" />\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"spring\"\n    section=\"api\"\n    category=\"animation\"\n    title=\"Spring\"\n    description=\"Accurate, versatile spring animation.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/stagger.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Stagger\n\nStagger the execution of a series of actions.\n\n## Import \n\n\\`\\`\\`javascript\nimport { stagger } from 'popmotion';\n\\`\\`\\`\n\n## Usage\n\n\\`\\`\\`typescript\nstagger(actions: Action[], interval: number | (i: number) => number): Action\n\\`\\`\\`\n\n\\`stagger\\` accepts two arguments, an array of actions and an \\`interval\\`:\n\n\\`\\`\\`javascript\nstagger([\n  tween(),\n  spring()\n], 100)\n\\`\\`\\`\n\nWhen started, it outputs the values as an array. Actions that haven't yet started will output \\`undefined\\`, and you can define a default.\n\n\\`\\`\\`javascript\nstagger([\n  tween(),\n  spring()\n], 100).start((values) => values.forEach((v = 0, i) => {\n  console.log(v);\n}))\n\\`\\`\\`\n\n## Methods\n\n### Action methods\n\n\\`stagger()\\` returns:\n\n- \\`filter((v: any) => boolean)\\`: Returns a new action that filters out values when the provided function returns \\`false\\`.\n- \\`pipe(...funcs: Array<(v) => v)\\`: Returns a new action that will run \\`update\\` values through this sequence of functions.\n- \\`start(update | { update, complete })\\`: Starts the tween and returns a subscription.\n- \\`while((v: any) => boolean)\\`: Returns a new action that will \\`complete\\` when the provided function returns \\`false\\`.\n\n### Subscription methods\n\n\\`stagger().start()\\` returns:\n\n- \\`stop(): void\\`\n\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"stagger\"\n    section=\"api\"\n    category=\"compositors\"\n    title=\"Stagger\"\n    description=\"Stagger the execution of a series of actions.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/stylefire.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n[Moved to the Stylefire docs](/stylefire/api/styler).`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"stylefire\"\n    section=\"api\"\n    category=\"stylefire\"\n    title=\"Stylers\"\n    description=\"Style setters for CSS, SVG and scroll, optimized for animation.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/svg.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n[Moved to the Stylefire docs](/stylefire/api/svg).`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"svg\"\n    section=\"api\"\n    category=\"stylefire\"\n    title=\"SVG\"\n    description=\"SVG styler with simplified transformation model and line drawing support.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/timeline.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Timeline\n\nTimeline is used to quickly script complex sequences of animation, split across independent tracks.\n\nIt returns a [\\`tween\\`](/api/tween), which allows the use of \\`loop\\`, \\`flip\\` and \\`yoyo\\` props, as well as tween methods like \\`pause\\` and \\`resume\\`.\n\n## Import\n\n\\`\\`\\`javascript\nimport { timeline } from 'popmotion';\n\\`\\`\\`\n\n## Usage\n\n### Create a sequence of animations\n\n\\`timeline\\` accepts an array of playhead instructions.\n\nA playhead instruction can either be an:\n- Animation\n- Absolute or relative timestamp\n- Array of animations\n\n#### Animation\n\nEach animation is defined as an object. This looks a lot like a simplified \\`tween\\`, with \\`from\\`, \\`to\\`, \\`duration\\` and \\`ease\\` properties:\n\n\\`\\`\\`javascript\ntimeline([\n  { track: 'ballX', from: 0, to: 300, duration: 1000 }\n])\n\\`\\`\\`\n\nThere's an extra, non-optional property called \\`track\\`. No two animations should overlap on the same \\`track\\`, and \\`timeline\\` will output every track to the reaction given to \\`start\\`:\n\n\\`\\`\\`javascript\ntimeline([\n  { track: 'ballX', from: 0, to: 300, duration: 1000 }\n]).start((v) => console.log(v.ballX))\n\\`\\`\\`\n\nIf we provide a second animation, it will (by default) play **after** the first:\n\n\\`\\`\\`javascript\ntimeline([\n  { track: 'ballX', from: 0, to: 300, duration: 1000 },\n  { track: 'ballY', from: 0, to: 300 }\n])\n\\`\\`\\`\n\nIn this example animation, the second animation will start after \\`1000\\` milliseconds, as that's when the first ends (as defined by \\`duration\\`).\n\n#### Timestamps\n\nWe can, however, move the playhead from that default position. If we provide a number as the next instruction, the playhead will move to that position.\n\nIn this example, the second animation will start after \\`500\\` milliseconds:\n\n\\`\\`\\`javascript\ntimeline([\n  { track: 'ballX', from: 0, to: 300, duration: 1000 },\n  500,\n  { track: 'ballY', from: 0, to: 300 }\n])\n\\`\\`\\`\n\nIf we instead provide a string, we can move the playhead **relative** to the current timestamp with either \\`'-'\\` or \\`'+'\\` instructions. For instance, this time the second animation will start after \\`800\\` milliseconds:\n\n\\`\\`\\`javascript\ntimeline([\n  { track: 'ballX', from: 0, to: 300, duration: 1000 },\n  '-200',\n  { track: 'ballY', from: 0, to: 300 }\n])\n\\`\\`\\`\n\n#### Parallel and stagger\n\nAnimations can be played in parallel, from the same point in time, by providing them in an array.\n\nIn this example, both animations provided after the first animation will play after \\`1000\\`ms:\n\n\\`\\`\\`javascript\ntimeline([\n  { track: 'ballX', from: 0, to: 300, duration: 1000 },\n  [\n    { track: 'ballX', to: 0 },\n    { track: 'ballY', from: 0, to: 300 }\n  ]\n])\n\\`\\`\\`\n\nIf we provide a number as the last item in the array, \\`timeline\\` will stagger over all the other items in the array with this delay:\n\n\\`\\`\\`javascript\ntimeline([\n  { track: 'ballX', from: 0, to: 300, duration: 1000 },\n  [\n    { track: 'ballX', to: 0 },\n    { track: 'ballY', from: 0, to: 300 },\n    50\n  ]\n])\n\\`\\`\\`\n\n#### Colors and multiprops\n\n\\`timeline\\` can animate colors:\n\n\\`\\`\\`javascript\n{ track: 'ballBackgroundColor', from: '#f00', to: '#fff' }\n\\`\\`\\`\n\nObjects:\n\n\\`\\`\\`javascript\n{ track: 'ball', from: 0, to: { x: 300, y: 300 } }\n\\`\\`\\`\n\nAnd n-dimensional arrays:\n\n\\`\\`\\`javascript\n{ track: 'foo', from: [300, 500], to: [0, 0] }\n\\`\\`\\`\n\n### Types\n\n\\`\\`\\`typescript\ntype Value = number | string | (number | string)[] | { [key: string]: number | string };\n\ntype AnimationDefinition = {\n  track?: string,\n  from?: Value = 0,\n  to?: Value = 1,\n  ease?: EasingFunction = easeOut,\n  duration?: number = 300\n};\n\ntype Instruction = string | number | AnimationDefinition | AnimationDefinition[];\n\ntimeline(instructions: Instruction, props: Props): Action\n\\`\\`\\`\n\n## Props\n\nThese can be passed as the second argument to \\`timeline\\` and are used to define the behaviour of the master playhead.\n\n- \\`duration?: number\\`: Total duration of animation, in milliseconds. By default, this is calculated by the instructions provided to \\`timeline\\`, but if manually overridden will rescale the whole animation.\n- \\`elapsed?: number = 0\\`: Duration of animation already elapsed, in milliseconds.\n- \\`ease?: Easing | Vector[Easing] = linear\\`: A function, given a progress between \\`0\\` and \\`1\\`, that returns a new progress value. Used to affect the rate of playback across the duration of the animation.\n- \\`loop?: number = 0\\`: Number of times to loop animation on \\`complete\\`.\n- \\`flip?: number = 0\\`: Number of times to flip animation on \\`complete\\`.\n- \\`yoyo?: number = 0\\`: Number of times to reverse tween on \\`complete\\`.\n\n## Methods\n\n### Action methods\n\n\\`timeline()\\` returns:\n\n- \\`filter((v: any) => boolean)\\`: Returns a new action that filters out values when the provided function returns \\`false\\`.\n- \\`pipe(...funcs: Array<(v) => v)\\`: Returns a new action that will run \\`update\\` values through this sequence of functions.\n- \\`start(update | { update, complete })\\`: Starts the tween and returns a subscription.\n- \\`while((v: any) => boolean)\\`: Returns a new action that will \\`complete\\` when the provided function returns \\`false\\`.\n\n\n### Subscription methods\n\n\\`timeline().start()\\` returns:\n\n- \\`getElapsed(): number\\`: Returns time elapsed in milliseconds.\n- \\`getProgress(): number\\`: Returns animation progress as a value of \\`0\\`-\\`1\\`.\n- \\`seek(progress: number): this\\`: Seeks animation to this position as a value of \\`0\\`-\\`1\\`.\n- \\`pause(): this\\`\n- \\`resume(): this\\`\n- \\`reverse(): this\\`: Reverses the direction of playback. \n- \\`stop(): void\\`\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"timeline\"\n    section=\"api\"\n    category=\"animation\"\n    title=\"Timeline\"\n    description=\"Sequence a multitrack animation with full playback controls.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/transformers.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Transformers\n\nTransformers are used to take a value, transform it in some way, and then return it. Because all transformers have the same signature, they can be easily composed.\n\n## Import\n\n\\`\\`\\`javascript\nimport { transform } from \"popmotion\";\n\\`\\`\\`\n\n## Usage\n\nAs pure functions, transformers can be used in any situation where you want to change one value into another.\n\nHowever, they're particularly useful with the [action](/api/action) \\`pipe\\` method. For instance, here we can easily compose some functions that will ensure that the \\`tween\\`'s output will always be a valid RGB value:\n\n\\`\\`\\`javascript\nimport { tween, transform } from \"popmotion\";\nconst { pipe, clamp } = transform;\n\ntween({ to: 255 })\n  .pipe(clamp(0, 255), Math.round)\n  .start(v => console.log(v));\n\\`\\`\\`\n\n## Preset transformers\n\n### \\`appendUnit\\`\n\nReturns a function that, when given a value, returns that value appended with the provided \\`unit\\`.\n\n\\`appendUnit(unit: string[])\\`\n\n\\`\\`\\`javascript\nconst convertToPx = appendUnit(\"px\");\nconvertToPx(5); // '5px'\n\\`\\`\\`\n\n### \\`applyOffset\\`\n\nTakes the offset of the provided value from \\`from\\`, and applies it to \\`to\\`.\n\n\\`applyOffset(from: number, to: number)\\`\n\\`applyOffset(to: number)\\`\n\n\\`\\`\\`javascript\n// With two arguments\napplyOffset(0, 10)(20); // 30\n\n// With one argument\nconst offsetFromFirst = applyOffset(10);\noffsetFromFirst(20); // 10\noffsetFromFirst(21); // 11\n\\`\\`\\`\n\n### \\`bezier\\`\n\nReturns a function that, provided a progress value from \\`0\\` to \\`1\\`, will return a resolved number from the provided bezier array.\n\nCan resolve either 3 or 4 bezier points. For more points, the [original implementation](https://github.com/hughsk/bezier) can be used.\n\n\\`bezier(...points: number[])\\`\n\n\\`\\`\\`javascript\nconst resolveBezier = bezier(0, 1, 2, 3);\n\nresolveBezier(0); // 0\nresolveBezier(0.5); // 1.5\nresolveBezier(1); // 3\n\\`\\`\\`\n\n### \\`blendColor\\`\n\nGiven two colors, returns a function that takes a progress value (0 - 1) and returns a correctly blended color.\n\nWatch [Computer Color is Broken](https://www.youtube.com/watch?v=LKnqECcg6Gw) for more information.\n\n\\`blendColor(colorA <String | Object>, colorB <String | Object>)\\`\n\n\\`\\`\\`javascript\nconst blendRedToBlue = blendColor(\"#f00\", \"#00f\");\nblendRedToBlue(0.5); // Returns blended object with rgba properties\n\\`\\`\\`\n\n### \\`clamp\\`\n\nReturns a function that restricts given values to within the provided range.\n\n\\`clamp(min: number, max: number)\\`\n\n\\`\\`\\`javascript\nconst rgbRange = clamp(0, 255);\nrgbRange(256); // 255\n\\`\\`\\`\n\n### \\`conditional\\`\n\nConditionally applies a transformer if \\`check\\` returns \\`true\\`.\n\n\\`\\`\\`javascript\nconst constrainWithSpring = conditional(v => v < 0, nonlinearSpring(50, 0));\n\\`\\`\\`\n\n### \\`interpolate\\`\n\nReturns a function that, when passed a value, interpolates from the \\`inputRange\\` to the \\`outputRange\\`.\n\nAn optional array of easing functions can be passed as the third argument, otherwise linear interpolation will be used by default.\n\nProvided values outside the given ranges will be clamped to the output range limits.\n\n**Note:** The \\`inputRange\\` must be in linear order. ie \\`[100, 200, 300]\\` and \\`[100, 0]\\` are valid, whereas \\`[100, 50, 200]\\` is not.\n\n\\`interpolate(inputRange: number[], outputRange: number[], ease: Easing[])\\`\n\n\\`\\`\\`javascript\nconst invert = interpolate([0, 100], [100, 0]);\ninvert(75); // 25\n\nconst foo = interpolate([0, 50, 100], [0, 0.5, 0]);\nfoo(75); // 0.25\n\\`\\`\\`\n\n### \\`pipe\\`\n\nUsed to compose other transformers, from left to right. The first argument passed to the returned function will be the value and any subsequent arguments will be passed to all functions unaltered.\n\n\\`pipe(...funcs:(v: any) => any[])\\`\n\n\\`\\`\\`javascript\nconst rgbType = pipe(clamp(0, 255), Math.round);\n\nrgbType(12.25); // 12\n\\`\\`\\`\n\n### \\`smooth\\`\n\nWill smooth a value over time.\n\n\\`smooth(strength: number)\\`\n\n**Note:** As \\`smooth\\` maintains an internal state, it must be initialised individually for every numerical value you wish to smooth.\n\n### \\`snap\\`\n\nGiven a number or an array of two or more numbers, returns a function that will snap a given value to the nearest multiple or to the nearest number in the array.\n\n\\`snap(positions: number[])\\`\n\n\\`\\`\\`javascript\nconst snapToIntervals = snap(45);\nsnapToIntervals(89); // 90\n\nconst snapToArbitraryDegrees = snap([0, 90, 270, 360]);\nsnapToArbitraryDegrees(75); // 90\n\\`\\`\\`\n\n### \\`steps\\`\n\nGiven a number of steps and a range, returns a function that will fix a given value to the specific number of discrete steps within that range.\n\n\\`steps(steps: number, min: number, max: number)\\`\n\n\\`\\`\\`javascript\nconst threeStep = steps(3, 0.4);\nthreeStep(0.1); // 0\nthreeStep(0.4); // 0.5\nthreeStep(0.9); // 1\n\\`\\`\\`\n\n### \\`linearSpring\\`\n\nCreates a spring that, given an elasticity (a value less than \\`1\\`) and an origin, will treat the provided value as a displacement.\n\n\\`linearSpring(elasticity: number, origin: number)\\`\n\n### \\`nonlinearSpring\\`\n\nCreates a spring that has a non-linear effect on the displacement - the greater the displacement, the greater effect on the provided value.\n\n\\`nonlinearSpring(elasticity: number, origin: number)\\`\n\n### \\`generateStaticSpring\\`\n\nA function that can generate new static springs like \\`linearSpring\\` and \\`nonlinearSpring\\`.\n\nThis function is actually used to create those functions:\n\n\\`\\`\\`javascript\nconst linearSpring = generateStaticSpring();\nconst nonlinearSpring = generateStaticSpring(Math.sqrt);\n\\`\\`\\`\n\n\\`\\`\\`\ngenerateStaticSpring(alterDisplacement: (displacement: number) => number)\n  => (elasticity: number, origin: number)\n\\`\\`\\`\n\n### \\`transformMap\\`\n\nAccepts an object of named transformers that expects \\`v\\` of the same structure. Applies those transformers to the corresponding property in \\`v\\` and outputs.\n\n\\`transformMap(map: { [key: string]: (v: any) => any })\\`\n\n\\`\\`\\`javascript\nconst foo = transformMap({\n  x: v => v + \"px\",\n  y: v => v + \"%\"\n});\n\nfoo({ x: 5, y: 10 }); // { x: '5px', y: '10%' }\n\\`\\`\\`\n\n### \\`wrap\\`\n\nWraps a number around.\n\n\\`wrap(min: number, max: number)\\`\n\n\\`\\`\\`javascript\nphysics({ velocity: 1000 })\n  .pipe(wrap(100, 400))\n  .start(v => console.log(v));\n\\`\\`\\`\n\n### Value type transformers\n\nTransformers that can convert from numbers and objects into value types like px or hsla can be found in the [\\`style-value-types\\` package](/api/value-types).\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"transformers\"\n    section=\"api\"\n    undefined\n    title=\"Transformers\"\n    description=\"Simple composable functions that take a value and return a new one.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/tween.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Tween\n\nAnimate between two values over a set duration of time.\n\nThe behaviour and feel of the animation can be affected by providing a different [easing](/api/easing) function.\n\n## Import\n\n\\`\\`\\`javascript\nimport { tween } from 'popmotion';\n\\`\\`\\`\n\n## Usage\n\nBy default, \\`tween\\` will tween from \\`0\\` to \\`1\\` over \\`300\\` milliseconds, with \\`easeOut\\` easing.\n\n\\`\\`\\`javascript\ntween()\n  .start((v) => console.log(v));\n\\`\\`\\`\n\nPass props to adjust the character of the tween:\n\n\\`\\`\\`javascript\ntween({ to: 200, duration: 500 })\n  .start((v) => console.log(v));\n\\`\\`\\`\n\n\\`from\\`, \\`to\\` and \\`ease\\` can also be defined as \\`Vectors\\`, which are either a map or array of numbers:\n\n\\`\\`\\`javascript\ntween({\n  from: { x: 124, y: 200 },\n  to: 0, // Both x and y will tween to 0\n  ease: { x: easing.easeOut, y: easing.easeIn }\n})\n\\`\\`\\`\n\n\\`\\`\\`javascript\ntween({\n  from: [0, 5, 20],\n  to: [100, 200, 300],\n  ease: easing.linear\n})\n\\`\\`\\`\n\n\\`tween\\` also supports colors:\n\n\\`\\`\\`javascript\ntween({ from: '#000', to: 'rgba(255, 0, 0, 0.5)' })\n\\`\\`\\`\n\nColors can also be provided to arrays or objects:\n\n\\`\\`\\`javascript\ntween({\n  from: {\n    x: 0,\n    background: 'hsla(125, 100, 50, 1)'\n  },\n  to: {\n    x: 100,\n    background: 'hsla(20, 100, 60, 1)'\n  }\n})\n\\`\\`\\`\n\n## Props\n\n- \\`from?: number | Vector[number] = 0\\`: Start value of animation.\n- \\`to?: number | Vector[number] = 1\\`: End value of animation.\n- \\`duration?: number = 300\\`: Total duration of animation, in milliseconds.\n- \\`elapsed?: number = 0\\`: Duration of animation already elapsed, in milliseconds.\n- \\`ease?: Easing | Vector[Easing] = easeOut\\`: A function, given a progress between \\`0\\` and \\`1\\`, that returns a new progress value. Used to affect the rate of playback across the duration of the animation.\n- \\`loop?: number = 0\\`: Number of times to loop animation on \\`complete\\`.\n- \\`flip?: number = 0\\`: Number of times to flip animation on \\`complete\\`.\n- \\`yoyo?: number = 0\\`: Number of times to reverse tween on \\`complete\\`.\n\n## Methods\n\n### Action methods\n\n\\`tween()\\` returns:\n\n- \\`filter((v: any) => boolean)\\`: Returns a new action that filters out values when the provided function returns \\`false\\`.\n- \\`pipe(...funcs: Array<(v) => v)\\`: Returns a new action that will run \\`update\\` values through this sequence of functions.\n- \\`start(update | { update, complete })\\`: Starts the tween and returns a subscription.\n- \\`while((v: any) => boolean)\\`: Returns a new action that will \\`complete\\` when the provided function returns \\`false\\`.\n\n\n### Subscription methods\n\n\\`tween().start()\\` returns:\n\n- \\`getElapsed(): number\\`: Returns time elapsed in milliseconds.\n- \\`getProgress(): number\\`: Returns animation progress as a value of \\`0\\`-\\`1\\`.\n- \\`seek(progress: number): this\\`: Seeks animation to this position as a value of \\`0\\`-\\`1\\`.\n- \\`pause(): this\\`\n- \\`resume(): this\\`\n- \\`reverse(): this\\`: Reverses the direction of playback. \n- \\`stop(): void\\`\n\n## Example\n\n<CodePen id=\"WXOPWX\" />\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"tween\"\n    section=\"api\"\n    category=\"animation\"\n    title=\"Tween\"\n    description=\"Animate between two values over a set duration of time.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/value-types.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Value Types\n\nTo help convert numerical values into commonly-used special value types, like \\`px\\` or \\`hex\\`, we provide an optional module called \\`style-value-types\\`:\n\n\\`\\`\\`bash\nnpm install style-value-types --save \n\\`\\`\\`\n\nEach value type has three functions:\n\n- \\`test\\`: Returns \\`true\\` if the provided value is of that type.\n- \\`parse\\`: Returns the value in a format suitable for animation. Either a \\`number\\` or \\`{ [key: string]: number }\\`.\n- \\`transform\\`: The reverse of \\`parse\\`. Accepts a \\`number\\` or map of named numbers and converts that into the value type.\n\n## Import\n\nFrom Popmotion:\n\n\\`\\`\\`javascript\nimport { valueTypes } from 'popmotion';\nconst { color } = valueTypes;\n\\`\\`\\`\n\nOr, either to save bytes and import \\`valueTypes\\` separately, or to use as a stand-alone library:\n\n\\`\\`\\`javascript\nimport { color } from 'style-value-types';\n\\`\\`\\`\n\n## Example\n\n\\`\\`\\`javascript\n// Test\ncolor.test('#fff'); // true\ncolor.test(0); // false\n\n// Parse\ncolor.parse('rgba(255, 255, 255, 0)');\n// { red: 255, green: 255, blue: 255, alpha: 0 }\n\n// Transform\ncolor.transform({ hue: 200, saturation: 100, lightness: 50, alpha: 0.5 });\n// 'hsla(200, 100%, 50%, 0.5)'\n\\`\\`\\`\n\n## Included value types\n\n- \\`alpha\\`: \\`Number\\` between \\`0\\` and \\`1\\`\n- \\`complex\\`: \\`String\\` containing arbitrary sequence of numbers mixed with other characters. See below.\n- \\`color\\`: \\`String\\` of either \\`hex\\`, \\`hsla\\` or \\`rgba\\` type\n- \\`degrees\\`: \\`String\\` ending in \\`deg\\`\n- \\`hex\\`: \\`String\\` beginning with \\`#\\` and followed by 3 or 6-digit hex code\n- \\`hsla\\`: \\`String\\` with valid \\`hsla\\` property\n- \\`percent\\`: \\`String\\` ending in \\`%\\`\n- \\`px\\`: \\`String\\` ending in \\`px\\`\n- \\`scale\\`: \\`Number\\` with a \\`default\\` of \\`1\\` instead of \\`0\\`\n- \\`rgbUnit\\`: Integer between \\`1\\` and \\`255\\`\n- \\`rgba\\`: String in \\`rgba(rgbUnit, rgbUnit, rgbUnit, alpha)\\` format\n\n## Complex type\n\nThe \\`complex\\` value type is slightly different to the others. Instead of a \\`transform\\` method, it has a \\`createTransformer\\` method which returns the \\`transform\\` method:\n\n\\`\\`\\`javascript\nconst svgPath = 'M150 0 L75 200';\nconst transform = complex.createTransformer(svgPath);\n\\`\\`\\`\n\nThe returned \\`transform\\` function is unique to the string given to it. When this function is provided an object of the same format as returned by \\`complex.parse()\\` (in this example \\`complex.parse(svgPath)\\`), it will use the original string as a template.\n\nExample: \n\n\\`\\`\\`javascript\ntransform({\n  '0': 300,\n  '1': 0,\n  '2': 100,\n  '3': 200\n}); // Returns 'M300 0 L100 200'\n\\`\\`\\`\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"value-types\"\n    section=\"api\"\n    undefined\n    title=\"Value Types\"\n    description=\"Parsers, transformers and tests for common style value types, eg: %, hex codes etc.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/api/value.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Value\n\nA [multicast reaction](/api/multicast) that tracks the state of a number and allows velocity queries.\n\n## Import\n\n\\`\\`\\`javascript\nimport { value } from 'popmotion';\n\\`\\`\\`\n\n## Usage\n\n\\`\\`\\`typescript\nvalue(initialValue, onUpdate);\n\\`\\`\\`\n\n\\`\\`\\`javascript\nimport { tween, value } from 'popmotion';\nimport styler from 'stylefire';\n\nconst div = styler(document.querySelector('div'));\nconst divX = value(0, div.set('x'));\n\ntween({ to: 500 }).start(divX);\n\nsetTimeout(() => console.log(() => {\n  physics({\n    velocity: divX.getVelocity()\n  }).start(divX); // This will automatically \\`stop\\` the tween\n}), 150);\n\\`\\`\\`\n\n\\`value\\` can also handle objects and arrays:\n\n\\`\\`\\`javascript\nconst foo = value({ x: 0, y: 0 });\nconst bar = value([0, 0]);\n\nfoo.getVelocity(); // { x: 0, y: 0 }\nbar.getVelocity(); // [0, 0]\n\\`\\`\\`\n\nAs a multicast reaction, you can optionally \\`subscribe\\` with multiple other reactions rather than providing an initial subscription:\n\n\\`\\`\\`javascript\nconst foo = value(0);\nfoo.subscribe(() => console.log('first reaction'));\nfoo.subscribe(() => console.log('second reaction'));\n\\`\\`\\`\n\n## Methods\n\n### Reaction methods\n\n\\`value()\\` returns:\n\n- \\`get(): number\\`: Returns the current value state.\n- \\`getVelocity: number\\`: Returns the current value velocity.\n- \\`filter((v: any) => boolean)\\`: Returns a new action that filters out values when the provided function returns \\`false\\`.\n- \\`pipe(...funcs: Array<(v) => v)\\`: Returns a new reaction that will run \\`update\\` values through this sequence of functions.\n- \\`stop()\\`: Stops parent action.\n- \\`subscribe(update | { update, complete })\\`: Returns a subscription.\n- \\`while((v: any) => boolean)\\`: Returns a new reaction that will \\`complete\\` when the provided function returns \\`false\\`.\n\n### Subscription methods\n\n\\`value().subscribe()\\` returns:\n\n- \\`unsubscribe(): void\\`\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"value\"\n    section=\"api\"\n    category=\"reactions\"\n    title=\"Value\"\n    description=\"Track value state and query velocity\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/blog/20170703-choosing-a-default-easing-for-popmotion.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Choosing the correct default easing for Popmotion\n\nChoosing default values for a library is difficult. Should you be the benefactor/victim of a wider audience:\n\n- These defaults will be used, often unwittingly, by your consumers.\n- You can change them only at the risk of breaking other people's stuff.\n\nIn a motion engine, these choices manifest themselves in a visual and visceral way. A duration here, a spring tightness there.\n\nThis means there's responsibility to choose values intelligently, so that the little patches of the web that use your library benefit from more responsive motion.\n\nAs the userbase of Popmotion is relatively small, I've always felt comfortable shirking the shackles of API stability until I finally felt like it had arrived at a the Good Place. Apologies to anyone who's lived that.\n\nLuckily, over the years of wildly oscillating GitHub activity graphs,\nthere has been one (one) decision that I felt like I got right at the start: Making the \\`tween\\` default easing property \\`easeOut\\`.\n\n![An example of a sweet easeOut, generated with Ceaser @ matthewlein.com/ceaser](/guides/ease-out-example.png)\n\n## A brief history of timing\n\nLike many greying front end devs, my first exposure to UI animation was [Greensock's](https://greensock.com) then-ActionScript library, TweenMax. For a platform so disposed to garish show-off loading screen animations, Flash animations were disgusting to hand code unless you were using TweenMax.\n\nAnd that's largely what we used it for: showy animations. The Flash days were as over-the-top and as divorced from the user's interests as the Amiga demoscene. All you wanted to do was play your cracked version of Worms but first you had to sit through the seizure-inducing cock-prancing of some git in Norwich. At least Flash intros occasionally had a skip button.\n\n![This, but flashing, and scrolling, and waving. Forever](/guides/amiga-demoscene.png)\n\nGreensock, in its sunrise years, had the right intentions. It did, and still to this day, has an \\`easeOut\\` as default. That's because the author understands, despite our hedonism and heathenism, that animation in UI design **should** be as a result of a user's action. \\`easeOut\\` is snappy, and as we'll see later, \"snappy\" is how we should respond to user actions.\n\nFlash died, and the community collectively denied any involvement.\n\n![\"Honestly never heard of it. Like Gordon?\"](/guides/flash-gordon.jpg)\n\nThen it was all about jQuery. jQuery was incredible for literally **everything**, which in the new world of composable asynchronous micropackages is probably why we again collectively deny any involvement, and why I'm talking about it in the past tense even while it's standing **right there**, watching us.\n\nFor me, and maybe for you, the coolest thing about jQuery was \\`animate\\`. It was amazing to easily get something resembling movement in humble HTML. Even if it defaulted to \\`swing\\` easing, a tepid, muddy \\`easeInOut\\` of homeopathic strength.\n\nThat easing was coupled with a default duration of \\`400\\`ms. Then that was folded into our neanderthal, performance-ignorant tweening of the CPU-choking, layout-breaking \\`width\\` and \\`height\\` properties. Lethargic animation ruled the internet.\n\n![Feels like a good idea at the time](/guides/ease-in-out-example.png)\n\n## The problem with \\`easeInOut\\`\n\nTo arrive at an actual point, the problem with \\`easeInOut\\` is that it **feels** incredibly slow. When we [watch videos about the principles of animation](https://vimeo.com/93206523), one of the things we're taught is that objects in motion don't start in motion and they don't stop dead.\n\nThey start slow, and end slow.\n\nSo that sounds about right, we think, and then we stop thinking, and use \\`easeInOut\\` by choice, or a framework like jQuery makes it default, and then everyone uses it, by default, and everything feels sluggish, by default. Why?\n\n## Why\n\nOur eyes and brain are hardwired to detect motion. We've evolved to find that motion distracting. Motion indicates that the present situation has changed, and we need to react if we'd prefer to survive. We **need** motion to be distracting.\n\nWhen you're scrolling through a website, and a space opens for an advert in the middle of your article, and everything jumps around, and then after a couple of seconds your crap, overpriced \"4G\" connection finally loads the banner ad, which animates on loop, until you scroll past it, when it then needlessly closes, god I hate Motherboard, your text jumps back up, you think of the poor bastard forced to make it, their hopes, their dreams, their broken dreams - all of those things are distracting.\n\nThat motion, the things causing it: They're not imparting useful information, they're not even trying to kill you. So it's annoying.\n\nIt's all shit, the user isn't involved in any of this, he's happy about the broken dreams. And yet, \\`easeInOut\\` is entirely appropriate, it is the least damaging easing to use for uninstigated animation, it is the right choice.\n\nWhat does it say about an easing that **this** is a good use case for it?\n\n## It's sometimes okay, I guess\n\nA **very** tiny amount of uninstigated motion is fine in a UI, as long as it correctly indicates that **the situation has changed, and the user needs to react**. A small \"new message\" dot, probably. Or a notification panel, possibly.\n\nFor this kind of animation, an \\`easeInOut\\` or \\`anticipate\\` is very appropriate because it gives the user a little bit of time to acclimatise to the movement, and it stops quite gently, naturally. It adheres to the principles of animation, these dots and panels now feel a little more real, your UI a little more alive.\n\nIt's certainly better than things just flicking around the page without the user understanding what's changed.\n\n## But usually it very much isn't\n\nThe **vast majority** of animation in UI is, or should be, user instigated.\n\nFor these animations, these interactions, the user already knows that an action has taken place. **They** started the motion, and the situation has changed, and the UI needs to react. The \"in\" of an \\`easeIn\\` or \\`easeInOut\\` feels sluggish in this instance because for god's sake hurry up, get on with it.\n\nThe energy and momentum of \\`easeInOut\\` starts in the virtual reality and stays there. The energy and momentum \\`easeOut\\`, conversely, starts in the user's reality and ends in the interface's.\n\nIt takes the user's energy, directly from their finger, through the wire or screen, straight into the button, the tooltip, the whatever, and bursts with the maximum energy at that initial moment of contact.\n\n\\`easeInOut\\` is barely bothered to get out of bed, like a stupid stroppy teenager who probably doesn't even have a finger. Probably.\n\nA user will feel that difference, even if it's subconscious, even if I have to pretend to myself that deep down they **know**, just to justify the hours of my life I've spent writing (and now writing about) animations.\n\nThis is why Greensock comes with \\`easeOut\\` by default. It's why [Anime.js](http://animejs.com/) uses a zinger \\`elasticOut\\`. And it's why Popmotion uses \\`easeOut\\` too.\n\nWhereas, CSS transitions default to the \\`swing\\`-alike \\`ease\\`, which is exactly as bland as it sounds. Worse, the native Web Animations API uses \\`linear\\` easing, which is, frankly, a fucking crime.\n\n![Blood at crime scene. Yawn.](/guides/ease-linear-example.png)\n\n## Feel it for yourself\n\nHere's \\`easeInOut\\`.\n\n\\`\\`\\`marksy\n<Example template=\"Ball\" id=\"a\">{\\`\nconst ball = document.querySelector('#a .ball');\nconst ballRenderer = styler(ball);\n\ntween({\n  to: 300,\n  duration: 500,\n  ease: easing.easeInOut\n}).start((x) => ballRenderer.set('x', x));\n\\`}</Example>\n\\`\\`\\`\n\nBuuuuuuurrrrr. END ME.\n\nConversely, here's an \\`easeOut\\` with the Popmotion default of \\`300\\`ms.\n\n\\`\\`\\`marksy\n<Example template=\"Ball\" id=\"b\">{\\`\nconst ball = document.querySelector('#b .ball');\nconst ballRenderer = styler(ball);\n\ntween({\n  to: 300,\n  ease: easing.easeOut\n}).start((x) => ballRenderer.set('x', x));\n\\`}</Example>\n\\`\\`\\`\n\nI. Am. Blushing.\n\nNotice that when you press start on these examples, you're pressing the button yet it's the ball that's moving. Even with this physical disconnect, the first example feels like you're **telling** the ball to move, and then it moves of its own accord. Whereas the second example, you're **making** the ball move, it's using **your** energy.\n\nIt makes a difference! Users can tell.\n\nIt does. It makes a difference.It does.Userscantellitmakesadifferencepleasemakeadifferenceuserscantell\n\n---\n\n[Get started with Popmotion](/learn/get-started)\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"20170703-choosing-a-default-easing-for-popmotion\"\n    section=\"blog\"\n    undefined\n    title=\"Choosing the correct default easing for Popmotion\"\n    description=\"Why I settled on easeOut for Popmotion's default easing, and why easeInOut sucks for interfaces\"\n    published=\"3 Jul 17\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/blog/20170704-manually-set-scroll-while-ios-momentum-scroll-bounces.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# How to manually set scrollTop during an iOS momentum bounce\n\nHere's one to file under [the mobile is web is awful](/blog/20170710-mobile-web-is-awful-and-were-all-to-blame).\n\nI've been writing a Slack-esque chat that lazy-loads new messages as you scroll up. The adventure of reliably anchoring scroll position as these new messages are added to the DOM is probably a blog post in itself, but there's a specific issue on iOS that I'd like to share solution to.\n\n## The problem\n\nHere's the code to restore a previous scroll position, (which has to be recalculated to accommodate the newly-loaded messages):\n\n\\`\\`\\`javascript\nnode.scrollTop = node.scrollHeight - prevScrollTop;\n\\`\\`\\`\n\nWorks great in every browser, except of course the modern-day IE:\n\n![Knew this wouldn't be so simple](/images/chat-without-hack.gif)\n\nAs you can see, the scroll position stays at the top, almost as if we never manually reset the scroll position at all.\n\nThe problem, as I began to understand, was that if you try and manually set a node's (and probably the viewport's) scroll position **while iOS is doing it's out-of-bounds bouncy thing**, that scroll position will be immediately overridden by the rest of the bounce animation.\n\n## The fix\n\nTo fix, we simply disable momentum scrolling on that element, restore scroll position, and then re-enable momentum scrolling:\n\n\\`\\`\\`javascript\nnode.style['-webkit-overflow-scrolling'] = 'auto';\nnode.scrollTop = node.scrollHeight - prevScrollTop;\nnode.style['-webkit-overflow-scrolling'] = 'touch';\n\\`\\`\\`\n\nHere's how that looks:\n\n![Better](/images/chat-with-hack.gif)\n\nNot as graceful as I'd prefer, but looking at the timestamps the user is still left on the correct message. It also avoids funny residual momentum effects, so I presume this technique can also be used to kill scroll momentum when a pointer moves from one overflowing node to another.\n\n---\n\nPopmotion is a 9kb JavaScript motion engine, and it'll give you way less bother than mobile Safari. Create awesome interactions with tweens, physics and input tracking.\n\n[Excite your users with Popmotion](/learn/get-started) and/or [excite us with 140 characters](https://twitter.com/popmotionjs)\n\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"20170704-manually-set-scroll-while-ios-momentum-scroll-bounces\"\n    section=\"blog\"\n    undefined\n    title=\"How to manually set scrollTop during an iOS momentum bounce\"\n    description=\"Why does existence hurt so much\"\n    published=\"4 Aug 17\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/blog/20170710-mobile-web-is-awful-and-were-all-to-blame.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# The mobile web is awful, and everyone's to blame\n\nAt work today, we were discussing the future direction of the website and app. A concern was raised that, without a clear mandate, the website would \"continue to be a great desktop version, and a much poorer version of the app.\"\n\nAs the front end lead, that stung. I felt like the \"much\" was undeserved.\n\nI took the point. It's worth imagining that the use-case of the app and website may well be different.\n\nHowever, the comment came as a response to a mini-moan that it'd taken me a couple hours to get an input field to stick to the bottom of the page and still be tappable in mobile Safari. A simple task made difficult.\n\nIt was an indictment that I haven't yet changed perceptions about the capabilities of the mobile web. Maybe those perceptions don't deserve to be changed.\n\nI've long held that the web experience **can** be just as performant and polished as native. It's only for a lack of time and ambition that it isn't. That belief is the reason I wrote Popmotion in the first place.\n\nSo I began to think, it's usually easy and quite enjoyable to make a great desktop experience. Yet developing for mobile is a constant headache.\n\nWith some mobile Geekbench scores approaching laptops, the technical argument is diminishing. So why?\n\nI realised that everyone is to blame. Browser vendors, Business People, every member of the Google AMP team, you reading this, me writing this: Everyone.\n\n## Browsers Know Best\n\nImplementing simple design features like overlays or bottom navigation on mobile browsers invariably involves trawling through blogs and forums to find that special hack that worked for that one guy that one day in June.\n\nAs every developer knows, no good hack goes unpunished. Testing cross-browser serves a specific cocktail; a nostalgic blend of heart palpitations, dream-like confusion and a palpable sense of impending disappointment. It takes you right back to '99.\n\nIt usually comes down to the same problem. Browsers Know Best. In their infinite wisdom, browser vendors implement novel or specific behaviour, ostensibly to aid performance and accessibility.\n\nIt's a noble aim but developing for browsers is already quite chaotic enough, thankyouverymuch. The absolute last thing the internet needs is more platform-specific behaviour. Let's take a look at some examples.\n\n### Safari\n\nA search for \"Safari is the new IE\" brings up enough results **refuting** that statement that there is, at the very least, a **vibe**.\n\nIt also wouldn't be surprising that a team of self-isolated Apple engineers working out of their space bunker would be susceptible to Browsers Know Best (BKB).\n\nThey've historically dragged their moonboots over implementing new performance-enhancing standards and APIs (like Service Workers), and what progress they do make is diminished by a lethargic release schedule intimately coupled with iOS and macOS.\n\nWhich is fine on desktop because virtually nobody gives a shit about desktop Safari. On mobile, however, the demographics are different, and this holds up progress.\n\n### Bottom navigation\n\nThe behaviour that inspired this 2000-word rant.\n\nNow we live in the future, the outrageous size of phones means they can't be safely touched in their upper halves. Reflecting this shift, design guidelines are increasingly recommending putting app navigation at the bottom of the screen.\n\nExcept, the greedy gits at Apple have colonised the bottom 40-ish pixels and used it as invisible magic space. Touch this, and the app navigation reappears.\n\nIn exchange for this genius piece of UX, you can't put a nav there, or an action button, or a link or or a chat box or whatever.\n\nNo, because we're dirty web peasants, we have to put our nav at the top, where no one can ever reach it. Unless, of course, we resort to the now-canonical hack detailed on [this god-given Eventbrite blog post](https://www.eventbrite.com/engineering/mobile-safari-why/), rightfully titled \"Mobile Safari (Whyyyy?)\". BKB.\n\nOr what do \\`100%\\` and \\`100vh\\` mean in a viewport that constantly changes and never seems to report the right size? BKB.\n\nOr why is it so difficult to lock page scroll when displaying an overlay, or prevent the page from scrolling to the top when you **do** manage to lock it, or or or. BKB.\n\n### Get over here\n\nChrome isn't blameless, either.\n\nIn Chrome 56, the Chrome team set \\`touch\\` events to \\`{ passive: true }\\` by default. They [excuse themselves in this blog post](https://developers.google.com/web/updates/2017/01/scrolling-intervention).\n\n\\`passive: true\\` allows a developer to reassure the browser that the page will not be calling \\`e.preventDefault()\\`, which would block page scroll. This allows the browser to respond immediately to scroll, which at risk of singing its praises, I don't remember ever being an issue in Safari. Is this an Android thing?\n\nEither way, it's broken every instance of a draggable DOM element I've implemented, and every virtual DOM event-handler abstraction like those found in React. Thanks, Chrome team.\n\n### A decade of this\n\nIt's been ten years of this shit.\n\nTake \\`hover\\` events. A hover event **obviously** has no place firing on a touch device. Originally though, large parts of the web weren't written as an input-agnostic place. As a result, key functionality was hidden behind hover events.\n\nTo unbreak the web on mobile, browsers starting emulating \\`hover\\` on the very \\`mousedown\\`-looking \\`touchstart\\`.\n\nSo, we end up with very weird interactions, like having to double-tap to open menus that rely on hover. Or CSS hover styles enabling on taps. Or sticky hover states when you're merely trying to scroll the page. Or or or...\n\nIf Apple had the bravery to break Flash websites, where was this bravery with hover interactions? Just break them, stick to a standard, the web will fix itself. \n\nNow, ten years later, we're still stuck with this. Scoping \\`:hover\\` effects to special capability classes and yet another esoteric behavior that's difficult to grok and embarrassing to explain to newcomers. \"Well you see, in 2007...\"\n\nBKB.\n\n## Business has feelings too\n\nWhether the interests of business and user are polarised or harmonised is a debate much older than software.\n\nAs a wide-eyed, UX-minded front end dev, I'm predisposed to thinking the latter. I think most people **believe** they are.\n\nInterests are hard to quantify. It's easy, then, for a business person to frame a stat in a way that makes interests look aligned.\n\nIn my own experience it's been an obvious, and incidentally statistical truth, that app users are stickier and more engaged with the product than mobile web users.\n\nSomehow it then leads that it's in the user's interests to be sticky and engaged, which then leads into all manner of poor choices for the mobile web user's experience.\n\n### Reddit\n\nFor example. I have installed two Reddit apps - Alien Blue and the official app. I usually use the desktop web version. Periodically, I'll be mid-surf and it'll be easier to hit the address bar, type \"sta\" and spent the next five minutes browsing the preloaded Star Trek subreddit.\n\nMy point is, as a user, **I'm engaged**. So why is it that I'm occasionally given the ol' mobile fuck you:\n\n![What on earth](/images/reddit-popover.png)\n\nThe USPs are mind-bending.\n\n- **50% faster:** By what metric?\n- **Infinite scrolling:** Infinite scrolling isn't difficult to implement, so why isn't it? Either the devs are lazy and/or incompetent, or much more likely the Business People needed another bullet point to whack on the pop-up and bag themselves a cheeky conversion. So there was a specific choice to make the web version worse.\n- **Autoplay gifs:** BKB.\n\n### Facebook\n\nI had the Facebook app, once. Then, because an analyst got a whiff that Messenger had higher engagement on the stand-alone app, the Business People decided to force users to download that. Once that was downloaded, the analyst got a whiff that users were stickier when push notifications were enabled. So the Business People forced users to turn those on. So I deleted it and used the web instead.\n\nThe mobile messages worked perfectly. I was quite happy not to have Facebook on my phone - despite lacking a messenger, it's half a gig. The mobile site loaded near-instantly with just a couple hundred of progressively downloaded kb.\n\nSniff.\n\n**Sniff.**\n\n![What on earth](/images/facebook-messenger.jpg)\n\nNow, when we click the \"new messages\" icon, we're treated to a splash screen telling us to download Messenger (or we were, there's presently a bug so it does literally nothing). This is purposeful degradation of a perfectly capable website and it is totally anti-user.\n\nIt is wild. I am wild.\n\n## AMP\n\nA lot has been made of the ill-comings of AMP (Accelerated Mobile Pages) recently, so I won't go too deep. My favourite is this [mic drop by The Register](https://www.theregister.co.uk/2017/05/19/open_source_insider_google_amp_bad_bad_bad/).\n\nThe complaints are usually the same; it's proprietary, Google is using you for your content, homogeneous, opaque, maintaining two views. Etc.\n\nIMO the biggest problem is the flagrant abuse of power. Google has a special AMP section at the top of their search results, where AMP results get a nice picture. It's labeled \"Top stories\", but realistically it's just a carousel of sell-outs. Not that you can blame them.\n\nMobile browser usage is, on some sites, far higher than desktop. Yet can you imagine if Google created a special standard for desktop sites and showcased those at the top of their results? There'd be outrage. It'd be a clear power play. But this is just the shitty mobile web, so who cares, right?\n\nNow, there's no denying that AMP pages are faster than the majority of the net and this definitely has some value for the user. AMP isn't magic though, and if a normal site is fast enough to be featured, why not include those, too?\n\nWe can't complain, though. AMP is our fault, yours and mine.\n\n## Mostly you\n\nI'll take a bit of this blame. You can take the rest.\n\nUltimately we're in this position because the mobile web is slow. We develop sites on our fancy Macbook Pros and fiber connections and then serve those sites to low-end Android phones on Edge networks.\n\nWhen we're not being mindful of our user, this is our fault.\n\nOr when we include expansive libraries like Lodash or Moment in their entirety, this is our fault.\n\nOr when we serve a site without server-side rendering, this is our fault.\n\nOr when we don't split our bundles, this is our fault.\n\nOr or or.\n\n## Do we even deserve redemption\n\nJohn Gruber of [Daring Fireball](https://daringfireball.net) has been banging on recently about how JavaScript was a mistake, that the web would load in under a second if it didn't exist.\n\nWell, maybe. It's an interesting thought experiment. Practically, JS does make things slower in the majority of cases. A little bit of power.\n\nWith care, and \\`fetch\\`, and code sharding, it can theoretically also make things quicker.\n\nIt can also be the case that a server-side rendered website with a JS payload of 100kb can belt down the network and render **quicker** than a bloated 500mb app can load into memory. There is opportunity here.\n\nThe address bar is an app launcher of power user speeds, and browsers can preload pages while the user is still thinking. No context-switching, or sloshing about with Apple's horrific app search, no need to delete, to arrange.\n\nThere's opportunity here, too.\n\n## Proceed with caution\n\nBrowsers Still Know Best, and keep releasing breaking changes that we have to learn to hack around. Business interests will always inexplicably collide with user interests. Google will always want control.\n\nAnd you'll always be lazy. Me, too, a bit. Mostly you.\n\nLet's be optimistic though. JavaScript, for all Gruber's delicious tears, isn't going anywhere. Nor should it. It's important that there's a democratic and open platform, and in the emerging world of closed devices the **web is it**.\n\nIt's essential this platform remains open, and continues to become more and more capable.\n\nWe're getting WebAssembly, so it'll get faster. WebGL is gaining adoption and we'll see improved AR and VR support, so it'll become more capable.\n\nAlready, we can use tools like Webpack and [bundlesize](https://github.com/siddharthkp/bundlesize) to code split and maintain size budgets.\n\nTools like [Next.js](https://github.com/zeit/next.js/) makes SSR trivial to implement.\n\nHopefully, [Popmotion](/learn/get-started) can help create delightful, high-quality interactions.\n\nWe just need to have the opportunity to create the time and space to dedicate to polish and performance, rather blindly belting along the Business People's feature treadmill. Then next time there won't be a \"much\" in sight.\n\n---\n\nPopmotion is a 9kb JavaScript motion engine. Create awesome interactions with tweens, physics and input tracking.\n\n[Make the mobile web marginally better](/learn/get-started) or [follow us on Twitter](https://twitter.com/popmotionjs)\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"20170710-mobile-web-is-awful-and-were-all-to-blame\"\n    section=\"blog\"\n    undefined\n    title=\"The mobile web is awful, and everyone's to blame\"\n    description=\"From browser vendors to front end developers, everyone is implicated in the state of the mobile web.\"\n    published=\"10 Jul 17\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/blog/20170803-coding-style-dont-be-a-dick.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# When it comes to adhering to a project's coding style, follow the golden rule.\n\nI just finished reading Ben Nadel's blog post, titled [After 3 Months Of JavaScript Linting, It's Pretty Much All Pain And No Gain](https://www.bennadel.com/blog/3312-after-3-months-of-javascript-linting-it-s-pretty-much-all-pain-and-no-gain.htm). It makes the argument that linting for maintaining a consistent style is burdensome.\n\nI couldn't disagree more. In fact, I wouldn't disagree more even if the post was titled \"2 plus 2 actually equals 5\", a 500 word rebuttal of a hard, rudimentary, objective fact.\n\nFor both solo, pet projects, and sprawling codebases with multiple contributors, linting for maintaining style is essential.\n\nPopmotion itself is just under 3,000 lines of code, I'm the primary contributor, and linting is useful even to keep just my messy self in check.\n\nIf anything, I'd argue it doesn't go far enough. The number of times I've argued with myself about whether I should declare as a \\`function\\` or an arrow function \\`const\\`, in different situations, and decided **different things**... I would to deprecate that from my life.\n\nAt work, five of us sit on about 100,000 lines of code. To you, this might be relatively big, or relatively small. It's all relative. Here, linting is one of many tools (types, tests) that have helped keeps us sane, for reasons we'll explore.\n\n> [...] the goal of consistency is a complete charade.\n\nA charade? Well it isn't a charade in the sense that linting does a great job of achieving that goal. To use Ben's own examples, indentation, quotes etc are easily kept consistent. So it's a slightly self-defeating argument.\n\nOne example given is \\`let\\` vs \\`const\\`. I don't understand how this is stealth-bundled in amongst actual stylistic choices. There is a right way and a wrong way to use these, they have semantic and practical meaning and a linter helps here, too.\n\nBut I suppose his question is, why would you want to? The following quotes are, with varying quantities of melodrama, essentially saying **because I don't want to**.\n\n> [...] my approach to code formatting is the best. If it weren't, I wouldn't use it.\n\nAnd a doozy:\n\n> When I'm asked to change my style, I am - quite literally - asked to deny a fundamental Truth of my being.\n\nMe, I know best, you do it your way, I do it my way. But my way's the best way.\n\nThis attitude simply isn't very team-like. One of the nice things about code consistency is simply the human interaction that leads you to your linting settings. It is team bonding. Not as bonding as oversharing at the pub, but certainly bonding, learning how to compromise and sharing ownership.\n\nWhen we originally set up linting at work, I insisted on semicolons. The team didn't feel strongly either way, fine, semicolons. The team liked two space indentations. Despite my preference for four, I compromised on two. I now like two. And safely refactoring Popmotion to also use two was a simple as changing - yes - my linting config.\n\nOn a more practical note, this discussion settles the argument early. You don't \"ugh\" when you inevitably stumble across four-space indentations and you don't get passive-aggressive PRs back-and-forthing over indentation.\n\nThe thought hurts my brain a little. Are there seriously projects out there where lines are written by Bobbie Two-Spaces, interleaved with heathen lines written by Four-Space Jimmy?\n\nIf we remember to consider that our own stylistic **preferences** are **not** a \"fundamental Truth of [our] being\", we'll immediately arrive at a more collaborative, less combative mindset and thus workplace.\n\nIt's fine. Nobody is dying today.\n\nThe sober point comes a little later:\n\n> [...] code is so much more than indentation and quotation choices.\n\nIt is true that code is an expression, even an artistic one. If the one thing we can all agree on is that indentation and quotation choices are essentially petty, then we won't feel so precious about them and start to trust that our character will come through in the actual solutions we choose and invent.\n\nWe're not selling out through compromise.\n\nIt doesn't make things hard, it doesn't make things painful. It is a collaborative effort and an act of imposed self-discipline. It's the act of letting go of ego, a little, and acting as a team. Because we're not all fucking \"peacocks\". We're just assholes, trying to do something cool.\n\n---\n\nPopmotion is a 9kb JavaScript motion engine, and way better than this daft nonsense. Create awesome interactions with tweens, physics and input tracking.\n\n[Make things lovely](/learn/get-started) and/or [send us your stupid abuse on Twitter](https://twitter.com/popmotionjs)\n\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"20170803-coding-style-dont-be-a-dick\"\n    section=\"blog\"\n    undefined\n    title=\"Adhering to a project's coding style: Don't be a dick\"\n    description=\"null\"\n    published=\"3 Aug 17\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/blog/20171210-popmotion-8-upgrade-guide.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Popmotion 8 upgrade guide\n\nThis guide will explain the breaking changes in Popmotion 8 and how to upgrade your project from version 7.\n\n## \\`onUpdate\\` and \\`onComplete\\`\n\nThe biggest change, from a practical point of view, is the way animations are initialised.\n\nPreviously, a \\`tween\\` might have been defined like this:\n\n\\`\\`\\`javascript\ntween({\n  from: 0,\n  to: 1,\n  onUpdate: (v) => console.log(v)\n}).start();\n\\`\\`\\`\n\nNow, that \\`onUpdate\\` is instead provided to \\`start\\`:\n\n\\`\\`\\`javascript\ntween({ from: 0, to: 1 })\n  .start((v) => console.log(v));\n\n// This is equivalent:\ntween({ from: 0, to: 1 })\n  .start({\n    update: (v) => console.log(v)\n  });\n\\`\\`\\`\n\nLikewise, \\`onComplete\\` also provided to \\`start\\`:\n\n\\`\\`\\`javascript\ntween({\n  from: 0,\n  to: 1\n}).start({\n  update: (v) => console.log(v),\n  complete: () => console.log('complete!')\n})\n\\`\\`\\`\n\n## Immutable\n\nEach animation, once defined, is immutable. Once \\`start\\` is called, a **new instance** of that animation is created and executed. Which means you can define an animation once:\n\n\\`\\`\\`javascript\nconst foo = tween({ from: 0, to: 1 });\n\\`\\`\\`\n\nAnd use that definition to power multiple animations:\n\n\\`\\`\\`javascript\nfoo.start((v) => console.log('first animation', v));\nfoo.start((v) => console.log('second animation', v));\n\\`\\`\\`\n\n## Playback controls\n\nThis means that \\`stop\\`, and other playback controls, aren't returned by \\`tween\\`, they're returned from \\`start\\`:\n\n\\`\\`\\`javascript\nconst myTween = foo.start(console.log);\nmyTween.stop();\n\\`\\`\\`\n\n## \\`transform\\` property\n\nPreviously, there was a \\`transform\\` property available to actions. It accepted  a pure function that accepted a value and returned a new one.\n\nIn Popmotion, we refer to these as [transformers](/api/transformers). As the API has evolved, its skewed towards using these pure functions to define functionality. Documents increasingly included references to the \\`pipe\\` transformer, which composes a new transformer from multiple others.\n\nIn Popmotion 8, \\`pipe\\` has been promoted to an action method. When used, it returns **a new version of that action** that pipes all \\`update\\` values through the functions given to \\`pipe\\`:\n\n\\`\\`\\`javascript\nconst double = (v) => v * 2;\nconst px = (v) => v + 'px';\n\nconst foo = tween({ from: 0, to: 1 });\nconst bar = foo.pipe(double, px);\n\nfoo.start(console.log); // Ends with 1\nbar.start(console.log); // Ends with '2px'\n\\`\\`\\`\n\n## Chainable\n\n\\`pipe\\` isn't the only chainable functions available to actions. There's also \\`while\\` and \\`filter\\`, and an API to add new functions will be available in the near future.\n\nHere's a \\`listen\\` action, which is our [DOM event listener action](/api/listen), that only fires when it detects more than two \\`touches\\`:\n\n\\`\\`\\`javascript\nlisten(document, 'touchstart')\n  .filter(({ touches }) => touches.length > 1)\n  .start(({ touches }) => {\n    console.log(touches.length); // more than 1\n  });\n\\`\\`\\`\n\n## \\`value.set\\`\n\n\\`value\\` is now a **reaction**. Which means you can still pass one to an action like this:\n\n\\`\\`\\`javascript\nconst foo = value(0, console.log);\nspring({ to: 300 }).start(foo);\n\\`\\`\\`\n\nAs \\`start\\` accepts reactions either as a function or an object with an \\`update\\` function, \\`value.set()\\` becomes \\`value.update()\\`.\n\n## \\`getVelocity\\`\n\nPreviously, every action has a \\`getVelocity\\` method. In Popmotion 8 I'm attempting to reduce statefulness and move to reactive streams.\n\n\\`value\\` is now the only stateful function to offer a \\`getVelocity\\` function. It's a special type of reaction that maintains state.\n\n\\`\\`\\`javascript\nconst ball = document.querySelector('#ball');\nconst ballX = value(0, styler(ball).set('x'));\n\nspring({ to: 400, stiffness: 500 }).start(ballX);\n\nsetTimeout(() => console.log(ballX.getVelocity()), 200);\n\\`\\`\\`\n\n## Every animation can handle color\n\nThe \\`colorTween\\` animation has been replaced by the capability for every animation to handle colors. Even \\`spring\\` and \\`physics\\`!\n\nSo this:\n\n\\`\\`\\`javascript\ncolorTween({ from: '#fff', to: '#000' })\n\\`\\`\\`\n\nIs now this:\n\n\\`\\`\\`javascript\ntween({ from: '#fff', to: '#000' })\n\\`\\`\\`\n\n## Every animation can handle arrays and objects\n\nIn Popmotion 7, animation of arrays and objects was achieved via the \\`parallel\\` and \\`composite\\` actions respectively.\n\nThese functions still exist in order to compose different animations. But when the animations are the same, this syntax has been greatly simplified:\n\n\\`\\`\\`javascript\nphysics({\n  from: 0,\n  velocity: {\n    x: 100,\n    y: 200\n  }\n}).start(console.log) // Receives { x, y }\n\\`\\`\\`\n\n\\`value\\` can now also be an n-dimensional array or object too, and \\`value.getVelocity\\` will return velocities in the defined format.\n\n## \\`stagger\\`\n\nAs the \\`update\\` method is bound to an animation only when \\`start\\` is called, \\`stagger\\` now accepts functions that can **optionally** return a started action. So this:\n\n\\`\\`\\`javascript\nstagger([\n  tween({ onUpdate: (v) => console.log('1st', v) }),\n  tween({ onUpdate: (v) => console.log('2nd', v) })\n], 50).start();\n\\`\\`\\`\n\nBecomes: \n\n\\`\\`\\`javascript\nstagger([\n  () => tween().start((v) => console.log('1st', v)),\n  () => tween().start((v) => console.log('2nd', v))\n], 50).start();\n\\`\\`\\`\n\nThis also means that \\`stagger\\` can iterate over any function, not just animations.\n\n## \\`touch\\` is now \\`multitouch\\`\n\nThe \\`touch\\` action has been renamed \\`multitouch\\`.\n\nPreviously, it provided \\`onUpdate\\` with an array of touches. Now, \\`touches\\` is a property that sits alongside \\`scale\\` and \\`rotate\\` properties:\n\n\\`\\`\\`javascript\nmultitouch().start(({ touches, scale, rotate }) => {});\n\\`\\`\\`\n\n## And the rest\n\n- \\`physics\\` \\`spring\\` property is now \\`springStrength\\`.\n- \\`physics\\` \\`autoStopSpeed\\` property is now \\`restSpeed\\`.\n- \\`spring\\` \\`restDisplacement\\` property is now \\`restDelta\\`.\n- \\`flow\\` alias for \\`pipe\\` has been removed.\n- \\`add\\`, \\`subtract\\`, \\`divide\\`, \\`multiply\\`, \\`conditional\\`, \\`alpha\\`, \\`percent\\`, \\`degrees\\`, \\`px\\`, \\`rgbUnit\\`, \\`rgba\\`, \\`hex\\`, \\`color\\`, \\`hsla\\` transformers have been removed. Value type transformers like \\`hex\\` can still be accessed from the [valueTypes](/api/value-types).\n- Render loop function must be imported separately from [Framesync](https://github.com/Popmotion/framesync)\n\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"20171210-popmotion-8-upgrade-guide\"\n    section=\"blog\"\n    undefined\n    title=\"Popmotion 8 upgrade guide\"\n    description=\"How to upgrade Popmotion 7 to 8\"\n    published=\"10 Dec 17\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/blog/20171211-introducing-popmotion-8.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Introducing Popmotion 8\n\nPopmotion 8 is a functional, reactive animation library.\n\nIt's the result of over three months work, the result of wanting to add a humble \\`pipe\\` method and instead tumbling down the rabbit hole.\n\nIt introduces new animations: \\`decay\\`, \\`everyFrame\\`, \\`keyframes\\` and \\`timeline\\`. It makes input dragging a breeze with our revamped \\`pointer\\` and \\`multitouch\\` actions.\n\nCrucially, there's a new streamlined, reactive API.\n\nThis new API reflects Popmotion's gradual shift towards functional programming and adopts it as a core part of the design philosophy.\n\nThe result is a small, flexible and composable library that I hope you'll find fun to use. Let's take a look at what's new.\n\n## Animations\n\n### \\`decay\\`\n\n\\`decay\\` models a form of exponential deceleration to create motion like momentum scrolling on smartphones.\n\nJust provide it \\`velocity\\` and \\`from\\` properties:\n\n\\`\\`\\`javascript\ndecay({\n  velocity: 1000,\n  from: 0\n}).start((v) => ...)\n\\`\\`\\`\n\n<CodePen id=\"Kyewbv\" />\n\nIt also exposes a \\`modifyTarget\\` option that provides a functional API for adding features like snap-to-grid.\n\n### \\`everyFrame\\`\n\n\\`everyFrame\\`, as you might imagine, fires once per frame. It provides the amount of time since it started:\n\n\\`\\`\\`javascript\neveryFrame().start((timeSinceStart) => ...);\n\\`\\`\\`\n\nIt's the fundamental driver of every Popmotion animation. We've exposed it because we reckon this kind low-level action will be useful in animations, like porting After Effects expressions:\n\n<CodePen id=\"XzYJvP\" />\n\n### \\`keyframes\\`\n\n\\`keyframes\\` transitions through a number of states over a set duration of time.\n\nIts API is inspired by Apple's \\`CAKeyframeAnimation\\`, which makes it trivial to resize the overall animation:\n\n\\`\\`\\`javascript\nkeyframes({\n  values: [\n    { x: 0, y: 0 },\n    { x: 100, y: 0 },\n    { x: 100, y: 100 }\n  ],\n  times: [0, 0.3, 1],\n  duration: 1000\n})\n\\`\\`\\`\n\n<CodePen id=\"JOZGdp\" />\n\n### \\`timeline\\`\n\n\\`timeline\\` is used to orchestrate more complicated patterns of tweens.\n\nIt supports absolute and relative timestamps, as well as parallel and staggered motion. The output action has all the same playback methods as \\`tween\\`, making it fully scrubbable.\n\nIn most animation libraries, the timeline function is a bit of a black box that we chuck setters or selectors into.\n\nAs Popmotion is a reactive library, we label each segment with a \\`track\\` property, and that then the latest state gets output as an object with those labels:\n\n\\`\\`\\`javascript\ntimeline([\n  { track: 'shade', from: 0, to: 1 },\n  '-100',\n  {\n    track: 'modal',\n    from: { y: -100, opacity: 0 },\n    to: { y: 0, opacity: 1 }\n  }\n]).start(({ shade, modal }) => ...)\n\\`\\`\\`\n\nThis means we can pass the output of timeline through the chainable methods \\`pipe\\`, \\`while\\` and \\`filter\\` (more on those later).\n\nAs timelines become more complicated, maintaining the link between labels and setters can become increasingly difficult, but the trade-off is a timeline that is immutable, composable, pure, and testable.\n\nWe're also experimenting with functions that can take a timeline definition and automatically generate the output reaction.\n\n<CodePen id=\"aEoqEG\" height={400} />\n\n## Input\n\n### \\`pointer\\`\n\nThe \\`pointer\\` action has been in Popmotion since before it was called Popmotion. But, its API has always been confused making simple tasks like dragging more convoluted than they needed to be.\n\nIn Popmotion 7, \\`pointer\\` output its absolute position and it was up to a second action, \\`trackOffset\\`, to get the **movement** of \\`pointer\\` relative to another point (say, a DOM element).\n\nPopmotion 8 scraps the \\`trackOffset\\` action entirely. Now, \\`pointer\\` will output its absolute position when used like this:\n\n\\`\\`\\`javascript\npointer().start(({ x, y }) => ...)\n\\`\\`\\`\n\n(Also notice how we no longer need to provide \\`pointer\\` with a \\`MouseEvent\\` or \\`TouchEvent\\`.)\n\nTo output that pointer's movement **applied to another point**, we simply need to provide that point as our initial argument:\n\n\\`\\`\\`javascript\npointer({ x: 0, y: 0 }).start(({ x, y }) => ...)\n\\`\\`\\`\n\n<CodePen id=\"RjBZoe\" />\n\n### \\`multitouch\\`\n\nThanks to the efforts of [Mars](https://twitter.com/marsi), Popmotion has had multitouch support since version 6.\n\nThere are two major changes coming in 8. The first and most apparent is we've changed the name of the action from \\`touches\\` to \\`multitouch\\` to highlight the second change:\n\nIt no longer outputs just an array of touches. \\`touches\\` is joined by \\`scale\\` and \\`rotate\\` properties:\n\n\\`\\`\\`javascript\nmultitouch().start(({ touches, scale, rotate }) => ...)\n\\`\\`\\`\n\n<CodePen id=\"LOBjxQ\" />\n\nLike \\`pointer\\`, \\`multitouch\\` accepts \\`scale\\` and \\`rotate\\` arguments and, if defined, will output the **change** in those properties as applied to the given values.\n\n## Reactive API\n\nAt the heart of all these new features is a change in the core building block of all animations, the **action**.\n\nThe \\`action\\` function is used to create streams of reactive values. Think of it as an animation-focused, tiny alternative to Rx Observables.\n\nIt looks like this:\n\n\\`\\`\\`javascript\naction(({ update, complete, error }) => {})\n\\`\\`\\`\n\nFor a practical example of how \\`action\\` works, let's define an function called \\`just\\`. It'll return an action that, when started, will fire \\`update\\` with the provided value and then \\`complete\\`:\n\n\\`\\`\\`javascript\nconst just = (v) => action(({ update, complete }) => {\n  update(v);\n  complete();\n});\n\njust(2).start(console.log); // 2\n\\`\\`\\`\n\nEvery time we \\`start\\` an action, its initialisation function runs anew, creating a new instance of the action. Because all animations are actions, we can define an animation once:\n\n\\`\\`\\`javascript\nconst moveRight = tween({ to: 300 });\n\\`\\`\\`\n\nAnd use it multiple times:\n\n\\`\\`\\`javascript\nmoveRight.start(console.log); // 0 - 300\nmoveRight.start(console.log); // 0 - 300\n\\`\\`\\`\n\nActions offer a number of chainable methods (currently \\`filter\\`, \\`pipe\\` and \\`while\\`, with an API for adding more on the way). Each returns a brand new version of the action with the added functionality:\n\n\\`\\`\\`javascript\nconst double = v => v * 2;\nconst px = v => v + 'px';\n\nconst justTwo = just(2);\n\njustTwo.start(console.log); // 2\n\njustTwo\n  .pipe(double, px)\n  .start(console.log); // '4px'\n\\`\\`\\`\n\nIn the last 6 months Popmotion has spun out [Framesync](/api/framesync) and [Stylefire](/stylefire) as standalone libraries.\n\nIt's helped me take greater care and consideration over where to draw the lines between the role and responsibilities of various parts of the library and enables people to use the isolated functionality in their own code or libraries.\n\nI can imagine a near-future where actions are spun out as a tiny reactive library, where people can start dabbling with reactive programming outside of animation without the full payload of something the size of Rx.\n\n## And the rest...\n\n### File size and individual imports\n\nPopmotion has always tried to respect your bytes. One of the reasons I wrote it in the first place was a dissatisfaction with the size of existing libraries in comparison to the benefits they provided.\n\nPopmotion 8 is a little bigger than 7 (11.5kb vs 10kb). Though, as such a radical rewrite with so many new features, I think there are efficiencies to be made over the coming months.\n\nIn the meantime, everything in Popmotion is **now available as an individual import**. Which means, if you only want to use (for instance) \\`spring\\`, you can import and use that for roughly 2kb. \n\n### Colours and multi-prop animations\n\nIn Popmotion 7, we exposed the ability to animate colours with \\`colorTween\\`. Multi-property animations could be composed with the \\`composite\\` and \\`parallel\\` compositors.\n\nThis has all been streamlined in 8. Every animation can now animate colors, objects, arrays (and objects and arrays of colors!).\n\nIt's as simple as this:\n\n\\`\\`\\`javascript\ntween({\n  from: { x: 0, color: '#f00' },\n  to: { x: 100, color: '#fff' }\n}).start(({ x, color }) => ...)\n\\`\\`\\`\n\n## Conclusion\n\nThat's most of what's new in Popmotion 8. Existing users should check out our [upgrade guide](/blog/20171210-popmotion-8-upgrade-guide) to handle breaking changes.\n\nAfter three years of development I'm **finally** happy with the API. I think the reactive model works incredibly well for neatly and declaratively handling streams of values and fits perfectly with the functional approach I was already moving towards.\n\nWith these solid foundations in place, the next logical step feels like exploring a way of describing the properties of UI elements and having motion and interactions derive naturally from that. Like a physically-based rendering for motion.\n\nOnce more down the rabbit hole.\n\n---\n\n[Get started with Popmotion](/learn/get-started)\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"20171211-introducing-popmotion-8\"\n    section=\"blog\"\n    undefined\n    title=\"Introducing Popmotion 8\"\n    description=\"Popmotion 8 is a functional, reactive approach to animation.\"\n    published=\"11 Dec 17\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/blog/20180104-when-ios-throttles-requestanimationframe.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# When iOS throttles requestAnimationFrame to 30fps\n\n> **TL;DR:** iOS throttles \\`requestAnimationFrame\\` to 30fps in cross-origin iframes and low power mode.\n\nYesterday I was looking at the examples on the [Popmotion homepage](https://popmotion.io) with my iPhone. They looked odd, clearly suffering a sluggish stutter, the cruel affliction of (**gasp**) 30 frames per second.\n\nHere's an artificially-throttled example:\n\n<CodePen id=\"dJzaMo\" />\n\nI'd seen this illness once before. If you're looking at the example above on an iOS browser, check out this unthrottled example:\n\n<CodePen id=\"WXOPWX\" />\n\nLooks the same, right? To other readers, this second example runs at a silky 60fps. Animation as the gods intended.\n\nI found that it was only affecting animations running on CodePen. The reason was initially unclear.\n\nI assumed that CodePen itself was doing **something** weird in the background that caused the stuttering. They helpfully pointed me to the Debug View, which runs the pen without the iframe.\n\nIt worked. 60fps on iOS. It wasn't CodePen after all.\n\nMy first discovery:\n\n## iOS throttles \\`requestAnimationFrame\\` in iframes\n\nSpecifically, it turns out, **cross-origin iframes**. Which is every CodePen embed, even the ones hosted on CodePen's own site (as the live panel is served on a subdomain).\n\nAs detailed in this [WebKit changelog](https://trac.webkit.org/changeset/215070/webkit), the throttling is cleared once a user interacts with the iframe.\n\nTry it for yourself. If you're on iOS, take a look at the tween animation again:\n\n<CodePen id=\"WXOPWX\" />\n\nThis time, tap anywhere within the frame and watch as the 30fps eye-thrashing is replaced by the soft caress of 60fps.\n\n### But... why?\n\nI haven't found a stated reason for this behaviour. But that doesn't stop semi-educated speculation.\n\nIframes are commonly used for advertising. Adverts are fairly liberal with your CPU cycles. So I imagine the throttling is an attempt to prevent adverts from eating your battery.\n\nThe performance cap is cleared once the user interacts with the iframe and indicates that the advert (or other embedded content) isn't unwelcome.\n\nAn alternative solution might be to throttle iframes that lie outside the current viewport (maybe pause execution entirely), and unthrottle when they enter. This current solution feels heavy-handed.\n\n### The remaining mystery\n\nBack to the present, this didn't explain why the examples on the homepage were stuttering. They're part of the page itself, no iframes.\n\nAs the myriad of known and unknown potential causes flashed before my eyes, a familiar feeling of nausea set in.\n\nStanding on the precipice of a rabbit hole of unknown depth, I began the ritual.\n\nOpened my MacBook. Chrome. Performance tab. Throttled CPU... 60fps.\n\nChecked my partner's phone, same OS, same make and model... 60fps.\n\nGoogled for bugs with iOS 11.2.1 and 30fps rAF... Nothing. What the fuuuuuu...\n\nI stared at my phone, dumbfounded. Maybe I needed to reset my phone. Maybe it was because my phone was the wrong colour. Maybe I simply needed to be kinder to Siri.\n\nLuckily, I saw it, and I knew I'd found the culprit. The nausea lifted. Relief settled:\n\n![Take me from this earth](/images/low-power-mode.png)\n\nLow power mode. Though part of me wouldn't believe it until I toggled it on and off and saw the difference with my own eyes, it made sense.\n\nMy second discovery:\n\n## iOS throttles \\`requestAnimationFrame\\` in low power mode\n\nAs detailed in this [WebKit bug](https://bugs.webkit.org/show_bug.cgi?id=168837), iOS throttles \\`requestAnimationFrame\\` to 30fps whilst low power mode is active.\n\nI have mixed feelings about this.\n\nFirst, there's no doubt that it's very clever. It is, in the short-term, a boon for users.\n\nIn the long-term, I'm not so sure. I've already covered in detail why the [mobile web is a dreadful platform](https://popmotion.io/blog/20170710-mobile-web-is-awful-and-were-all-to-blame/) to develop for.\n\nThis is yet another unpredictable tributary feeding into a much larger river of unpredictable nonsense that we have to put up with.\n\nThe salmon will get tired. It's a self-perpetuating cycle. Horizons, ambitions and standards will drop. Further emboldening mobile browser vendors to push for clever solutions to improve user experience and degrade the developer one.\n\nOn iOS, the app developers themselves are given the responsibility to [respond to low power mode](https://developer.apple.com/library/content/documentation/Performance/Conceptual/EnergyGuide-iOS/LowPowerMode.html), whereas WebKit still hasn't implemented the [Battery Status API](https://developer.mozilla.org/en-US/docs/Web/API/Battery_Status_API). It's a familiar story, and a shame.\n\nA clever, battery-saving shame.\n\n---\n\nIf you still have any energy left in your tired little salmon fins, make the mobile web an app-quality kinda place with [Popmotion](https://popmotion.io). Alternatively, throw your opinions in my stupid salmon face [on Twitter](https://twitter.com/popmotionjs)\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"20180104-when-ios-throttles-requestanimationframe\"\n    section=\"blog\"\n    undefined\n    title=\"When iOS throttles requestAnimationFrame to 30fps\"\n    description=\"In specific situations, iOS throttles rAF to 30fps. Here's when, and why it's wrong.\"\n    published=\"4 Jan 18\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/blog/20180521-pose-2-migration-guide.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# What's new in Pose 2.0?\n\nPose and React Pose 2.0 are out now!\n\nThey introduce a simple new API for \\`transition\\`, so there's now no requirement to import Popmotion separately for custom transitions.\n\n\\`transition\\` can also now accept a named map of values, meaning no more having to check \\`key\\` to return different animations.\n\nAs we all know all-too-well, major version increases also mean one thing: All your shit's broke. Just kidding. Only some of your shit's broke.\n\nLet's take a look.\n\n## Transition definitions\n\nUntil now, creating custom transitions involved importing Popmotion animations and manually passing along Pose-generated values like \\`from\\`, \\`to\\` and \\`velocity\\`:\n\n\\`\\`\\`javascript\nimport { tween, easing } from 'popmotion';\n\nconst config = {\n  visible: {\n    opacity: 0,\n    transition: (props) => tween({\n      ...props,\n      duration: 1000,\n      ease: easing.linear\n    })\n  }\n};\n\\`\\`\\`\n\nNow, we can simply define \\`transition\\` as an object of animation props:\n\n\\`\\`\\`javascript\nconst config = {\n  visible: {\n    opacity: 0,\n    transition: { duration: 1000, ease: 'linear' }\n  }\n};\n\\`\\`\\`\n\nNotice that we don't need to import easing functions separately, as Pose provides a collection of named easings. We can even automatically define a cubic bezier easing by providing an array:\n\n\\`\\`\\`javascript\nease: [.01, .64, .99, .56]\n\\`\\`\\`\n\nBy default, a transition defined like this will be a [tween](/api/tween). But Pose supports Popmotion's [spring](/api/spring), [keyframes](/api/keyframes), [physics](/api/physics) and [decay](/api/decay) animations too.\n\nWe can switch to one of these by setting \\`transition.type\\`:\n\n\\`\\`\\`javascript\nconst config = {\n  dragEnd: {\n    x: 0,\n    transition: { type: 'spring', stiffness: 1000 }\n  }\n}\n\\`\\`\\`\n\nOr dynamically set them as a function:\n\n\\`\\`\\`javascript\nconst config = {\n  dragEnd: {\n    x: 0,\n    transition: ({ velocity }) => velocity < 0\n      ? { type: 'spring', stiffness: 1000 }\n      : { type: 'physics', to: -1000 }\n  }\n}\n\\`\\`\\`\n\nThere's also some new properties supported by all animations: \\`round\\`, \\`min\\`, \\`max\\` and \\`delay\\`. Take a look at the [custom transition tutorial for full details](/pose/learn/custom-transitions).\n\nOf course, for animations that aren't yet possible with the new transition API, these functions can still return Popmotion animations just as before. \n\n## Named transition maps\n\nPreviously, to return different animations for different properties, we had to check the provided \\`key\\` property:\n\n\\`\\`\\`javascript\nconst config = {\n  hidden: {\n    x: -100,\n    opacity: 0,\n    transition: ({ key, ...props }) => (key === 'x')\n      ? spring({ ...props, stiffness: 1000 })\n      : tween({ ...props, duration: 100 })\n  }\n}\n\\`\\`\\`\n\nInstead, we can now **optionally** define \\`transition\\` as a named map, with a \\`default\\` prop for a catch-all transition:\n\n\\`\\`\\`javascript\nconst config = {\n  hidden: {\n    x: -100,\n    opacity: 0,\n    transition: {\n      x: { type: 'spring', stiffness: 1000 },\n      default: { duration: 100 }\n    }\n  }\n}\n\\`\\`\\`\n\nThese named transitions can also be functions that return dynamic transition definitions or Popmotion animations.\n\nTransition definitions and named transition maps will both be coming to React Native Pose in the near future.\n\n## Migration guide\n\nOf course, with a major version change there's always a breaking change or two. We've started flagging these in advance with deprecation warnings, where possible, so hopefully the impact will be minimal.\n\nHere's what's changed:\n\n### \\`transitionProps\\` is now \\`props\\`\n\nIn a bit of bikeshedding that should, nonetheless, make the API a little easier to explain, \\`transitionProps\\` is now \\`props\\`.\n\nWhen they were first introduced, \\`transitionProps\\` were used to dynamically generate \\`transition\\`s. Now, they can be used to dynamically set any pose prop, hence the change in terminology:\n\n\\`\\`\\`javascript\nconst config = {\n  open: {\n    x: ({ x }) => x\n  },\n  props: { x: 0 }\n};\n\n// Pose\nconst poser = pose(config);\n\n// React Pose\nconst Posed = posed.div(config);\n() => <Posed x={10} />\n\\`\\`\\`\n\nThis has also led to the renaming of \\`setTransitionProps\\` to \\`setProps\\` for the vanilla Pose users in the audience.\n\n### FLIP is now opt-in\n\nPreviously, Pose would detect if you were animating a layout property like \\`width\\` or \\`top\\` and automatically convert that to a FLIP animation.\n\nAlthough FLIP animations are more performant, if not handled with care they can cause unexpected visual artifacts. We also don't currently have a good strategy for animating to \\`0\\` (which makes the \"invert\" stage of FLIP decidedly tricky - what's the inverse of 0?)\n\nThis was one of the most commonly-occurring points of confusion with the API, so I've made it opt-in with \\`flip: true\\`:\n\n\\`\\`\\`javascript\nconst config = {\n  open: {\n    width: '100vw',\n    height: '100vh',\n    flip: true\n  },\n  close: {\n    width: '100px',\n    height: '100px',\n    flip: true\n  }\n}\n\\`\\`\\`\n\nThe good news is that this shouldn't break any of your code. If left unchanged, Pose will simply animate the layout property, **unless**, as above, you're animating between two different unit types which Pose doesn't currently support (PRs welcome!)\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"20180521-pose-2-migration-guide\"\n    section=\"blog\"\n    undefined\n    title=\"What's new in Pose 2.0\"\n    description=\"A quick overview of what's new in Pose and React Pose 2.0, and how to migrate\"\n    published=\"29 May 18\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/index.js",
    "content": "import PopmotionHomepage from '~/templates/Popmotion';\n\nexport default () => <PopmotionHomepage />;\n"
  },
  {
    "path": "packages/site/pages/pure/learn/action-reaction.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Actions and reactions\n\nThe \\`tween\\` function returns what's known in Popmotion as an **action**.\n\nPopmotion is a reactive library, and actions are functions that **create** streams of values. These actions output to **reactions**.\n\n**In Popmotion, every animation and input is an action**. In this quick tutorial, we'll gain a better understanding of actions and reactions by writing our own.\n\n## Import\n\n\\`\\`\\`javascript \nimport { action } from 'popmotion';\n\\`\\`\\`\n\n## Creating an action\n\nThe \\`action\\` function accepts a single argument. It's an initialisation function that will be executed **each time the returned action is started** via its \\`start\\` method.\n\nThis means that we can define one action, and start it multiple times, leading to multiple instances of that action.\n\nThe \\`init\\` function is provided an object of three functions: \\`update\\`, \\`complete\\`, and \\`error\\`:\n\n\\`\\`\\`javascript\naction(({ update, complete, error }) => {})\n\\`\\`\\`\n\nLet's define a function called \\`just\\`. It'll return an action that, when started, will fire \\`update\\` with the provided value and then \\`complete\\`:\n\n\\`\\`\\`javascript\nconst just = (v) => action(({ update, complete }) => {\n  update(v);\n  complete();\n});\n\\`\\`\\`\n\nNow, when the action returned from \\`just\\` is \\`start\\`ed, it'll emit the provided value:\n\n\\`\\`\\`javascript\njust(1).start(console.log); // 1\n\\`\\`\\`\n\n\\`console.log\\` is being used as a **reaction**. It will fire whenever the new action instance calls \\`update\\` with a new value.\n\nWe also defined \\`just\\` to fire \\`complete\\` once it's finished. Instead of a function, we can provide an object of \\`update\\` and \\`complete\\` functions as our reaction:\n\n\\`\\`\\`javascript\njust(1).start({\n  update: console.log,\n  complete: () => console.log('complete!')\n});\n\\`\\`\\`\n\nWhen \\`start\\` runs, the initialisation function is run anew, and a **new instance** of the active action is returned:\n\n\\`\\`\\`javascript\nconst justOne = just(1);\njustOne.start(console.log); // 1\njustOne.start(console.log); // 1\n\\`\\`\\`\n\nAs all Popmotion animations are actions, we can define an animation once and use it multiple times:\n\n\\`\\`\\`javascript\nconst mySpring = spring({ to: 500 });\n\nmySpring.start({\n  update: console.log,\n  complete: () => console.log('complete!')\n});\n\nmySpring.start({\n  update: (v) => console.log('second spring: ' + v),\n  complete: () => console.log('second spring also complete!')\n});\n\\`\\`\\`\n\n## Chainable modifiers\n\nAll actions, as well as special reactions like [multicast](/api/multicast) and [value](/api/value), are **chainable**.\n\nThey offer methods that **return a new instance of the action or reaction** with altered behaviour.\n\nCurrently, there are three chainable methods: \\`filter\\`, \\`pipe\\` and \\`while\\`.\n\nAn API for developers to add more is on the roadmap.\n\nLet's take a look at an example of each:\n\n### \\`filter\\`\n\n\\`filter\\` accepts a single function. This function is passed the latest value emitted from \\`update\\`.\n\nThe value is only passed down the chain if the function provided to \\`filter\\` returns \\`true\\`.\n\n\\`\\`\\`javascript\naction(({ update }) => {\n  update(1);\n  update(2);\n  update(1);\n}).filter((v) => v === 1)\n  .start(log); // 1, 1\n\\`\\`\\`\n\n### \\`pipe\\`\n\n\\`pipe\\` accepts a series of functions.\n\nEach function is provided the latest value emitted from \\`update\\`, and returns a new value that is passed down the chain:\n\n\\`\\`\\`javascript\nconst double = (v) => v * 2;\nconst px = (v) => v + 'px';\n\nconst one = just(1);\nconst twoPx = one.pipe(double, px);\n\none.start(console.log); // 1\ntwoPx.start(console.log); // '2px'\n\\`\\`\\`\n\n### \\`while\\`\n\n\\`while\\` accepts a single function. This function is passed every value from \\`update\\` and fires \\`complete\\` if the function returns \\`false\\`:\n\n\\`\\`\\`javascript\njust(1)\n  .while((v) => v === 2);\n  .start(console.log); // never fires, as while returned false\n\\`\\`\\`\n\n### Combining\n\nLet's combine \\`pipe\\` and \\`while\\` to make a [pointer](/api/pointer) that outputs its \\`x\\` position as percentage of the current viewport, and automatically stops itself if the pointer is more than 75% across the screen:\n\n\\`\\`\\`javascript\nconst pickX = ({ x }) => x;\nconst viewportWidth = window.innerWidth;\nconst percentageOfViewport = (v) => v / viewportWidth * 100;\nconst asPercent = (v) => v + '%';\n\npointer()\n  .pipe(pickX, percentageOfViewport) // The output of this\n  .while((v) => v < 75) // Gets passed to this\n  .pipe(asPercent) // Before being passed to this\n\\`\\`\\`\n\n## Stopping actions\n\nEvery action returns a \\`stop\\` method:\n\n\\`\\`\\`javascript\nconst foo = tween().start(console.log);\nfoo.stop();\n\\`\\`\\`\n\nBut how does the code defined in your \\`init\\` function know its been stopped?\n\nEach init function can **optionally** return an API. This can include a \\`stop\\` function:\n\n\\`\\`\\`javascript\nconst oneEverySecond = action(({ update }) => {\n  const updateOne = () => update(1);\n  const interval = setInterval(updateOne, 1000);\n\n  return {\n    stop: () => clearInterval(interval)\n  };\n});\n\nconst foo = oneEverySecond.start();\nsetTimeout(() => foo.stop(), 3000); // 1, 1, 1\n\\`\\`\\`\n\n## Custom API\n\nYour action can return a custom API, too:\n\n\\`\\`\\`javascript\nconst valueEverySecond = action(({ update }) => {\n  let outputValue = 1;\n  const updateOne = () => update(outputValue);\n  const interval = setInterval(updateOne, 1000);\n\n  return {\n    stop: () => clearInterval(interval),\n    setOutputValue: (v) => outputValue = v\n  };\n});\n\nconst foo = valueEverySecond.start();\nfoo.setOutputValue(2); // 2, 2...\n\\`\\`\\`\n\n## Conclusion\n\nBy chaining actions we can create new actions with different behaviour.\n\nThis flexibility is available on all animations and inputs, and later tutorials will touch on these capabilities.\n\nIn the next tutorial, we'll learn how to implement pointer tracking with two input actions, [Pointer and Listen](/learn/input-tracking).\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"action-reaction\"\n    section=\"learn\"\n    category=\"basics\"\n    title=\"Actions and reactions\"\n    description=\"A quick look at Popmotion's simplified reactive model.\"\n    published=\"\"\n    theme=\"pure\"\n    next=\"input-tracking\"\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/learn/circular-motion.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Circular motion\n\nHTML and SVG elements are positioned by \\`x\\` and \\`y\\` coordinates. This type of positioning is known as **cartesian coordinates**, and animating these is great for moving elements in straight lines (the majority use-case).\n\nHowever, to move elements in a circular fashion, it's much easier to animate position using **polar coordinates**: Position as defined by \\`angle\\` and \\`radius\\`.\n\nWe can then convert these polar coordinates into \\`x\\` and \\`y\\` to produce movement like this:\n\n<CodePen id=\"eygBGW\" height={400} />\n\nIn this quick tutorial, we'll create circular motion converting polar to cartesian coordinates using functional composition.\n\nAs a bonus step, we'll then explain how we can rotate the element to face its direction of travel.\n\nYou can [fork this CodePen](https://codepen.io/popmotion/pen/qpRROg?editors=0010) to follow along.\n\n## Position\n\nWe can convert \\`radius\\` and \\`angle\\` into \\`x\\` and \\`y\\` using \\`cos\\` and \\`sin\\` functions:\n\n\\`\\`\\`javascript\nconst x = radius * Math.cos(angle);\nconst y = radius * Math.sin(angle);\n\\`\\`\\`\n\nBy expressing this as a pure function, we'll be able to provide it to any animation's \\`pipe\\` method:\n\n\\`\\`\\`javascript\nconst polarToCartesian = ({ angle, radius }) => ({\n  x: radius * Math.cos(angle),\n  y: radius * Math.sin(angle)\n});\n\\`\\`\\`\n\nWith this function we can write a simple animation that:\n- 1) Changes \\`radius\\` at a constant velocity of 5 radians a second.\n- 2) Pipes the animation output through \\`polarToCartesian\\` to convert into \\`x\\` and \\`y\\`.\n- 3) Styles the div by using \\`boxStyler.set\\`:\n\n\\`\\`\\`javascript\nphysics({\n  from: { angle: 0, radius: 150 },\n  velocity: { angle: 5, radius: 0 }\n}).pipe(polarToCartesian)\n  .start(boxStyler.set);\n\\`\\`\\`\n\nNow our box moves in a circular motion.\n\n<CodePen id=\"GyrWJv\" />\n\nIn this animation we're keeping \\`radius\\` at a constant value by setting \\`velocity\\` to \\`0\\`. By using the \\`composite\\` function, we can combine two different animations to animate \\`radius\\` and \\`angle\\` in different ways:\n\n\\`\\`\\`javascript\ncomposite({\n  angle: physics({ velocity: 5 }),\n  radius: tween({\n    from: 0,\n    to: 150,\n    yoyo: Infinity,\n    ease: easing.easeInOut,\n    duration: 2000\n  })\n}).pipe(polarToCartesian)\n  .start(boxStyler.set);\n\\`\\`\\`\n\n## Direction\n\nIt looks a little awkward to have a square stay upright as it moves in a circular motion.\n\nWe can calculate and inject a \\`rotate\\` property based on the current \\`angle\\` to ensure the square is facing the direction of travel.\n\nFirst, let's make our \\`polarToCartesian\\` function more composable by allowing it to pass through any properties that it doesn't consume using spread props:\n\n\\`\\`\\`javascript\nconst polarToCartesian = ({ angle, radius, ...props }) => ({\n  x: radius * Math.cos(angle),\n  y: radius * Math.sin(angle),\n  ...props\n});\n\\`\\`\\`\n\nNext, we need to make a function that simply takes \\`angle\\` and returns the angle perpendicular to it as a new property, \\`rotate\\`.\n\n\\`cos\\` and \\`sin\\` functions accept radians, whereas CSS and SVG \\`rotate\\` properties are defined in degrees. We can use Popmotion's [\\`radiansToDegrees\\` calculator](/api/calc) to convert \\`angle\\` into degrees, and then simply rotate it by \\`90\\`:\n\n\\`\\`\\`javascript\nconst rotatePerpendicular = (props) => {\n  const { angle } = props;\n  return {\n    rotate: radiansToDegrees(angle) + 90,\n    ...props\n  };\n};\n\\`\\`\\`\n\nApplying this new function is as easy as modifying \\`pipe\\` to read:\n\n\\`\\`\\`javascript\n.pipe(rotatePerpendicular, polarToCartesian)\n\\`\\`\\`\n\n<CodePen id=\"PEWWmG\" />\n\n## Conclusion\n\nCircular motion is much easier to reason about in polar coordinates, and mapping these to cartesian is simple with \\`pipe\\`.\n\nWe can animate \\`angle\\` and \\`radius\\` with separate animations by using the \\`composite\\` composition function.\n\nAnd finally, we can make the element rotate along with the direction of travel by converting \\`angle\\` into degrees and then adding an extra \\`90\\` degrees.\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"circular-motion\"\n    section=\"learn\"\n    category=\"how-to\"\n    title=\"Circular motion\"\n    description=\"How to animate angle and radius to output x and y coordinates.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/learn/constrain-motion.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Constrain motion\n\nWhen creating UIs, there's plenty of instances when we want to constrain motion to within a specific range.\n\nFor instance, if we're making an input slider, we want to constrain its sliding motion to within the slider's visible boundaries.\n\nOtherwise, the illusion of a coherent piece of UI is broken, and the input is useless:\n\n<CodePen id=\"KZzWdz\" height={200} />\n\nIn this tutorial, we'll look at a functional approach to solving this problem. We'll handle out-of-range motion with 1) a hard clamp, and 2) a static spring.\n\nYou can follow along by forking [this CodePen](https://codepen.io/popmotion/pen/KZzWdz?editors=0010).\n\n## Clamp\n\nThe easiest way to restrict motion to within a range is by clamping it. Clamping is simply the process of restricting a number within a range.\n\nJavaScript includes two commonly-used clamping functions, \\`Math.min\\` and \\`Math.max\\`.\n\nWe can change the dragging action from:\n\n\\`\\`\\`javascript\npointerX(handleX.get())\n  .start(handleX)\n\\`\\`\\`\n\nTo:\n\n\\`\\`\\`javascript\npointerX(handleX.get())\n  .pipe(v => Math.max(0, v))\n  .start(handleX)\n\\`\\`\\`\n\nBy using \\`Math.max\\` to clamp the lower range to \\`0\\`, you'll notice you can't drag the handle beyond the left boundary:\n\n<CodePen id=\"ppyeGW\" height={200 />\n\nWe could add the right boundary like this:\n\n\\`\\`\\`javascript\npointerX(handleX.get())\n  .pipe(\n    v => Math.max(0, v),\n    v => Math.min(250, v)\n  )\n  .start(handleX)\n\\`\\`\\`\n\nPopmotion provides a clearer way of expressing this via the \\`clamp\\` [transformer](/api/transformers). This function accepts a range and returns a function that will clamp any provided number to within that range:\n\n\\`\\`\\`javascript\nclamp(0, 250)(-50) // 0\n\\`\\`\\`\n\nSo our \\`pointerX\\` function becomes:\n\n\\`\\`\\`javascript\npointerX(handleX.get())\n  .pipe(clamp(0, 250))\n  .start(handleX)\n\\`\\`\\`\n\n<CodePen id=\"eyZvar\" height={200} />\n\nWe now have a functional input slider! But we don't have a **delightful** one.\n\nThink of iOS, when you scroll a view beyond its boundaries. It doesn't stop dead, it tugs back. It's a visceral and satisfying experience.\n\nWe can replicate this experience with Popmotion using static springs.\n\n## Static springs\n\nPopmotion has so many springs you could use it as a mattress. It's not a point of pride, it can be confusing. But, different springs are useful in different situations:\n\n- [Spring](/api/spring) is a highly-accurate simulation, but immutable. Most appropriate for **spring animations**.\n- [Physics](/api/physics) is a lightweight integrated simulation that can change over time. Most appropriate for **spring interactions**.\n\nOf the two, \\`physics\\`, in theory, could be used to restrain motion to a range. But it's overkill. You'd have to set conditional statements to start and stop animations, grab the velocity from \\`handleX\\`, set this and that. It'd be an imperative soup.\n\nInstead, Popmotion provides two transformers that can be used in a purely functional manner: \\`linearSpring\\` and \\`nonlinearSpring\\`.\n\nThey both share an API. Provide a \\`strength\\` and a \\`target\\`, and they'll return a function. This function, when given a numerical value, will return a new number \"pulled\" towards the target.\n\n\\`\\`\\`javascript\nlinearSpring(0.25, 0)(4) // 1\n\\`\\`\\`\n\n\\`linearSpring\\` applies a **constant force**, whereas \\`nonlinearSpring\\` applies a **greater force the further the given number is away from \\`target\\`**.\n\nIn tandem with the \\`conditional\\` transformer, we can apply these springs only when the number output by \\`pointerX\\` exceeds the defined boundaries:\n\n\\`\\`\\`javascript\nconditional(\n  v => v < 0, // If less than 0\n  linearSpring(0.25, 0) // Apply spring\n)\n\\`\\`\\`\n\nLet's compose a new function using \\`pipe\\`, \\`conditional\\` and \\`linearSpring\\` that will restrict a range of motion using springs:\n\n\\`\\`\\`javascript\nconst springRange = (from, to, strength) => pipe(\n  conditional(\n    v => v < from,\n    linearSpring(strength, from)\n  ),\n  conditional(\n    v => v > to,\n    linearSpring(strength, to)\n  )\n);\n\\`\\`\\`\n\nThis can be passed to our \\`pipe\\`:\n\n\\`\\`\\`javascript\npointerX(handleX.get())\n  .pipe(springRange(0, 200, 0.2))\n  .start(handleX)\n\\`\\`\\`\n\nTo create spring-restricted motion that feels like this:\n\n<CodePen id=\"jYqmEa\" height={200} />\n\nTry replacing \\`linearSpring\\` with \\`nonlinearSpring\\` and adjust the \\`strength\\` to see how that changes the behaviour of the handle.\n\n### Spring back\n\nYou'll notice that if you release the handle outside the slider's boundaries, it just sits still. This is at odds with the perceived spring that binds the handle to the slider.\n\nFor this, we can start a \\`spring\\` animation on the mouseup/touchend event.\n\nCurrently, we just call \\`() => handleX.stop()\\` which ungracefully stops any action driving \\`handleX\\`, which in this example is \\`pointerX\\`.\n\nLet's replace this reaction with:\n\n\\`\\`\\`javascript\n() => {\n  const x = handleX.get()\n\n  if (x < 0 || x > 250) {\n    // Start spring animation\n  } else {\n    handleX.stop();\n  }\n}\n\\`\\`\\`\n\nNow the function will only stop motion abruptly if the handle is **within** the slider's range.\n\nTo handle cases when the handle is **outside** the range, replace the commented line with this:\n\n\\`\\`\\`javascript\nspring({\n  from: x,\n  to: x < 0 ? 0 : 250,\n  velocity: handleX.getVelocity(),\n  stiffness: 900,\n  damping: 30\n}).start(handleX);\n\\`\\`\\`\n\n<CodePen id=\"xpVdLv\" height={200} />\n\nYou can play around with the settings of both the static spring and the \\`spring\\` animation until you find something that feels responsive, satisfying and in-keeping with your brand.\n\n## Conclusion\n\nWe can declaratively implement motion constraints using functional composition.\n\nClamping is the most basic approach, but static springs can yield more satisfying results when paired with user input.\n\n\\`pipe\\` and \\`conditional\\` allow you the freedom to devise and compose your own strategies for imposing motion constraints.\n\nA couple ideas for next steps:\n\n- Replace the \\`stop\\` call in our mouseup event with a \\`decay\\` animation that allows the user to throw the handle. It could include a little bump animation when it hits a slider limit.\n- Generate your own static springs using the \\`generateStaticSpring\\` transformer.\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"constrain-motion\"\n    section=\"learn\"\n    category=\"how-to\"\n    title=\"Constrain motion\"\n    description=\"How to constrain motion to within ranges using clamping and springs.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/learn/get-started.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Get started\n\nPopmotion is a functional, reactive JavaScript motion library.\n\nIt allows developers to create animations and interactions from **actions**.\n\nActions are streams of values that can be started and stopped, like tweens, physics and pointer input.\n\nActions are unopinionated, so those values can be used to create animations with CSS, SVG, React, Three.js... any API that accepts a number as an input.\n\nIn this simple introductory guide we're going to install Popmotion and use it to animate an element using the \\`tween\\` animation and DOM \\`styler\\`.\n\n## Installation\n\nYou can install Popmotion directly from npm:\n\n\\`\\`\\`bash\nnpm install popmotion --save\n\\`\\`\\`\n\nAlternatively, you can also **download pre-bundled files** or **fork CodePen playgrounds**. Full installation options are available on the [Install Popmotion](/learn/install) page.\n\n## Import\n\nIn Popmotion, everything can be imported from the main library:\n\n\\`\\`\\`javascript\nimport { tween } from 'popmotion';\n\\`\\`\\`\n\nOr, if you're only using a small subset of the library you can respect your user's bytes by importing everything individually:\n\n\\`\\`\\`javascript\nimport tween from 'popmotion/animations/tween';\n\\`\\`\\`\n\n## The \"Hello World\" tween\n\nA \\`tween\\` is a function that changes one number to another, over a set duration of time. If you're familiar with CSS transitions, that is also a form of tweening.\n\nBy default, a \\`tween\\` will change \\`0\\` to \\`1\\` over \\`300\\` milliseconds:\n\n\\`\\`\\`marksy\n<Example template=\"Counter\" id=\"a\" autostart={false}>{\\`\nconst counter = document.querySelector('#a .counter');\nconst updateCounter = (v) => counter.innerHTML = v;\n\ntween().start(updateCounter);\n\\`}</Example>\n\\`\\`\\`\n\n**All examples in the green-bordered boxes are editable**. Try editing the above example by writing\n\n\\`\\`\\`javascript\n{ to: 300, duration: 500 }\n\\`\\`\\`\n\nas the argument to the \\`tween\\` function. The counter will now count up to \\`300\\` over the course of half a second.\n\n## Animate!\n\nAs web developers, the DOM is our most common target for animations.\n\nSo, let's use the exact same animation from before to output to an element's \\`translateX\\` property.\n\nFor this, we can use the \\`styler\\` function:\n\n\\`\\`\\`javascript\nimport { tween, styler } from 'popmotion';\n\\`\\`\\`\n\n\\`styler\\` accepts a single \\`Element\\` and returns a get/set interface for HTML and SVG styles that's optimised for animation.\n\n\\`\\`\\`javascript\nconst ball = styler(document.querySelector('.ball'))\n\\`\\`\\`\n\nWhen \\`set\\` is called, it schedules a render [on the next frame](/api/framesync). All renders are batched to prevent layout thrashing.\n\n\\`set\\`, if called with just a property name, returns a setter function. So we can swap \\`updateCounter\\` from the previous example with \\`styler(element).set('x')\\` to animate the element:\n\n\\`\\`\\`marksy\n<Example template=\"Ball\" id=\"css\" autostart={false}>{\\`\nconst ball = document.querySelector('#css .ball');\n\ntween({ to: 300, duration: 500 })\n  .start(styler(ball).set('x'));\n\\`}</Example>\n\\`\\`\\`\n\nAnd that's it! Your first animation. \n\n## Multi-property animations\n\nAll animations included with Popmotion can animate:\n\n- Numbers\n- Colors\n- Objects of numbers and colors\n- Arrays of numbers and colors\n\nFor instance, by replacing \\`300\\` in the previous example with \\`{ x: 300, scale: 2 }\\` the action will animate and output \\`x\\` and \\`scale\\` values:\n\n\\`\\`\\`marksy\n<Example template=\"Ball\" id=\"object\" autostart={false}>{\\`\nconst ball = document.querySelector('#object .ball');\nconst ballStyler = styler(ball);\n\ntween({\n  from: { x: 0, scale: 1 },\n  to: { x: 300, scale: 2 },\n  ease: easing.easeInOut,\n  flip: Infinity,\n  duration: 1000\n}).start(ballStyler.set);\n\\`}</Example>\n\\`\\`\\`\n\n## Next\n\nThis tutorial has covered just the basics for the \\`tween\\` animation. You can find more details in the full [tween API docs](/api/tween).\n\nPopmotion uses a simple reactive model. Every animation, like \\`tween\\`, and every input is an **action**.\n\nAnd for every action, there is (naturally) a **reaction**.\n\nIn the next tutorial, we'll briefly look at [actions and reactions](/learn/action-reaction).\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"get-started\"\n    section=\"learn\"\n    category=\"basics\"\n    title=\"Get started\"\n    description=\"Introduction to Popmotion's tween animation.\"\n    published=\"\"\n    theme=\"pure\"\n    next=\"action-reaction\"\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/learn/input-smoothing.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Input smoothing\n\nYou can easily add input smoothing to pointer tracking using some light functional composition.\n\nDrag this ball to see pointer tracking without smoothing:\n\n\\`\\`\\`marksy\n<Example template=\"Ball\" id=\"a\" autostart={true}>{\\`\nconst ball = document.querySelector('#a .ball');\nconst ballStyler = styler(ball);\nconst ballXY = value({ x: 0, y: 0 }, ballStyler.set);\n\nlet pointerTracker;\n\nconst startTracking = () => {\n  pointerTracker = pointer(ballXY.get())\n    .start(ballXY);\n};\n\nconst stopTracking = () => {\n  if (pointerTracker) pointerTracker.stop();\n};\n\nlisten(ball, 'mousedown touchstart').start(startTracking);\nlisten(document, 'mouseup touchend').start(stopTracking);\n\\`}</Example>\n\\`\\`\\`\n\nAnd now with smoothing applied:\n\n\\`\\`\\`marksy\n<Example template=\"Ball\" id=\"b\" autostart={true}>{\\`\nconst ball = document.querySelector('#b .ball');\nconst ballStyler = styler(ball);\nconst ballXY = value({ x: 0, y: 0 }, ballStyler.set);\n\nconst { transformMap, smooth } = transform;\nlet pointerTracker;\n\nconst startTracking = () => {\n  pointerTracker = pointer(ballXY.get())\n    .pipe(transformMap({\n      x: smooth(200),\n      y: smooth(200)\n    }))\n    .start(ballXY);\n};\n\nconst stopTracking = () => {\n  if (pointerTracker) pointerTracker.stop();\n};\n\nlisten(ball, 'mousedown touchstart').start(startTracking);\nlisten(document, 'mouseup touchend').start(stopTracking);\n\\`}</Example>\n\\`\\`\\`\n\n## Add smoothing\n\nWe can use the \\`smooth\\` [transformer](/api/transformers#smooth) to apply smoothing to any numerical value.\n\n\\`smooth\\` works by passing a smoothing amount, in milliseconds. This is the duration over which movement will be averaged. So, high numbers equal greater smoothing.\n\n\\`\\`\\`javascript\nsmooth(200)\n\\`\\`\\`\n\n**Importantly**, a new instance of \\`smooth\\` must be created for each value we want to smooth. This is because the returned function refers to an internal average value. If we pass it multiple values from different sources, it can't work!\n\n### Multi-axis smoothing\n\nSo, our \\`pointer\\` might originally look like this:\n\n\\`\\`\\`javascript\npointer({ x: 0, y: 0 })\n  .start(({ x, y }) => /* unsmoothed output */)\n\\`\\`\\`\n\nTo apply smoothing on both \\`x\\` and \\`y\\`, we can use the \\`transformMap\\` transformer along with \\`smooth\\`:\n\n\\`\\`\\`javascript\nimport { pointer, transform } from 'popmotion';\nconst { transformMap, smooth } = transform;\n\npointer({ x: 0, y: 0 })\n  .pipe(transformMap({\n    x: smooth(200),\n    y: smooth(200)\n  }))\n  .start(({ x, y }) => /* smoothed! */)\n\\`\\`\\`\n\n### Single-axis smoothing\n\nIf we're just tracking a single axis, we don't even need \\`transformMap\\`:\n\n\\`\\`\\`javascript\npointer({ x: 0, y: 0 })\n  .pipe(\n    ({ x }) => x,\n    smooth(200)\n  ).start((x) => /* smoothed x axis */)\n\\`\\`\\`\n\n## Conclusion\n\nBy using \\`smooth\\`, we can apply smoothing to not just \\`pointer\\` output, but that of any action.\n\nMore examples of \\`pipe\\` and functional composition can be found in the [value pipelines](/api/value-pipelines) tutorial.\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"input-smoothing\"\n    section=\"learn\"\n    category=\"how-to\"\n    title=\"Input smoothing\"\n    description=\"How to apply input smoothing to mouse and touch input\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/learn/input-tracking.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Pointer tracking\n\nPointer tracking is an integral part of user interfaces.\n\nDrag & drop, scrolling galleries, and measuring touch scroll speed are some obvious use cases.\n\nIn this quick tutorial, we'll first see how to convert DOM events into streams of values with the \\`listen\\` action.\n\nThen, we'll look at how to track mouse and touch movement with the \\`pointer\\` action and then use that pointer's movement to drag a DOM element.\n\n## The \\`listen\\` action\n\nPopmotion provides the [\\`listen\\` action](/api/listen) to add event listeners to the DOM.\n\n\\`\\`\\`javascript\nimport { listen } from 'popmotion';\n\\`\\`\\`\n\nIt accepts event names as a space-delimited string, meaning you can use a single \\`listen\\` call to listen to multiple events:\n\n\\`\\`\\`javascript\nlisten(document, 'mousedown touchstart')\n  .start((e) => console.log(e));\n\\`\\`\\`\n\nJust like the good-old days of jQuery!\n\nAs \\`listen\\` is an [action](/api/action), it offers all the same chainable methods.\n\nFor example, here's how you could make a \\`touchmove\\` listener that only fires when there's more than two \\`touches\\`:\n\n\\`\\`\\`javascript\nlisten(document, 'touchmove')\n  .filter(({ touches }) => touches.length >= 2)\n  .start((e) => /* This event has more than 2 touches! */);\n\\`\\`\\`\n\n## The \\`pointer\\` action\n\nThe \\`pointer\\` action provides a generic interface for interacting with **single point** mouse and touch inputs (for multitouch, Popmotion offers the [\\`multitouch\\` action](/api/multitouch)).\n\n\\`\\`\\`javascript\nimport { pointer } from 'popmotion';\n\\`\\`\\`\n\nBy default, \\`pointer\\` outputs the pointer's \\`clientX\\` and \\`clientY\\` properties as \\`x\\` and \\`y\\`.\n\n\\`\\`\\`javascript\nlet pointerTracker;\n\nlisten(document, 'mousedown touchstart').start(() => {\n  pointerTracker = pointer()\n    .start(({ x, y }) => console.log(x, y));\n});\n\nlisten(document, 'mouseup touchend').start(() => {\n  if (pointerTracker) pointerTracker.stop();\n});\n\\`\\`\\`\n\n## Dragging\n\nThe majority of time we actually want to use this movement data to drag or scroll.\n\nLet's use the \\`styler\\` function again to create a DOM element interface to provide the positional data to.\n\nLook at \\`startTracking\\` function and try to drag the ball:\n\n\\`\\`\\`marksy\n<Example template=\"Ball\" id=\"a\" autostart={true}>{\\`\nconst ball = document.querySelector('#a .ball');\nconst ballStyler = styler(ball);\nlet pointerTracker;\n\nconst startTracking = () => {\n  pointerTracker = pointer()\n    .start(ballStyler.set);\n};\n\nconst stopTracking = () => {\n  if (pointerTracker) pointerTracker.stop();\n};\n\nlisten(ball, 'mousedown touchstart').start(startTracking);\nlisten(document, 'mouseup touchend').start(stopTracking);\n\\`}</Example>\n\\`\\`\\`\n\n**Oh dear.** The ball moves, but it jumps to a weird location (maybe one that's off-screen entirely!)\n\nThe reason for this is simple. \\`pointer\\` is outputting the \\`{ x, y }\\` position of the pointer **relative to the viewport**.\n\nThe **ball's** \\`{ x, y }\\` transform begins at \\`0, 0\\`. So if we apply the pointer's absolute position directly to the ball, it won't move where we want it to.\n\nInstead, we want to apply the **movement** of the \\`pointer\\` to the ball's initial position.\n\nTo do this, we can provide \\`pointer\\` with an initial \\`{ x, y }\\` point, and it will output the movement of its \\`{ x, y }\\` **relative to that point**:\n\n\\`\\`\\`javascript\npointer({ x: 0, y: 0 })\n\\`\\`\\`\n\nDragging becomes trivial:\n\n\\`\\`\\`marksy\n<Example template=\"Ball\" id=\"b\" autostart={true}>{\\`\nconst ball = document.querySelector('#b .ball');\nconst ballStyler = styler(ball);\nlet pointerTracker;\n\nconst startTracking = () => {\n  pointerTracker = pointer({\n    x: ballStyler.get('x'),\n    y: ballStyler.get('y')\n  }).start(ballStyler.set);\n};\n\nconst stopTracking = () => {\n  if (pointerTracker) pointerTracker.stop();\n};\n\nlisten(ball, 'mousedown touchstart').start(startTracking);\nlisten(document, 'mouseup touchend').start(stopTracking);\n\\`}</Example>\n\\`\\`\\`\n\n## Single-axis dragging\n\nLimiting dragging to a single axis is a matter of using just the \\`x\\` or \\`y\\` output from \\`pointer\\`.\n\nWe could do this via the reaction:\n\n\\`\\`\\`javascript\npointer().start(({ x }) => ballStyler.set('x', x));\n\\`\\`\\`\n\nBut the more reusable way is to **compose a new action** using \\`pointer\\`'s \\`pipe\\` method. We can provide it a simple picker function that selects \\`x\\` from \\`pointer\\`'s output and returns it:\n\n\\`\\`\\`javascript\nconst xPointer = (initialX) => pointer({ x: initialX })\n  .pipe(({ x }) => x);\n\\`\\`\\`\n\nNow we can use our newly composed \\`xPointer\\` like so:\n\n\\`\\`\\`javascript\nxPointer(ballStyler.get('x'))\n  .start(ballStyler.set('x'));\n\\`\\`\\`\n\n\\`\\`\\`marksy\n<Example template=\"Ball\" id=\"c\" autostart={true}>{\\`\nconst ball = document.querySelector('#c .ball');\nconst ballStyler = styler(ball);\nconst xPointer = (initialX) => pointer({ x: initialX })\n  .pipe(({ x }) => x);\n\nlet pointerTracker;\n\nconst startTracking = () => {\n  pointerTracker = xPointer(ballStyler.get('x'))\n    .start(ballStyler.set('x'));\n};\n\nconst stopTracking = () => {\n  if (pointerTracker) pointerTracker.stop();\n};\n\nlisten(ball, 'mousedown touchstart').start(startTracking);\nlisten(document, 'mouseup touchend').start(stopTracking);\n\\`}</Example>\n\\`\\`\\`\n\n## Conclusion\n\n\\`listen\\` can convert DOM events into reactive streams of values. Useful for leveraging \\`pipe\\` and other chainable methods, and composing \\`listen\\` with other actions.\n\n\\`pointer\\` can output values either absolutely, or, if we provide initial coordinates, by applying its delta relatively.\n\nFinally, we can compose new actions to produce reusable bits of code with new behaviour, like single-axis dragging.\n\n## Next\n\nNow that we've got dragging working, in the [next tutorial](/learn/velocity-and-physics) we will learn how to inspect the \\`velocity\\` of the dragged object and apply that to \\`decay\\`, \\`physics\\` and \\`spring\\` actions to create natural-feeling interactions.\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"input-tracking\"\n    section=\"learn\"\n    category=\"basics\"\n    title=\"Pointer tracking\"\n    description=\"Learn to track pointer movement and use that to drag DOM elements.\"\n    published=\"\"\n    theme=\"pure\"\n    next=\"velocity-and-physics\"\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/learn/install.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Install Popmotion\n\n## Package managers\n\n### npm\n\n\\`\\`\\`bash\nnpm install popmotion --save\n\\`\\`\\`\n\n### yarn\n\n\\`\\`\\`bash\nyarn add popmotion\n\\`\\`\\`\n\n## File include\n\n**Note:** The Popmotion documentation uses the \\`import\\` syntax for importing individual modules.\n\n**If you use one of the following installation methods, Popmotion will be available on the global \\`popmotion\\` variable.**\n\nSo, when you see in the docs \\`import { tween } from 'popmotion'\\`, you will use \\`const { tween } = popmotion\\` instead.\n\n### Download\n\nYou can download the latest version of Popmotion at https://unpkg.com/popmotion/dist/popmotion.global.min.js\n\n### \\`script\\` include:\n\nOr include it directly in your HTML with this \\`script\\` tag:\n\n\\`\\`\\`html\n<script src=\"https://unpkg.com/popmotion/dist/popmotion.global.min.js\"></script>\n\\`\\`\\`\n\n### CodePen\n\nYou can fork the [Popmotion playground on CodePen](https://codepen.io/popmotion/pen/zPjXWa?editors=0010), which is set up with the latest version of Popmotion.\n\nYou an also add Popmotion to any existing CodePen project by clicking on Settings > JavaScript and then pasting \\`https://unpkg.com/popmotion/dist/popmotion.global.min.js\\` into the \"Add External JavaScript\" field.\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"install\"\n    section=\"learn\"\n    category=\"basics\"\n    title=\"Install Popmotion\"\n    description=\"Overview of Popmotion's different installation options.\"\n    published=\"\"\n    theme=\"pure\"\n    next=\"get-started\"\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/learn/morph-svg.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Morph SVG\n\nPopmotion animations can be used to morph between any two SVG \\`path\\` shapes.\n\nSVG-morphing libraries [Flubber](https://github.com/veltman/flubber) and [Polymorph](https://github.com/notoriousb1t/polymorph) both functions that accept a value between 0 and 1 to blend between two shapes. This works great with Popmotion's functional API, and animating the morph is as simple as this:\n\n\\`\\`\\`javascript\ntween()\n  .pipe(morph)\n  .start(styler(pathElement).set('d'));\n\\`\\`\\`\n\nIn this quick tutorial we'll define this \\`morph\\` function with both Flubber and Polymorph and animate it with a \\`tween\\`.\n\n## Set up\n\nFirst, we need an SVG with a \\`path\\` element to render into.\n\n\\`\\`\\`html\n<svg viewBox=\"0 0 400 400\">\n  <path id=\"target\" />\n</svg>\n\\`\\`\\`\n\nAs we're going to animate the \\`path\\`'s verbosely-named \\`d\\` attribute, which defines the shape of the path, we can use Popmotion's [\\`styler\\` function](/api/styler) to create an optimised setter:\n\n\\`\\`\\`javascript\nconst path = document.getElementById('#target');\nconst setPathAttr = styler(path).set('d');\n\\`\\`\\`\n\nNow we simply need a path definition string to provide to \\`setPathAttr\\`.\n\n## Flubber\n\n<CodePen id=\"yProEp\" />\n\n[Flubber](https://github.com/veltman/flubber) is a fully-featured morphing library that yields very accurate and pleasing results. The drawback being its filesize: A whopping 53kb!\n\nOnce you've installed and imported Flubber according to the docs, you can make the \\`morph\\` function using \\`flubber.interpolate\\`.\n\nThis function accepts two strings, one of each path you want to morph between:\n\n\\`\\`\\`javascript\nconst star = \"M103.04 162.52L39.36 196l12.16-70.9L0 74.86 71.2 64.5 103.04 0l31.85 64.52 71.2 10.35-51.57 50.22L166.7 196z\";\nconst circle = \"M86,171.5 C38.7796539,171.5 0.5,133.220346 0.5,86 C0.5,38.7796539 38.7796539,0.5 86,0.5 C133.220346,0.5 171.5,38.7796539 171.5,86 C171.5,133.220346 133.220346,171.5 86,171.5 Z\";\n\nconst morph = flubber.interpolate(circle, star);\n\\`\\`\\`\n\nBy default, the blending of the two shapes is pretty rough. We can pass \\`interpolate\\` a third options argument \\`{ maxSegmentLength: 2 }\\` to output more accurate shapes, though this might have performance impacts with more complex blends.\n\nThe generated \\`morph\\` function accepts a number between \\`0\\` and \\`1\\` and outputs a path definition string generated from a blend of \\`circle\\` and \\`star\\`.\n\nSo to animate our target \\`path\\`, we simply need to write an animation that outputs a number between \\`0\\` and \\`1\\` and provide \\`morph\\` to its \\`pipe\\` method so its output is the new path:\n\n\\`\\`\\`javascript\ntween()\n  .pipe(morph)\n  .start(setPathAttr);\n\\`\\`\\`\n\n## Polymorph\n\n<CodePen id=\"dZLRLq\" />\n\n[Polymorph](https://github.com/notoriousb1t/polymorph) is a much lighter library clocking in at just 6kb! For complex shapes it works just as well as Flubber, though results may vary for simpler shapes. \n\nSetup works a little differently as it takes \\`path\\` definitions from existing elements, so we'll need to add those:\n\n\\`\\`\\`html\n<svg>\n  <path id=\"Oval\" d=\"M86,171.5 C38.7796539,171.5 0.5,133.220346 0.5,86 C0.5,38.7796539 38.7796539,0.5 86,0.5 C133.220346,0.5 171.5,38.7796539 171.5,86 C171.5,133.220346 133.220346,171.5 86,171.5 Z\" />\n  <path id=\"Star\" d=\"M103.04 162.52L39.36 196l12.16-70.9L0 74.86 71.2 64.5 103.04 0l31.85 64.52 71.2 10.35-51.57 50.22L166.7 196z\" />\n</svg>\n\\`\\`\\`\n\nWe simply provide the element ids to \\`polymorph.interpolate\\`, along with an optional \\`precision\\` setting:\n\n\\`\\`\\`javascript\nconst morph = polymorph.interpolate(['#Star', '#Oval'], { precision: 4 });\n\ntween()\n  .pipe(morph)\n  .start(setPathAttr);\n\\`\\`\\`\n\n## Next steps\n\nPopmotion, Flubber and Polymorph's functional approach gives you the freedom to combine whichever libraries suit your project.\n\nIn this article, we've shown how simple it is to animate between shapes using \\`tween\\`. You could play around with other animations like \\`pointer\\`, which would make the blending scrubbable:\n\n\\`\\`\\`javascript\npointer()\n  .pipe(\n    ({ x }) => x,\n    interpolate([0, window.innerWidth], [0, 1])\n  )\n  .start()\n\\`\\`\\`\n\nOne caveat, however, is neither library accepts numbers outside of \\`0\\` and \\`1\\`, which entails the following:\n\n- \\`spring\\` needs to be overdamped by choosing a \\`damping\\` property high enough to prevent overshoot.\n- Easing functions that generate overshoot, like \\`backOut\\`, will lead to stunted animations.\n\nYou can of course \\`pipe\\` animations through the \\`clamp\\` [transformer](/api/transformers) for safety, but ideally you'll want to create animations that don't exceed these limits.\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"morph-svg\"\n    section=\"learn\"\n    category=\"how-to\"\n    title=\"Morph SVG\"\n    description=\"How to animate between two SVG shapes with Popmotion.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/learn/rounded-values.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Rounded values\n\nPopmotion's emphasis on functional composition means actions don't offer explicit support via properties like \\`rounded: true\\`.\n\nInstead, we can round the output of any [action](/api/action) by providing JavaScript's native \\`Math.round\\` to \\`pipe\\`. For instance:\n\n## Round a single value\n\nIf we have a \\`tween\\` that outputs a single value, we can round it like this:\n\n\\`\\`\\`javascript\ntween({ to: 1000 }).pipe(Math.round)\n\\`\\`\\`\n\n\\`\\`\\`marksy\n<Example template=\"Counter\" id=\"a\" autostart={false}>{\\`\nconst counter = document.querySelector('#a .counter');\nconst updateCounter = (v) => counter.innerHTML = v;\n\ntween({ to: 1000, duration: 2000 })\n  .pipe(Math.round)\n  .start(updateCounter);\n\\`}</Example>\n\\`\\`\\`\n\nEvery animation is an action, so this applies to animations like \\`physics\\` too:\n\n\\`\\`\\`javascript\nphysics({ velocity: 100 }).pipe(Math.round)\n\\`\\`\\`\n\n\\`\\`\\`marksy\n<Example template=\"Counter\" id=\"b\" autostart={false}>{\\`\nconst counter = document.querySelector('#b .counter');\nconst updateCounter = (v) => counter.innerHTML = v;\n\nphysics({ velocity: 100 })\n  .pipe(Math.round)\n  .start(updateCounter);\n\\`}</Example>\n\\`\\`\\`\n\n## Round a complex value\n\nIf we're animating an object, we can apply rounding to specific values using the \\`transformMap\\` [transformer](/api/transformers#transformmap):\n\n\\`\\`\\`javascript\nimport { tween, transform } from 'popmotion';\nconst { transformMap } = transform;\n\ntween({\n  to: { x: 100, y: 100 }\n}).pipe(transformMap({\n  x: Math.round\n}));\n\\`\\`\\`\n\nMore examples of \\`pipe\\` and functional composition can be found in the [value pipelines](/api/value-pipelines) tutorial.\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"rounded-values\"\n    section=\"learn\"\n    category=\"how-to\"\n    title=\"Rounded values\"\n    description=\"How to output rounded values from any action\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/learn/spring-loaded-characters-remaining.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Spring-loaded \"characters remaining\" counter\n\nForms are, by nature, dreary. From a user's perspective, there's nothing fun about them: Non-zero friction, mental effort, the cold exchange of info for goods.\n\nIt doesn't have to be this way! By adding thoughtful little touches, we can soften the negative form experience and maybe even make something a little bit delightful.\n\nIn this tutorial we're going to take a traditionally mundane part of form, the remaining character counter, and increase its functionality by adding a little playfulness.\n\nWe're going to attach a spring that fires on every keypress that goes over the character count limit, drawing attention to the counter. We're also going to slowly change the counter color to red as we approach the limit.\n\nHave a play by typing in this box:\n\n<CodePen id=\"JOeemQ\" />\n\nTo begin, you can use [this CodePen template](https://codepen.io/popmotion/pen/XzyypY?editors=0010) to follow along.\n\n## The counter\n\nOur first job is to get the counter to actually count down as a user enters characters.\n\nThe input field's \\`maxlength\\` is set to \\`10\\`. We can read this with JavaScript:\n\n\\`\\`\\`javascript\nconst charLimit = parseInt(input.getAttribute('maxlength'));\n\\`\\`\\`\n\nNow, let's create a function that takes a string and updates the character counter with the remaining number of characters, which will be calculated by measuring the string and subtracting that from the \\`charLimit\\`:\n\n\\`\\`\\`javascript\nfunction updateRemainingCharsCounter(val) {\n  counter.innerHTML = charLimit - val.length;\n}\n\\`\\`\\`\n\nWe can test that this function works by, on the following line, writing:\n\n\\`\\`\\`javascript\nupdateRemainingCharsCounter('test');\n\\`\\`\\`\n\n\\`'test'\\` is four characters long, so our counter displays \\`6\\`.\n\nWe want this function to fire on every \\`keyup\\` event, as this event carries the \\`input\\` field's latest value.\n\nWe're going to use the [\\`listen\\` action](/api/listen) to bind the event. \\`listen\\` converts DOM events into reactive streams. As an action, we can use \\`pipe\\` to pick the latest value out of the event before passing it on to \\`updateRemainingCharsCounter\\`:\n\n\\`\\`\\`javascript\nlisten(input, 'keyup')\n  .pipe(e => e.target.value)\n  .start(updateRemainingCharsCounter);\n\\`\\`\\`\n\nNow when you type, the character counter updates!\n\nWe have a functional counter, but not a delightful one. Let's attach a \\`spring\\`.\n\n## The spring\n\nWe're going to use the spring to increase the counter's \\`scale\\` property.\n\nThis isn't just going to look playful. By rapidly enlarging the counter, it'll draw the user's attention. You could use a little shake, or another effect. It's the movement itself that will distract the user to make sure they understand that there's no space for new characters.\n\nUnlike a simple \\`tween\\`, spring physics can take into account a pre-existing velocity. This will make the animation interactive and playful: I haven't seen many people resist hammering away at the keyboard once they realise rapid keypresses builds momentum!\n\n### Rendering the counter's \\`scale\\` prop\n\nFirst, we need to import the [\\`value\\`](/api/value) and [\\`styler\\`](/api/styler) functions.\n\n\\`value\\` will help us track and measure the velocity of \\`scale\\`, and \\`styler\\` will enable us to render it performantly.\n\n\\`\\`\\`javascript\nconst { listen, value, styler } = window.popmotion;\n\\`\\`\\`\n\nWe make our styler by simply passing the \\`counter\\`'s DOM node to \\`styler\\`:\n\n\\`\\`\\`javascript\nconst counterStyler = styler(counter);\n\\`\\`\\`\n\nAnd we can initialise the \\`counterScale\\` value by passing it an initial value (\\`1\\`), and create a setter function with \\`counterStyler.set\\`: \n\n\\`\\`\\`javascript\nconst counterScale = value(1, counterStyler.set('scale'));\n\\`\\`\\`\n\nNow, whenever \\`counterScale\\` updates, the \\`counter\\` DOM node will be updated too.\n\n### Listening to \\`keydown\\`\n\nWe also need to listen for a new event, \\`keydown\\`.\n\nThis event the moment the user presses down on the key, which is the moment they're imparting their physical energy into the UI.\n\nIt feels very responsive - try putting the following code under a \\`keyup\\` event instead and you'll immediately notice how disconnected the animation feels from your physical actions.\n\nWe'll use \\`listen\\` again, this time chained with a different method, \\`filter\\`. \n\n\\`filter\\`, as the name implies, filters out values that don't meet the provided criteria. In this case, we want to create an event listener that only fires when the number of entered characters is the same as the \\`chatLimit\\`:\n\n\\`\\`\\`javascript\nlisten(input, 'keydown')\n  .filter(e => e.target.value.length === charLimit)\n  .start(fireSpring);\n\\`\\`\\`\n\n### The \\`spring\\` function\n\nNow, we're ready to add our \\`spring\\`.\n\n\\`\\`\\`javascript\nconst { listen, value, styler, spring } = window.popmotion;\n\\`\\`\\`\n\nBefore this event listener, create a new function called \\`fireSpring\\` that'll start a new \\`spring\\` animation:\n\n\\`\\`\\`javascript\nfunction fireSpring() {\n  spring({\n    // Start the animation from the current scale:\n    from: counterScale.get()\n\n    // We want the spring to rest on 1\n    to: 1,\n\n    // We set the initial velocity to whichever the smallest is:\n    // a) counterScale's current velocity, or\n    // b) an arbitrary minimum. You can experiment.\n    velocity: Math.max(counterScale.getVelocity(), 100),\n\n    // This ratio of stiffness to damping gives a nice, tight spring. Experiment!\n    stiffness: 700,\n    damping: 80\n  }).start(counterScale);\n}\n\\`\\`\\`\n\nBy tweaking the properties of \\`spring\\`, you can make springs with wildly different feelings. Some can be playful, some can be terse. Try to find one appropriate for your brand or website.\n\nThere's one final modification to make. Currently, the spring says \"Hey! You've reached the character count!\" in a loud and abrupt way. By slowly changing the color of the counter we can also quietly inform the user that they're **approaching** the limit.\n\n## The warning color\n\nWe're going to compose a very simple [value pipeline](/learn/value-pipelines) function that will convert our remaining character count into a color.\n\nWe can use three of Popmotion's [transformers](/api/transformers) to achieve this: \\`pipe\\`, \\`blendColor\\`, and \\`interpolate\\`.\n\nWe'll use \\`pipe\\` to make a new function. This new function will accept a character count and map that to a value between \\`0\\` and \\`1\\`. That new number is then used to blend between the \\`counter\\`'s text color and red:\n\nImport:\n\n\\`\\`\\`javascript\nconst { listen, value, styler, spring, transform } = window.popmotion;\nconst { blendColor, interpolate, pipe } = transform;\n\\`\\`\\`\n\nAnd then, after we define \\`charLimit\\` and \\`counterStyler\\`, create our new function:\n\n\\`\\`\\`javascript\nconst convertCountToColor = pipe(\n  // The input range starts at half the charLimit and ends at the\n  // charLimit itself. This means the color will start changing, in this\n  // instance, when the counter hits 5\n  interpolate([charLimit * 0.5, charLimit], [0, 1]),\n  blendColor(counterStyler.get('color'), '#f00')\n);\n\\`\\`\\`\n\nNow we just need to amend our \\`updateRemainingCharsCounter\\` function to set \\`counterStyler\\`'s \\`'color'\\` property with the output of this function:\n\n\\`\\`\\`javascript\nfunction updateRemainingCharsCounter(val) {\n  // Measure char count\n  const charCount = val.length;\n\n  // Set remaining chars\n  counter.innerHTML = charLimit - charCount;\n\n  // Set counter color\n  counterStyler.set('color', convertCharCountToColor(charCount));\n}\n\\`\\`\\`\n\nNow when you type, the counter will begin to change color as your reach the character limit.\n\n## Further optimisations\n\nThat's all for this tutorial, but there's plenty of ways in which we can go on to improve this form field counter:\n\n- Visual \\`focus\\` state - maybe only show the character remaining count while the input has focus.\n- Allow extra characters to be entered, and allow the \"characters remaining\" counter to run into the negatives.\n- Not firing the spring on backspace.\n- Only show the counter if JavaScript has loaded.\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"spring-loaded-characters-remaining\"\n    section=\"learn\"\n    category=\"projects\"\n    title=\"Spring-loaded 'characters remaining' counter\"\n    description=\"Inject some fun into your text fields with a spring-loaded characters remaining counter.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/learn/value-pipelines.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Composable value pipelines\n\nPopmotion provides simple utility functions that can take a value and return it transformed. These are, unsurprisingly, called **[transformers](/api/transformers)**.\n\n\\`\\`\\`javascript\nimport { transform } from 'popmotion';\n// Or save your user's bytes!\nimport * as transform from 'popmotion/transformers';\n\\`\\`\\`\n\nThese functions can perform a wide range of tasks. Something as simple as appending a unit:\n\n\\`\\`\\`javascript\nconst { appendUnit } = transform;\nconst px = appendUnit('px');\npx(5); // '5px'\n\\`\\`\\`\n\nMake an infinite looping sequence:\n\n\\`\\`\\`javascript\nwrap(0, 100)(150); // 50\n\\`\\`\\`\n\nOr converting a value from one range to another:\n\n\\`\\`\\`javascript\ninterpolate([0,1], [-500, 500])(0.5); // 0\n\\`\\`\\`\n\n## Curry\n\nAs you can see, many of these transformers are curried. So we can make a function:\n\n\\`\\`\\`javascript\nconst restrictNormalised = clamp(0, 1);\n\\`\\`\\`\n\nAnd then reuse it elsewhere:\n\n\\`\\`\\`javascript\nrestrictNormalised(5); // 1\n\\`\\`\\`\n\n## Compose\n\nBecause these functions are very simple and all carry the same signature, we can compose them. Popmotion provides a special transformer to do just that.\n\n\\`\\`\\`javascript\nconst { pipe } = transform;\n\\`\\`\\`\n\n\\`pipe\\` is named as such because it takes a list of functions and returns a new function that will run these functions from **left to right**. Essentially, creating a value pipeline.\n\nAs our functions are descriptively named, and as many of them are curried, our pipelines become very easy to read. They become less imperative, and more declarative.\n\nFor instance, let's compose a function that will always return a valid RGB value. RGB values are simply integers between \\`0\\` and \\`255\\`.\n\n\\`\\`\\`javascript\nconst rgbUnit = pipe(\n  clamp(0, 255),\n  Math.round\n);\n\\`\\`\\`\n\nWhat's cool about this example is that it shows that **any** function that 1) takes a number and 2) returns a number, can be composed. \\`Math.round\\` does exactly that, so we can compose it.\n\nYou don't have to write this function yourself, because that exact code is already included as a Popmotion transformer, and used in the \\`rgba\\` [value type](/api/value-types).\n\nThe \\`rgba\\` transformer is **itself** composed. Here's the exact code:\n\n\\`\\`\\`javascript\nconst rgba = pipe(\n  transformMap({\n    red: rgbUnit,\n    green: rgbUnit,\n    blue: rgbUnit,\n    alpha\n  }),\n  rgbaTemplate\n);\n\\`\\`\\`\n\nThis is an example of composing functions **which were themselves composed**. This is a very clear way of expressing and reusing our logic.\n\n## Applying transformers to animations\n\nEvery Popmotion [action](/api/action) and [reaction](/api/reaction) has a native \\`pipe\\` function.\n\nProviding a list of functions to \\`pipe\\` will return a new instance of the action or reaction, and whenever its \\`update\\` function is called, the value will be passed through these functions before being emitted.\n\nConsider this tween:\n\n\\`\\`\\`javascript\ntween({ from: 0, to: 255 });\n\\`\\`\\`\n\nWe can use our \\`rgbUnit\\` transformer from before to ensure that whenever this tween is called, it **always** returns a valid RGB unit:\n\n\\`\\`\\`javascript\ntween({ from: 0, to: 255 })\n  .pipe(rgbUnit)\n  .start(console.log);\n\\`\\`\\`\n\nThis is a versatile approach to adding functionality to any animation. For instance, many animation libraries offer an option to create stepped tweens, but with this kind of composition we can easily bring that same functionality to \\`physics\\` (or any other animation).\n\nHere, we can easily create something that spins at a constant velocity, outputting an angle value that snaps to \\`45\\` degree intervals:\n\n\\`\\`\\`javascript\nphysics({ velocity: 100 })\n  .pipe(\n    snap(45),\n    appendUnit('deg')\n  );\n\\`\\`\\`\n\nEtc.\n\n## Conclusion\n\nThese pure, simple functions are easily composed and reused. They can be used on their own, or with any action (not just tweens), making them extremely versatile.\n\nWe believe this functional approach gives developers the greatest flexibility and predictability.\n\nWe've covered just some of the many transformers here, but more are documented in our [API docs](/api/transformers). As they're pure functions, not specific to Popmotion, you can easily have fun creating your own.\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"value-pipelines\"\n    section=\"learn\"\n    category=\"advanced\"\n    title=\"Composable value pipelines\"\n    description=\"Use `pipe` to compose reusable value pipelines\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/pure/learn/velocity-and-physics.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/components';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video\n  }\n});\n\nconst content = convertMarkdown(`\n# Physics and velocity\n\nA core feature of Popmotion is the ability for some animations ([decay](/api/decay), [spring](/api/spring) and [physics](/api/physics)) to take a \\`velocity\\` parameter.\n\n\\`velocity\\` changes each of these animations in a way that feels natural and visceral.\n\nBy passing the velocity of an existing animation to another, we can create natural-feeling transitions. And if that existing animation is \\`pointer\\`, it allows the user to directly affect animations with their own force leading to natural and playful interactions. \n\n## Inspect velocity\n\nBut how do we get \\`velocity\\`?\n\nPopmotion provides a special type of reaction called \\`value\\`.\n\n\\`\\`\\`javascript\nimport { value } from 'popmotion';\n\\`\\`\\`\n\n\\`value\\` sits between your action and another reaction (for instance a style setter), and can be queried with \\`get\\` and \\`getVelocity\\`:\n\n\\`\\`\\`javascript\nconst myValue = value(0, console.log);\n\ntween().start(myValue);\n\nsetTimeout(() => myValue.getVelocity(), 100)\n\\`\\`\\`\n\nThe returned \\`velocity\\` is measured in **units per second**. Why? Although 60fps is the current common framerate, VR devices support 90+ fps and the iPad Pro delivers a silky 120 frames per second!\n\nTo future-proof our code, we decouple velocity from the device framerate, otherwise our animations would run at 1.5x or even 2x the speed on these faster displays.\n\n## Using \\`value\\`\n\n\\`value\\` is provided two arguments: A value, and a function to call when this value updates:\n\n\\`\\`\\`javascript\nconst foo = value(0, console.log);\n\\`\\`\\`\n\nAs \\`value\\` is a reaction, it has an \\`update\\` method. We can call it to update the value:\n\n\\`\\`\\`javascript\nfoo.update(5);\n\\`\\`\\`\n\nUsually though, we provide the \\`value\\` directly to an action:\n\n\\`\\`\\`javascript\ntween({ to: 5 }).start(foo);\n\\`\\`\\`\n\nLike our animations, \\`value\\` can accept objects and arrays:\n\n\\`\\`\\`javascript\nconst xy = value({ x: 0, y: 0 }, console.log);\nconst foo = tween({\n  to: { x: 100, y: 200 }\n}).start(xy);\n\nsetTimeout(() => xy.getVelocity(), 100); // Returns as object\n\\`\\`\\`\n\nNow we know enough about \\`value\\` to get the velocity of our user's pointer.\n\n## Get \\`pointer\\` velocity\n\nUsing the example from the [previous tutorial](/learn/input-tracking), let's first make a \\`value\\` that updates \\`ballStyler\\`'s \\`x\\` and \\`y\\` properties:\n\n\\`\\`\\`javascript\nconst ballXY = value({ x: 0, y: 0 }, ballStyler.set);\n\\`\\`\\`\n\nNow we can replace our \\`startTracking\\` function with this:\n\n\\`\\`\\`javascript\nconst startTracking = () => {\n  pointer(ballXY.get()).start(ballXY);\n};\n\\`\\`\\`\n\nAs an added benefit of using \\`value\\`, a \\`value\\` **can't be subscribed to more than one action at a time**.\n\nThis means that we can stop using \\`pointerTracker\\` to maintain a reference to our active \\`pointer\\`.\n\nInstead, we can either use \\`ballXY.stop()\\`, which will stop the action it's currently subscribed to. Or, we simply provide it to a different action, which is what we'll do in the following examples.\n\nFor now, amend \\`stopTracking\\` so it queries \\`ballXY\\`'s current velocity:\n\n\\`\\`\\`javascript\nconst stopTracking = () => {\n  const velocity = ballXY.getVelocity();\n};\n\\`\\`\\`\n\n## Using \\`velocity\\`\n\nThree Popmotion animations accept a \\`velocity\\` property: \\`decay\\`, \\`physics\\` and \\`spring\\`.\n\nLet's modify \\`stopTracking\\` three times, once for each, to see what they each do with \\`velocity\\`.\n\n### \\`decay\\`\n\n[\\`decay\\`](/api/decay) exponentially decreases a velocity over time. It's a form of the algorithm used in smartphone momentum scrolling, making it a natural-feeling way of slowing something down.\n\nBased on the initial properties and \\`velocity\\`, it'll automatically calculate a \\`target\\` to animate to.\n\nUsing it is as easy as passing our newly-calculated \\`velocity\\` to \\`decay\\`:\n\n\\`\\`\\`javascript\ndecay({ velocity }).start(ballXY);\n\\`\\`\\`\n\n\\`\\`\\`marksy\n<Example template=\"Ball\" id=\"a\" autostart={true}>{\\`\nconst ball = document.querySelector('#a .ball');\nconst ballStyler = styler(ball);\nconst ballXY = value({ x: 0, y: 0 }, ballStyler.set);\n\nfunction startTracking() {\n  pointer(ballXY.get())\n    .start(ballXY);\n}\n\nfunction stopTracking() {\n  decay({\n    from: ballXY.get(),\n    velocity: ballXY.getVelocity()\n  }).start(ballXY);\n}\n\nlisten(ball, 'mousedown touchstart').start(startTracking);\nlisten(document, 'mouseup touchend').start(stopTracking);\n\\`}</Example>\n\\`\\`\\`\n\n\\`decay\\` also accepts a \\`modifyTarget\\` function, which is provided the calculated target and returns a new one.\n\nThis can be used, for instance, to snap the target to a grid:\n\n\\`\\`\\`javascript\ndecay({\n  from: ballX.get(),\n  velocity,\n  modifyTarget: (target) => Math.ceil(target / 100) * 100\n})\n\\`\\`\\`\n\n### \\`spring\\`\n\n[\\`spring\\`](/api/spring) is a spring simulation using \\`mass\\`, \\`velocity\\`, \\`stiffness\\` and \\`damping\\`. It can be used to simulate a wide variety of spring-feels.\n\nSprings are great for interaction designers because they're expressive. For instance, you could design a spring that has a \\`stiffness\\` and \\`damping\\` property, but the \\`mass\\` property is based on the relative size of the element moving.\n\n\\`spring\\` has defaults for all properties but you'll likely want to adjust at least \\`stiffness\\` and \\`damping\\`:\n\n\\`\\`\\`javascript\nspring({\n  from: ballXY.get(),\n  velocity,\n  stiffness: 300,\n  damping: 10\n}).start(ballXY);\n\\`\\`\\`\n\n\\`\\`\\`marksy\n<Example template=\"Ball\" id=\"b\" autostart={true}>{\\`\nconst ball = document.querySelector('#b .ball');\nconst ballStyler = styler(ball);\nconst ballXY = value({ x: 0, y: 0 }, ballStyler.set);\n\nfunction startTracking() {\n  pointer(ballXY.get())\n    .start(ballXY);\n}\n\nfunction stopTracking() {\n  spring({\n    from: ballXY.get(),\n    velocity: ballXY.getVelocity(),\n    stiffness: 100,\n    damping: 10\n  }).start(ballXY);\n}\n\nlisten(ball, 'mousedown touchstart').start(startTracking);\nlisten(document, 'mouseup touchend').start(stopTracking);\n\\`}</Example>\n\\`\\`\\`\n\n### \\`physics\\`\n\nThe \\`physics\\` animation is the swiss army knife of velocity-based animations.\n\nIt offers \\`friction\\`, \\`to\\` and \\`springStrength\\` properties, so it can theoretically be used to create motion similar to \\`decay\\` and \\`spring\\`. \n\nHowever, \\`decay\\` and \\`spring\\` animations are **differential equations** that resolve for a given \\`elapsedTime\\`. In practical terms, this means that if you want to change the animation they're creating, you need create a new animation with the new properties.\n\nThese equations are incredibly accurate, offering the smoothest motion and in the near future, will allow these animations to be scrubbable the same way \\`tween\\` is.\n\nInstead, \\`physics\\` is an **integrated simulation**. This means that, once the simulation has started, its properties **can be modified** because \\`physics\\` uses **its current state** to calculate its next\n\nFor instance, we can tether a \\`physics\\` spring between the ball and the pointer:\n\n\\`\\`\\`javascript\nconst springTo = physics({\n  velocity: ballXY.getVelocity(),\n  friction: 0.6,\n  springStrength: 400,\n  to: ballXY.get(),\n  restSpeed: false\n}).start(ballXY);\n\npointer(ballXY.get())\n  .start((v) => springTo.setSpringTarget(v));\n\\`\\`\\`\n\n\\`\\`\\`marksy\n<Example template=\"Ball\" id=\"c\" autostart={true}>{\\`\nconst ball = document.querySelector('#c .ball');\nconst ballStyler = styler(ball);\nconst ballXY = value({ x: 0, y: 0 }, ballStyler.set);\n\nlet activeAction;\nlet pointerTracker;\n\nfunction startTracking() {\n  activeAction = physics({\n    velocity: ballXY.getVelocity(),\n    friction: 0.6,\n    springStrength: 400,\n    to: ballXY.get(),\n    restSpeed: false\n  }).start(ballXY);\n\n  pointerTracker = pointer(ballXY.get())\n    .start((v) => activeAction.setSpringTarget(v));\n}\n\nfunction stopTracking() {\n  if (activeAction) activeAction.stop();\n  if (pointerTracker) pointerTracker.stop();\n  spring({\n    velocity: ballXY.getVelocity(),\n    from: ballXY.get(),\n    stiffness: 300,\n    damping: 10\n  }).start(ballXY);\n}\n\nlisten(ball, 'mousedown touchstart').start(startTracking);\nlisten(document, 'mouseup touchend').start(stopTracking);\n\\`}</Example>\n\\`\\`\\`\n\n## Conclusion\n\n\\`velocity\\` is a key part of creating natural interactions with Popmotion.\n\nBe sure to check out the full docs of [value](/api/value), [decay](/api/decay), [spring](/api/spring) and [physics](/api/physics), as there's much more to each than we've been able to cover in this introductory tutorial.\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"velocity-and-physics\"\n    section=\"learn\"\n    category=\"basics\"\n    title=\"Physics and velocity\"\n    description=\"Create responsive interactions with velocity, decay, physics and spring.\"\n    published=\"\"\n    theme=\"pure\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/stylefire/api/create-styler-factory.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/jsx';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\nimport CodeSandbox from '~/components/examples/CodeSandbox';\nimport TOC from '~/templates/content/TableOfContents';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video,\n    TOC: () => <TOC toc={content.toc} />,\n    CodeSandbox\n  }\n});\n\nconst content = convertMarkdown(`# createStylerFactory\n\nBy default, \\`styler\\` outputs stylers for HTML and SVG elements. It's possible to create a \\`styler\\` for any JavaScript API that might benefit from render batching or cached state.\n\nFor this, we can use the \\`createStylerFactory\\` function.\n\n## Usage\n\n### Import\n\n\\`\\`\\`javascript\nimport { createStylerFactory } from 'stylefire';\n\\`\\`\\`\n\n### Create a styler factory\n\n\\`createStylerFactory\\` accepts an object of properties:\n\n#### onRead\n\nThis method is fired when the styler's \\`get\\` is called and no property with this name is present in the state cache (or \\`useCache\\` is set to \\`false\\`).\n\n\\`\\`\\`typescript\n(key: string, props: {}): any\n\\`\\`\\`\n\n#### onRender\n\nThis method is fired on the render step, or if the styler's \\`render\\` method is called manually.\n\n\\`\\`\\`typescript\n(state: {}, props: {}, changedValues: string[]): void\n\\`\\`\\`\n\n#### useCache\n\nSet to \\`false\\` if you always want \\`onRead\\` to fire when a user calls \\`get\\`.\n\n### Using the styler factory\n\n\\`createStylerFactory\\` returns a styler factory:\n\n\\`\\`\\`javascript\nconst myStylerFactory = createStylerFactory({ onRead, onRender });\n\\`\\`\\`\n\nThis is a function that accepts one argument, an object of props. These props can be anything - they are for you to use in \\`onRead\\` and \\`onRender\\` methods.\n\nHere's an incredibly simple example of a styler that simply reads and writes any object provided to it:\n\n\\`\\`\\`javascript\nimport { createStylerFactory } from 'stylefire';\n\nconst exampleStyler = createStylerFactory({\n  onRead: (key, props) => props[key],\n  onRender: (state, props, changedValues) => {\n    changedValues.forEach(key => (props[key] = state[key]));\n  }\n});\n\nconst myExampleStyler = exampleStyler({ red: 255, green: 255, blue: 255 });\nmyExampleStyler.set('green', 0);\n\\`\\`\\``);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"create-styler-factory\"\n    section=\"api\"\n    undefined\n    title=\"Create styler factory\"\n    description=\"Create a custom styler factory.\"\n    published=\"\"\n    author=\"undefined\"\n    theme=\"stylefire\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/stylefire/api/html.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/jsx';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\nimport CodeSandbox from '~/components/examples/CodeSandbox';\nimport TOC from '~/templates/content/TableOfContents';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video,\n    TOC: () => <TOC toc={content.toc} />,\n    CodeSandbox\n  }\n});\n\nconst content = convertMarkdown(`# HTML styler\n\nWhen [\\`styler\\`](/stylefire/stylefire) is provided a \\`HTMLElement\\`, it returns a styler capable of setting CSS and scroll props.\n\n\\`\\`\\`javascript\nconst divStyler = styler(document.getElementByTag('div'))\n\ndivStyler.set({ x: 0, scale: 1.2 })\n\\`\\`\\`\n\n## Config\n\nA configuration argument can be **optionally** passed to \\`styler\\` as the second argument:\n\n\\`\\`\\`javascript\nconst divStyler = styler(div, {});\n\\`\\`\\`\n\n### enableHardwareAcceleration\n\nIf set to \\`false\\`, Stylefire won't optimise animations with the GPU.\n\nThis can result in higher image quality when scaling up elements.\n\n## Props\n\n### Property alias\n\nThe following alias' can be optionally used for setting CSS props:\n\n* \\`x\\`: \\`translateX\\`\n* \\`y\\`: \\`translateY\\`\n* \\`z\\`: \\`translateZ\\`\n* \\`originX\\`: \\`transformOriginX\\`\n* \\`originY\\`: \\`transformOriginY\\`\n* \\`originZ\\`: \\`transformOriginZ\\`\n\nIf set as a number, \\`originX\\` and \\`originY\\` are set as a progress value between \\`0\\` and \\`1\\`. \\`originZ\\` is set in pixels.\n\n### Transform property order\n\nThe \\`transform\\` property can be set directly, but in most cases it's simpler to animate \\`rotate\\`, \\`translate\\` and \\`scale\\` as individual props.\n\nIn accordance with the [CSS Transforms Level 2 spec](https://drafts.csswg.org/css-transforms-2/#individual-transforms), if set individually these properties will be set in the following order:\n\n\\`translate\\`, \\`scale\\`, \\`rotate\\`\n\nA different order can be specified by setting \\`transform\\` to a function. It'll be provided two values, the individually-set props and the Stylefire-generated. \\`transform\\`.\n\n\\`\\`\\`javascript\nstyler.set({\n  transform: ({ x, y }, generated) => 'translateX' + x * y + 'px)'\n})\n\\`\\`\\`\n\n### CSS variables\n\n[CSS variables](https://css-tricks.com/difference-between-types-of-css-variables/#article-header-id-1) can be set and animated just like any other property:\n\n\\`\\`\\`javascript\nconst htmlStyler = css(document.documentElement);\n\nhtmlRenderer.set('--bg-color', '#000');\n\\`\\`\\`\n\n### Supported props\n\n**All CSS properties are supported**, in addition to these scroll properties:\n\n* \\`scrollTop\\`\n* \\`scrollLeft\\`\n\nIf \\`window\\` is passed to styler, these are the **only** two supported props.\n\n### Prop types\n\nFor convenience and safety, many props are mapped to [value types](https://github.com/Popmotion/popmotion/tree/master/packages/style-value-types) for safety and convenience.\n\n#### Color props\n\n* \\`color\\`: \\`color\\`\n* \\`backgroundColor\\`: \\`color\\`\n* \\`outlineColor\\`: \\`color\\`\n* \\`fill\\`: \\`color\\`\n* \\`stroke\\`: \\`color\\`\n\n#### Border props\n\n- \\`borderColor\\`: \\`color\\`\n- \\`borderTopColor\\`: \\`color\\`\n- \\`borderRightColor\\`: \\`color\\`\n- \\`borderBottomColor\\`: \\`color\\`\n- \\`borderLeftColor\\`: \\`color\\`\n- \\`borderWidth\\`: \\`px\\`\n- \\`borderTopWidth\\`: \\`px\\`\n- \\`borderRightWidth\\`: \\`px\\`\n- \\`borderBottomWidth\\`: \\`px\\`\n- \\`borderLeftWidth\\`: \\`px\\`\n- \\`borderRadius\\`: \\`px\\`\n- \\`borderTopLeftRadius\\`: \\`px\\`\n- \\`borderTopRightRadius\\`: \\`px\\`\n- \\`borderBottomRightRadius\\`: \\`px\\`\n- \\`borderBottomLeftRadius\\`: \\`px\\`\n\n#### Positioning\n\n* \\`width\\`: \\`px\\`\n- \\`maxWidth\\`: \\`px\\`\n* \\`height\\`: \\`px\\`\n- \\`maxHeight\\`: \\`px\\`\n* \\`top\\`: \\`px\\`\n* \\`left\\`: \\`px\\`\n* \\`bottom\\`: \\`px\\`\n* \\`right\\`: \\`px\\`\n\n#### Transform\n\n* \\`rotate\\`: \\`degrees\\`\n* \\`rotateX\\`: \\`degrees\\`\n* \\`rotateY\\`: \\`degrees\\`\n* \\`rotateZ\\`: \\`degrees\\`\n* \\`scale\\`: \\`scale\\`\n* \\`scaleX\\`: \\`scale\\`\n* \\`scaleY\\`: \\`scale\\`\n* \\`scaleZ\\`: \\`scale\\`\n* \\`skewX\\`: \\`degrees\\`\n* \\`skewY\\`: \\`degrees\\`\n* \\`translateX\\`: \\`px\\`\n* \\`translateY\\`: \\`px\\`\n* \\`translateZ\\`: \\`px\\`\n* \\`perspective\\`: \\`px\\`\n* \\`opacity\\`: \\`alpha\\`\n\n#### Spacing\n\n- \\`padding\\`: \\`px\\`\n- \\`paddingTop\\`: \\`px\\`\n- \\`paddingRight\\`: \\`px\\`\n- \\`paddingBottom\\`: \\`px\\`\n- \\`paddingLeft\\`: \\`px\\`\n- \\`margin\\`: \\`px\\`\n- \\`marginTop\\`: \\`px\\`\n- \\`marginRight\\`: \\`px\\`\n- \\`marginBottom\\`: \\`px\\`\n- \\`marginLeft\\`: \\`px\\`\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"html\"\n    section=\"api\"\n    category=\"stylers\"\n    title=\"HTML\"\n    description=\"Styler for HTML that supports CSS variables, individual transform props and prevents layout thrashing.\"\n    published=\"\"\n    author=\"undefined\"\n    theme=\"stylefire\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/stylefire/api/styler.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/jsx';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\nimport CodeSandbox from '~/components/examples/CodeSandbox';\nimport TOC from '~/templates/content/TableOfContents';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video,\n    TOC: () => <TOC toc={content.toc} />,\n    CodeSandbox\n  }\n});\n\nconst content = convertMarkdown(`# Styler\n\nStylers are performant style setters for HTML and SVG elements, optimised to work with animation libraries.\n\nThey batch updates to a single step on the [Framesync](/api/framesync) render loop, preventing layout thrashing and unnecessary renders.\n\nThey also allow \\`transform\\` properties to be set and animated independently.\n\nThe \\`styler\\` factory function is used to create a new styler for a single element or \\`window\\`.\n\n## Usage\n\n### Import\n\n\\`\\`\\`javascript\nimport styler from 'stylefire';\n\\`\\`\\`\n\n### Create a styler\n\n\\`\\`\\`javascript\nconst div = document.querySelector('div');\nconst divStyler = styler(div);\n\\`\\`\\`\n\n### Set style properties\n\nThe \\`set\\` method is used to schedule an update on the next render step.\n\n\\`\\`\\`javascript\ndivStyler.set({ x: 100 });\n\\`\\`\\`\n\nStylers understand default property types for many [CSS](/stylefire/api/html) and [SVG](/stylefire/api/svg) props. So even though we just set \\`x\\` as \\`100\\`, Stylefire will output \\`transform: translateX(100px)\\`.\n\n### Forced render\n\nSometimes we need to force a render outside of the render loop. For instance, if we want to set some properties and then immediately measure the state of the element.\n\nWe can do so with the \\`render\\` method:\n\n\\`\\`\\`javascript\ndivStyler.set({ width: 'auto' });\ndivStyler.render();\n\\`\\`\\`\n\n### Get style property\n\nThe \\`get\\` method can be used to read individual properties:\n\n\\`\\`\\`javascript\nconst div = document.querySelector('path');\nconst pathStyler = styler(path);\npathStyler.get('pathLength');\n\\`\\`\\`\n\n**Note:** Due to the considerable filesize overhead in reading CSS \\`transform\\` properties, Stylefire will return the default value for any transform properties unless they've already been \\`set\\`.\n\n## Methods\n\n### set\n\nSets one or multiple properties, and schedules a render for the next available render step.\n\n\\`\\`\\`typescript\nset(props: {}): this\nset(key: string, prop: any): this\n\\`\\`\\`\n\n### get\n\nReturns the value of the provided key.\n\n\\`\\`\\`typescript\nget(key: string): any\n\\`\\`\\`\n\n### render\n\nImmediately render, without waiting for the next frame.\n\n\\`\\`\\`typescript\nrender(): this\n\\`\\`\\``);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"styler\"\n    section=\"api\"\n    undefined\n    title=\"Styler\"\n    description=\"Create style setters for HTML, SVG and the viewport.\"\n    published=\"\"\n    author=\"undefined\"\n    theme=\"stylefire\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/stylefire/api/svg.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/jsx';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\nimport CodeSandbox from '~/components/examples/CodeSandbox';\nimport TOC from '~/templates/content/TableOfContents';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video,\n    TOC: () => <TOC toc={content.toc} />,\n    CodeSandbox\n  }\n});\n\nconst content = convertMarkdown(`# SVG styler\n\nThe SVG styler replaces the confusing SVG transformation model with the CSS model and provides a simple API for \\`path\\` drawing.\n\n\\`\\`\\`javascript\nconst pathStyler = styler(document.getElementByTag('path'))\n\npathStyler.set({ pathLength: 50 })\n\\`\\`\\`\n\n## Path drawing\n\nLine drawing the process of using an SVG \\`path\\` element and its \\`stroke-dasharray\\` and \\`stoke-dashoffset\\` properties to emulate a pen drawing a line. [This blog post](https://css-tricks.com/svg-line-animation-works/) explains the effect in more detail.\n\nStylefire supports both\\`'stoke-dasharray'\\` and \\`stroke-dashorigin\\` properties, but also provides:\n\n* \\`pathLength\\`\n* \\`pathSpacing\\`\n* \\`pathOffset\\`\n\nThese are all set as a **progress of the total path length, from \\`0\\` to \\`1\\`**, which is automatically measured by Stylefire.\n\nSo you can define an animation from \\`0\\` to \\`1\\`:\n\n\\`\\`\\`javascript\nimport { tween } from 'popmotion';\nimport styler from 'stylefire';\n\nconst path = document.querySelector('path');\nconst pathStyler = styler(polygon);\n\ntween({ to: 1 }).start(\n  v => pathStyler.set('pathLength', v)\n);\n\\`\\`\\`\n\nIn this example you can change the real \\`path\\` shape and length without having to update the animation.\n\n## Props\n\n### Supported props\n\nAll SVG attributes are supported. \\`x\\` and \\`y\\` attributes can be accessed via \\`attrX\\` and \\`attrY\\`.\n\nThe following transform props are supported:\n\n* \\`rotate\\`: \\`degrees\\`\n* \\`rotateX\\`: \\`degrees\\`\n* \\`rotateY\\`: \\`degrees\\`\n* \\`scale\\`: \\`scale\\`\n* \\`scaleX\\`: \\`scale\\`\n* \\`scaleY\\`: \\`scale\\`\n* \\`skewX\\`: \\`degrees\\`\n* \\`skewY\\`: \\`degrees\\`\n* \\`translateX\\`: \\`px\\`\n* \\`translateY\\`: \\`px\\`\n* \\`translateZ\\`: \\`px\\`\n* \\`perspective\\`: \\`px\\`\n\n## Prop types\n\nFor convenience and safety, many props are mapped to [value types](https://github.com/Popmotion/popmotion/tree/master/packages/style-value-types) for safety and convenience.\n\n* \\`fill\\`: \\`color\\`\n* \\`stroke\\`: \\`color\\`\n* \\`x\\`/\\`y\\`: \\`px\\`\n* \\`scale\\`: \\`scale\\`\n* \\`scaleX\\`: \\`scale\\`\n* \\`scaleY\\`: \\`scale\\`\n* \\`opacity\\`: \\`alpha\\`\n* \\`fillOpacity\\`: \\`alpha\\`\n* \\`strokeOpacity\\`: \\`alpha\\`\n`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"svg\"\n    section=\"api\"\n    category=\"stylers\"\n    title=\"SVG\"\n    description=\"Styler for SVG that simplifies transforms and path drawing.\"\n    published=\"\"\n    author=\"undefined\"\n    theme=\"stylefire\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/stylefire/api/viewport.js",
    "content": "\nimport { createElement } from 'react';\nimport marksy from 'marksy/jsx';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\nimport CodeSandbox from '~/components/examples/CodeSandbox';\nimport TOC from '~/templates/content/TableOfContents';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video,\n    TOC: () => <TOC toc={content.toc} />,\n    CodeSandbox\n  }\n});\n\nconst content = convertMarkdown(`# Viewport styler\n\nWhen \\`styler\\` is provided \\`window\\`, it returns a styler capable of scrolling the viewport.\n\n\\`\\`\\`javascript\nconst viewportStyler = styler(window);\n\nviewportStyler.set('scrollTop', 20);\n\\`\\`\\`\n\nIt supports \\`scrollTop\\` and \\`scrollLeft\\` props.`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"viewport\"\n    section=\"api\"\n    category=\"stylers\"\n    title=\"Viewport\"\n    description=\"Styler for setting viewport scroll position.\"\n    published=\"\"\n    author=\"undefined\"\n    theme=\"stylefire\"\n    undefined\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n"
  },
  {
    "path": "packages/site/pages/stylefire/api.js",
    "content": "import { Fragment } from 'react';\nimport GlobalTemplate from '~/templates/global/Template';\nimport ContentPage from '~/templates/global-new/ContentPage';\nimport { Section, PageHeader } from '~/templates/global-new/styled';\nimport MenuPage from '~/templates/content/MenuPage';\n\nexport default () => (\n  <GlobalTemplate\n    title=\"API | Stylefire\"\n    description=\"Simple HTML & SVG styler, optimised for animation\"\n    theme=\"stylefire\"\n  >\n    <ContentPage section=\"api\">\n      <Section>\n        <PageHeader>API</PageHeader>\n        <MenuPage section=\"api\" />\n      </Section>\n    </ContentPage>\n  </GlobalTemplate>\n);\n"
  },
  {
    "path": "packages/site/pages/stylefire/index.js",
    "content": "import StylefireHomepage from '~/templates/Stylefire';\n\nexport default () => <StylefireHomepage />;\n"
  },
  {
    "path": "packages/site/pages/support.js",
    "content": "import { Fragment } from 'react';\n\nimport GlobalTemplate from '~/templates/global/Template';\nimport ContentPage from '~/templates/global-new/ContentPage';\nimport { Section, PageHeader } from '~/templates/global-new/styled';\nimport { A, P, H2, Li, Ul } from '~/templates/global/styled';\n\nexport default () => (\n  <GlobalTemplate\n    title=\"Support us | Popmotion\"\n    description=\"Join the Popmotion Patreon or Open Collective to support its continued development\"\n    theme=\"popmotion\"\n  >\n    <ContentPage section=\"support\">\n      <Section>\n        <PageHeader>Support</PageHeader>\n        <P>\n          Popmotion makes animations libraries that are open source and free to\n          use. It isn't sustainable without financial backing, which is why\n          we've turned to the community for funding.\n        </P>\n        <H2>Recurring pledges</H2>\n        <P>\n          There's a range of support tiers suited to individuals and\n          organisations alike.\n        </P>\n        <P>\n          You can pledge any amount, but for $10 a month individuals will\n          receive a special permissive, commercial license for premium React\n          components, like{' '}\n          <A href=\"/pose/api/react-pose-text\">React Pose Text</A>.\n        </P>\n        <P>\n          For $100 or more a month, companies can get this license for their\n          entire team, as well as sponsoring the project publicly on our\n          website.\n        </P>\n        <P>\n          Finally, contributions of any amount are welcomed, and all will get\n          your name on our{' '}\n          <A href=\"https://github.com/Popmotion/popmotion/blob/master/BACKERS.md\">\n            official backers list\n          </A>\n          .\n        </P>\n        <Ul>\n          <Li>\n            <A href=\"https://patreon.com/popmotion\">Patreon</A> (best for\n            individuals)\n          </Li>\n          <Li>\n            <A href=\"https://opencollective.com/popmotion\">Open Collective</A>{' '}\n            (best for organisations)\n          </Li>\n        </Ul>\n      </Section>\n    </ContentPage>\n  </GlobalTemplate>\n);\n"
  },
  {
    "path": "packages/site/public/manifest.json",
    "content": "{\n  \"theme_color\": \"#ED2754\"\n}"
  },
  {
    "path": "packages/site/scripts/build-next-config.js",
    "content": "const fs = require('fs');\nconst path = require('path');\n\nconst outputPath = path.join(__dirname, '../next.config.js');\n\nconst fileTemplate = routes => `\nmodule.exports = {\n  distDir: 'build',\n  exportTrailingSlash: true,\n  exportPathMap: function () {\n    return ${routes};\n  },\n  webpack: (config, props) => {\n    config.module.rules.push({\n      test: /\\.md$/,\n      loader: 'emit-file-loader',\n      options: {\n        name: 'dist/[path][name].[ext]',\n      },\n    },\n    {\n      test: /\\.md$/,\n      loader: 'raw-loader',\n    })\n\n    return config\n  }\n};\n`;\n\nconst generateRouteDefinitions = data => {\n  // TODO: Automatically generate api/blog etc\n  let routes = `\n    '/': { page: '/' },\n    '/support': { page: '/support' },\n    '/api': { page: '/api' },\n    '/blog': { page: '/blog' },\n    '/pose': { page: '/pose' },\n    '/pure': { page: '/pure' },\n    '/popcorn': { page: '/popcorn' },\n    '/pose/api': { page: '/pose/api' },\n    '/pose/examples': { page: '/pose/examples' },\n    '/page-not-found': { page: '/_error' },\n    '/stylefire': { page: '/stylefire' },\n    '/stylefire/api': { page: '/stylefire/api' },\n  `;\n\n  Object.keys(data).forEach(siteId => {\n    const siteData = data[siteId];\n\n    Object.keys(siteData).forEach(sectionId => {\n      const sectionData = siteData[sectionId];\n      const pageIds = Object.keys(sectionData);\n\n      pageIds.forEach(pageId => {\n        const route = `/${\n          siteId === 'pure' ? '' : siteId + '/'\n        }${sectionId}/${pageId}`;\n        routes += `\n          '${route}': {\n            page: '${route}'\n          },\n        `;\n      });\n    });\n  });\n\n  return `{${routes}}`;\n};\n\nmodule.exports = function(data) {\n  const routes = generateRouteDefinitions(data);\n  fs.writeFileSync(outputPath, fileTemplate(routes));\n};\n"
  },
  {
    "path": "packages/site/scripts/convert-date-format.js",
    "content": "/*\nSimple script to convert YYYYMMDD format into eg 28 Jan 2017 format\n*/\nconst months = ['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n\nmodule.exports = function (yyyymmdd) {\n  const year = yyyymmdd.substring(2, 4);\n  const month = parseInt(yyyymmdd.substring(4, 6));\n  const day = parseInt(yyyymmdd.substring(6, 8));\n\n  return `${day} ${months[month]} ${year}`;\n};\n"
  },
  {
    "path": "packages/site/scripts/filename-operations.js",
    "content": "const DS_STORE = '.DS_Store';\n\nmodule.exports = {\n  filterFiles: (filename) => (filename.indexOf('.') === -1),\n  filterSystemFiles: (filename) => (filename !== DS_STORE)\n};\n"
  },
  {
    "path": "packages/site/scripts/generate-content-page.js",
    "content": "const escapeBackticks = (string) => string.replace(/`/g, '\\\\`');\n\nmodule.exports = (\n  body,\n  {\n    category,\n    id,\n    title,\n    description,\n    published,\n    siteName,\n    section,\n    next,\n    author,\n  },\n  isHomepage = false\n) =>\n  isHomepage\n    ? `\nimport marksy from 'marksy';\nimport Homepage from '~/components/template';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { createElement } from 'react';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    blockquote: Blockquote,\n  }\n});\n\nconst Page = ({ section }) => (\n  <Homepage tableOfContents={content.toc}>\n    {content.tree}\n  </Homepage>\n);\n\nconst content = convertMarkdown(\\`${escapeBackticks(body)}\\`);\n\nexport default Page;\n`\n    : `\nimport { createElement } from 'react';\nimport marksy from 'marksy/jsx';\nimport { A, H1, H2, H3, H4, H5, P, Li, Ol, Ul, Hr, Code, Blockquote, ArticleHeader, Video } from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\nimport ContentTemplate from '~/templates/content/Template';\nimport Example from '~/components/examples/Example';\nimport CodePen from '~/components/examples/CodePen';\nimport CodeSandbox from '~/components/examples/CodeSandbox';\nimport TOC from '~/templates/content/TableOfContents';\n\nconst removeEmpty = filename => filename !== '';\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ol: Ol,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote,\n  },\n  components: {\n    Example,\n    CodePen,\n    Video,\n    TOC: () => <TOC toc={content.toc} />,\n    CodeSandbox\n  }\n});\n\nconst content = convertMarkdown(\\`${escapeBackticks(body)}\\`);\n\nconst Page = ({ section }) => (\n  <ContentTemplate\n    id=\"${id}\"\n    section=\"${section}\"\n    ${category && `category=\"${category}\"`}\n    title=\"${title}\"\n    description=\"${description}\"\n    published=\"${published}\"\n    author=\"${author}\"\n    theme=\"${siteName}\"\n    ${next && `next=\"${next}\"`}\n  >\n    {content.tree}\n  </ContentTemplate>\n);\n\nexport default Page;\n`;\n"
  },
  {
    "path": "packages/site/scripts/generate-content.js",
    "content": "const fs = require('fs');\nconst path = require('path');\nconst frontMatter = require('front-matter');\nconst generatePage = require('./generate-content-page');\nconst generateMenus = require('./generate-menus');\nconst convertDateFormat = require('./convert-date-format');\nconst { filterFiles, filterSystemFiles } = require('./filename-operations');\nconst buildNextConfig = require('./build-next-config');\n\nconst packagesPath = path.join(__dirname, '../../');\nconst contentMetadataOutputPath = path.join(__dirname, '../data/content.json');\nconst siteNameMap = JSON.parse(\n  fs.readFileSync(path.join(__dirname, '../data/site-names.json'), {\n    encoding: 'utf-8',\n  })\n);\n\nconst siteMetadata = {};\n\nfunction generateContent({\n  rootDir,\n  subDir = '',\n  firstLevelDir = '',\n  siteName,\n  packageName,\n}) {\n  packageName = packageName || rootDir;\n  siteName = siteName || siteNameMap[rootDir];\n\n  if (!siteName) return;\n  if (!siteMetadata[siteName]) siteMetadata[siteName] = {};\n\n  const readPath = path.join(__dirname, `../../${packageName}/docs/${subDir}`);\n\n  const outputPath = path.join(\n    __dirname,\n    `../pages/${siteName === 'pure' ? '' : siteName}/${firstLevelDir}`\n  );\n\n  // Create directory if none exists\n  if (!fs.existsSync(outputPath)) fs.mkdirSync(outputPath);\n\n  const dirList = fs.readdirSync(readPath).filter(filterSystemFiles);\n\n  dirList.forEach((filename) => {\n    // If directory, generate content for that directory\n    if (filename.indexOf('.') === -1) {\n      generateContent({\n        rootDir,\n        subDir: `${subDir}/${filename}/`,\n        firstLevelDir: firstLevelDir === '' ? filename : firstLevelDir,\n        siteName,\n        packageName,\n      });\n\n      // If file, generate content\n    } else {\n      const [id] = filename.split('.');\n      const file = fs.readFileSync(`${readPath}/${filename}`, {\n        encoding: 'utf-8',\n      });\n      const { attributes, body } = frontMatter(file);\n      const {\n        title,\n        description,\n        category,\n        published,\n        author,\n        next,\n        draft,\n      } = attributes;\n\n      const outputId = id === 'README' ? category : id;\n\n      if (!siteMetadata[siteName][firstLevelDir])\n        siteMetadata[siteName][firstLevelDir] = {};\n\n      const metadata = {\n        id: outputId,\n        title,\n        description,\n        category,\n        date: published,\n        author,\n        draft,\n        published: published ? convertDateFormat(`${published}`) : '',\n        section: firstLevelDir,\n        siteName: firstLevelDir === 'blog' ? 'popmotion' : siteName,\n        next,\n      };\n\n      fs.writeFileSync(\n        `${outputPath}/${outputId}.js`,\n        generatePage(body.replace(new RegExp('.md', 'g'), ''), metadata)\n      );\n\n      siteMetadata[siteName][firstLevelDir][outputId] = metadata;\n    }\n  });\n}\n\nconst topLevel = fs.readdirSync(packagesPath).filter(filterFiles);\ntopLevel.forEach((rootDir) => generateContent({ rootDir }));\n\n// Convert readme to homepage\nconst readme = fs\n  .readFileSync(path.join(__dirname, '../../../README.md'))\n  .toString('utf8')\n  .split('<!-- Documentation -->')[1];\n\nfs.writeFileSync(\n  path.join(__dirname, '../pages/index.js'),\n  generatePage(\n    readme,\n    {\n      id: 'index',\n      title: 'Popmotion: The JavaScript animation toolbox',\n      description: '',\n      siteName: 'popmotion',\n    },\n    true\n  )\n);\n\nfs.writeFile(contentMetadataOutputPath, JSON.stringify(siteMetadata), (err) => {\n  const msg = !err ? 'Site content created' : err;\n  console.log(msg);\n});\n\ngenerateMenus(siteMetadata);\nbuildNextConfig(siteMetadata);\n"
  },
  {
    "path": "packages/site/scripts/generate-menus.js",
    "content": "const fs = require('fs');\nconst path = require('path');\n\nconst menuOutputPath = path.join(__dirname, '../data/menus.json');\nconst categoryNames = JSON.parse(\n  fs.readFileSync(path.join(__dirname, '../data/category-names.json'), 'utf8')\n);\n\nmodule.exports = function(siteMetadata) {\n  const menus = {};\n\n  // Iterate over sites\n  Object.keys(siteMetadata).forEach(siteName => {\n    const siteMenu = {};\n\n    // Iterate over sections\n    Object.keys(siteMetadata[siteName]).forEach(sectionKey => {\n      const menu = [];\n      const categories = {};\n      const sectionMetadata = siteMetadata[siteName][sectionKey];\n\n      // Iterate over posts\n      Object.keys(sectionMetadata).forEach(postKey => {\n        const { id, title, category } = sectionMetadata[postKey];\n\n        // This post has a category\n        if (category) {\n          // If category data doesn't exist\n          if (!categories[category]) {\n            categories[category] = {\n              id: category,\n              title: categoryNames[category],\n              posts: []\n            };\n            menu.push(categories[category]);\n          }\n\n          if (id !== category) {\n            categories[category].posts.push({ id, title });\n          }\n\n          // Or stand-alone post\n        } else {\n          menu.push({ id, title });\n        }\n      });\n\n      // Sort posts - adapted/butchered from https://blog.theodorejb.me/linked-list-sorting/\n      menu.sort((a, b) => (a.id < b.id ? -1 : 1)).forEach(menuItem => {\n        if (menuItem.posts) {\n          const unsortedList = [];\n          const sortedList = [];\n          const map = new Map();\n          let currentPost = null;\n\n          menuItem.posts.forEach((post, i) => {\n            const { next } = sectionMetadata[post.id];\n\n            if (!next || !sectionMetadata[next]) {\n              unsortedList.push(post);\n            } else {\n              const nextIndex = menuItem.posts.findIndex(\n                ({ id }) => id === next\n              );\n              const isFirstPost =\n                menuItem.posts.find(({ id }) => {\n                  const thisPost = sectionMetadata[id];\n                  return post.id === thisPost.next;\n                }) === undefined;\n              if (isFirstPost) currentPost = post;\n\n              if (nextIndex > -1) {\n                map.set(post.id, nextIndex);\n              } else {\n                throw new Error(`${post.id} incorrectly linked to ${next}`);\n              }\n            }\n          });\n\n          const numPosts = menuItem.posts.length;\n          const numUnsorted = unsortedList.length;\n          const numToSort = numPosts - numUnsorted;\n\n          if (numToSort && currentPost) {\n            sortedList.push(currentPost);\n            const removeIndex = unsortedList.findIndex(\n              ({ id }) => id === currentPost.id\n            );\n            if (removeIndex >= 0) {\n              unsortedList.splice(removeIndex, 1);\n            }\n\n            while (sortedList.length < numToSort) {\n              const nextPost = menuItem.posts[map.get(currentPost.id)];\n              sortedList.push(nextPost);\n              currentPost = nextPost;\n            }\n\n            menuItem.posts = [...sortedList, ...unsortedList];\n          }\n        }\n      });\n\n      siteMenu[sectionKey] = menu;\n\n      if (sectionKey === 'blog') menu.reverse();\n    });\n\n    menus[siteName] = siteMenu;\n  });\n\n  fs.writeFile(menuOutputPath, JSON.stringify(menus), err => {\n    const msg = !err ? 'Menus created' : err;\n  });\n};\n"
  },
  {
    "path": "packages/site/styles/fonts.js",
    "content": "const fontWeight = (weight) => `font-weight: ${weight};`;\n\nexport const bodyFont = `\n  font-family: GT Walsheim,Neue Helvetica W02,Helvetica Neue,Helvetica,Arial,sans-serif;\n  -webkit-font-smoothing: antialiased;\n  text-rendering: optimizeLegibility;\n  ${fontWeight(400)}\n`;\n\nexport const codeFont = `\nfont-family: \"IBM Plex Mono\", \"MonaLisa\", \"Dank Mono\",\n\"Source Sans Pro\", Courier, Monaco, monospace !important;\n  ${fontWeight(400)}\n`;\n\nexport const fontSize = (size) => `\n  font-size: ${size}px;\n`;\n\nexport const fontBold = `font-weight: 700;`;\n\nexport const lineHeight = (height) => `line-height: ${height}px;`;\n\nexport const font = {\n  body: bodyFont,\n  bold: fontBold,\n};\n"
  },
  {
    "path": "packages/site/styles/nprogress.js",
    "content": "import { color } from '~/styles/vars';\n\nexport default `\n/* Make clicks pass-through */\n#nprogress {\n  pointer-events: none;\n}\n\n#nprogress .bar {\n  background: ${color.black};\n  position: fixed;\n  z-index: 9999;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 2px;\n}\n\n/* Fancy blur effect */\n#nprogress .peg {\n  display: block;\n  position: absolute;\n  right: 0px;\n  width: 100px;\n  height: 100%;\n  box-shadow: 0 0 10px ${color.black}, 0 0 5px ${color.black};\n  opacity: 1.0;\n\n  -webkit-transform: rotate(3deg) translate(0px, -4px);\n      -ms-transform: rotate(3deg) translate(0px, -4px);\n          transform: rotate(3deg) translate(0px, -4px);\n}\n\n\n.nprogress-custom-parent #nprogress .bar {\n  position: absolute;\n}\n`;\n"
  },
  {
    "path": "packages/site/styles/reset.js",
    "content": "import { bodyFont, codeFont, fontSize } from './fonts';\nimport { ACTION, color, cols, ACTION_BURN } from './vars';\nimport { prismTheme } from '~/styles/syntax-highlighting';\n\nexport default `\nbody {\n  --color-popmotion: #FA196C;\n  --color-black: #2D2D2F;\n  --color-shade: #F7F7F7;\n}\n\n@font-face {\n  font-family: \"GT Walsheim\";\n  src: url(\"/fonts/GT-Walsheim-Regular.woff2\")\n      format(\"woff2\"),\n    url(\"/fonts/GT-Walsheim-Regular.woff\")\n      format(\"woff\");\n}\n\n@font-face {\n  font-family: \"GT Walsheim Bold\";\n  src: url(\"/fonts/GT-Walsheim-Bold.woff2\")\n      format(\"woff2\"),\n    url(\"/fonts/GT-Walsheim-Bold.woff\")\n      format(\"woff\");\n}\n\n* {\n  box-sizing: border-box;\n  margin: 0;\n  padding: 0;\n  border: 0;\n  outline: 0;\n  font-style: inherit;\n  color: ${color.black};\n  ${bodyFont}\n  line-height: 1;\n  vertical-align: baseline;\n  word-wrap: break-word;\n  -webkit-tap-highlight-color: rgba(0,0,0,0);\n  -webkit-font-smoothing: antialiased;\n}\n\nbr {\n  line-height: 0;\n}\n\ntextarea,\ninput {\n  -webkit-appearance: none;\n  border-radius: 0;\n}\n\ninput:-webkit-autofill {\n  -webkit-box-shadow: 0 0 0px 1000px white inset;\n}\n\n/*! normalize.css v4.1.1 | MIT License | github.com/necolas/normalize.css */\n\n/**\n * 1. Change the default font family in all browsers (opinionated).\n * 2. Prevent adjustments of font size after orientation changes in IE and iOS.\n */\n\nhtml {\n  font-family: sans-serif; /* 1 */\n  -ms-text-size-adjust: 100%; /* 2 */\n  -webkit-text-size-adjust: 100%; /* 2 */\n}\n\n/**\n * Remove the margin in all browsers (opinionated).\n */\n\nbody {\n  margin: 0;\n  overflow-x: hidden;\n}\n\n/* HTML5 display definitions\n   ========================================================================== */\n\n/**\n * Add the correct display in IE 9-.\n * 1. Add the correct display in Edge, IE, and Firefox.\n * 2. Add the correct display in IE.\n */\n\narticle,\naside,\ndetails, /* 1 */\nfigcaption,\nfigure,\nfooter,\nheader,\nmain, /* 2 */\nmenu,\nnav,\nsection,\nsummary { /* 1 */\n  display: block;\n}\n\n/**\n * Add the correct display in IE 9-.\n */\n\naudio,\ncanvas,\nprogress,\nvideo {\n  display: inline-block;\n}\n\nul, ol {\n  list-style-type: none;\n}\n\n/**\n * Add the correct display in iOS 4-7.\n */\n\naudio:not([controls]) {\n  display: none;\n  height: 0;\n}\n\n/* Links\n   ========================================================================== */\n\n/**\n * 1. Remove the gray background on active links in IE 10.\n * 2. Remove gaps in links underline in iOS 8+ and Safari 8+.\n */\n\na {\n  background-color: transparent; /* 1 */\n  -webkit-text-decoration-skip: objects; /* 2 */\n  color: #09f;\n  text-decoration: none;\n\n  &:hover {\n    color: #09f;\n  }\n}\n\n/**\n * Remove the outline on focused links when they are also active or hovered\n * in all browsers (opinionated).\n */\n\na:active,\na:hover {\n  outline-width: 0;\n}\n\n/* Text-level semantics\n   ========================================================================== */\n\n/**\n * 1. Remove the bottom border in Firefox 39-.\n * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.\n */\n\nabbr[title] {\n  border-bottom: none; /* 1 */\n  text-decoration: underline; /* 2 */\n  text-decoration: underline dotted; /* 2 */\n}\n\n/**\n * Prevent the duplicate application of bolder by the next rule in Safari 6.\n */\n\nstrong {\n  font-weight: inherit;\n}\n\n/**\n * Add the correct font weight in Chrome, Edge, and Safari.\n */\n\nstrong {\n  font-weight: bolder;\n}\n\n/**\n * Prevent sub and sup elements from affecting the line height in\n * all browsers.\n */\n\nsub,\nsup {\n  font-size: 75%;\n  line-height: 0;\n  position: relative;\n  vertical-align: baseline;\n}\n\nsub {\n  bottom: -0.25em;\n}\n\nsup {\n  top: -0.5em;\n}\n\n/* Embedded content\n   ========================================================================== */\n\n/**\n * Remove the border on images inside links in IE 10-.\n */\n\nimg {\n  border-style: none;\n}\n\n/**\n * Hide the overflow in IE.\n */\n\nsvg:not(:root) {\n  overflow: hidden;\n}\n\n/* Grouping content\n   ========================================================================== */\n\n/**\n * 1. Correct the inheritance and scaling of font size in all browsers.\n * 2. Correct the odd em font sizing in all browsers.\n */\n\ncode,\nkbd,\npre,\nsamp,\ncode span,\npre span {\n  ${codeFont}\n  -webkit-font-smoothing: initial;\n  tab-size: 2;\n}\n\np code,\nli code {\n  background: ${color.superLightGrey};\n  padding: 3px 5px;\n  border: 1px solid ${color.lightGrey};\n}\n\n@media (max-width: ${cols(50)}) {\n  pre, pre code, pre span, code span {\n    ${fontSize(14)}\n    line-height: 18px;\n  }\n}\n/**\n * 1. Add the correct box sizing in Firefox.\n * 2. Show the overflow in Edge and IE.\n */\n\nhr {\n  box-sizing: content-box; /* 1 */\n  height: 0; /* 1 */\n  overflow: visible; /* 2 */\n}\n\n${prismTheme}\n\n/* Forms\n   ========================================================================== */\n\n/**\n * 1. Change font properties to inherit in all browsers (opinionated).\n * 2. Remove the margin in Firefox and Safari.\n */\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n  font: inherit; /* 1 */\n  margin: 0; /* 2 */\n}\n\n/**\n * Restore the font weight unset by the previous rule.\n */\n\noptgroup {\n  font-weight: bold;\n}\n\n/**\n * Show the overflow in IE.\n * 1. Show the overflow in Edge.\n */\n\nbutton,\ninput { /* 1 */\n  overflow: visible;\n}\n\n/**\n * Remove the inheritance of text transform in Edge, Firefox, and IE.\n * 1. Remove the inheritance of text transform in Firefox.\n */\n\nbutton,\nselect { /* 1 */\n  text-transform: none;\n}\n\n/* Reset button and button-style input default styles */\ninput[type=\"submit\"],\ninput[type=\"reset\"],\ninput[type=\"button\"],\nbutton {\n    background: none;\n    border: 0;\n    color: inherit;\n    cursor: default;\n    font: inherit;\n    line-height: normal;\n    overflow: visible;\n    padding: 0;\n    -webkit-appearance: none; /* for input */\n    -webkit-user-select: none; /* for button */\n       -moz-user-select: none;\n        -ms-user-select: none;\n}\ninput::-moz-focus-inner,\nbutton::-moz-focus-inner {\n    border: 0;\n    padding: 0;\n}\n\n/**\n * 1. Prevent a WebKit bug where (2) destroys native audio and video\n *    controls in Android 4.\n * 2. Correct the inability to style clickable types in iOS and Safari.\n */\n\nbutton,\nhtml [type=\"button\"], /* 1 */\n[type=\"reset\"],\n[type=\"submit\"] {\n  -webkit-appearance: none; /* 2 */\n}\n\n/**\n * Remove the inner border and padding in Firefox.\n */\n\nbutton::-moz-focus-inner,\n[type=\"button\"]::-moz-focus-inner,\n[type=\"reset\"]::-moz-focus-inner,\n[type=\"submit\"]::-moz-focus-inner {\n  border-style: none;\n  padding: 0;\n}\n\n/**\n * Restore the focus styles unset by the previous rule.\n */\n\nbutton:-moz-focusring,\n[type=\"button\"]:-moz-focusring,\n[type=\"reset\"]:-moz-focusring,\n[type=\"submit\"]:-moz-focusring {\n  outline: 1px dotted ButtonText;\n}\n\n\n/**\n * 1. Correct the text wrapping in Edge and IE.\n * 2. Correct the color inheritance from fieldset elements in IE.\n * 3. Remove the padding so developers are not caught out when they zero out\n *    fieldset elements in all browsers.\n */\n\nlegend {\n  box-sizing: border-box; /* 1 */\n  color: inherit; /* 2 */\n  display: table; /* 1 */\n  max-width: 100%; /* 1 */\n  padding: 0; /* 3 */\n  white-space: normal; /* 1 */\n}\n\n/**\n * Remove the default vertical scrollbar in IE.\n */\n\ntextarea {\n  overflow: auto;\n}\n\n/**\n * 1. Add the correct box sizing in IE 10-.\n * 2. Remove the padding in IE 10-.\n */\n\n[type=\"checkbox\"],\n[type=\"radio\"] {\n  box-sizing: border-box; /* 1 */\n  padding: 0; /* 2 */\n}\n\n/**\n * Correct the cursor style of increment and decrement buttons in Chrome.\n */\n\n[type=\"number\"]::-webkit-inner-spin-button,\n[type=\"number\"]::-webkit-outer-spin-button {\n  height: auto;\n}\n\n/**\n * 1. Correct the odd appearance in Chrome and Safari.\n * 2. Correct the outline style in Safari.\n */\n\n[type=\"search\"] {\n  -webkit-appearance: textfield; /* 1 */\n  outline-offset: -2px; /* 2 */\n}\n\n/**\n * Remove the inner padding and cancel buttons in Chrome and Safari on OS X.\n */\n\n[type=\"search\"]::-webkit-search-cancel-button,\n[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\n\n/**\n * Correct the text style of placeholders in Chrome, Edge, and Safari.\n */\n\n::-webkit-input-placeholder {\n  color: inherit;\n  opacity: 0.54;\n}\n\n/**\n * 1. Correct the inability to style clickable types in iOS and Safari.\n * 2. Change font properties to inherit in Safari.\n */\n\n::-webkit-file-upload-button {\n  -webkit-appearance: none; /* 1 */\n  font: inherit; /* 2 */\n}\n`;\n"
  },
  {
    "path": "packages/site/styles/syntax-highlighting.js",
    "content": "import { BLACK, BRAND, ENTITY, ACTION, cols } from './vars';\n\nconst createTheme = ({ fontSize = 14, lineHeight = 20, width = '100%' }) => ({\n  hljs: {\n    display: 'block',\n    overflowX: 'auto',\n    padding: cols(1),\n    color: BLACK,\n    fontSize: `${fontSize}px`,\n    lineHeight: `${lineHeight}px`,\n    width,\n  },\n  'hljs-comment': {\n    opacity: 0.5,\n  },\n  'hljs-keyword': {\n    color: ENTITY,\n  },\n  'hljs-name': {\n    color: ACTION,\n  },\n  'hljs-number': {\n    color: BRAND,\n  },\n  'hljs-params': {\n    color: ACTION,\n  },\n  'hljs-string': {\n    color: BRAND,\n  },\n  'hljs-attribute': {\n    color: BRAND,\n  },\n  'hljs-function': {\n    color: ACTION,\n  },\n});\n\nexport const prismTheme = `\n.token {\n  color: ${BLACK};\n  &.string {\n    color: ${BRAND};\n  }\n  &.keyword {\n    color: ${ENTITY};\n  }\n  &.comment {\n    opacity: 0.5;\n  }\n  &.number {\n    color: ${BRAND};\n  }\n  &.function {\n    color: ${ACTION};\n  }\n}\n`;\n\nexport const codeTheme = createTheme({});\nexport const codeThemeLarge = createTheme({\n  fontSize: 14,\n  lineHeight: 20,\n  width: '85%',\n});\n"
  },
  {
    "path": "packages/site/styles/themes.js",
    "content": "import menus from '~/data/menus.json';\nimport content from '~/data/content.json';\nimport PopmotionLogo from '~/components/icons/Logo';\nimport PoseLogo from '~/components/icons/PoseLogo';\nimport PureLogo from '~/components/icons/PopmotionPure';\nimport StylefireLogo from '~/components/icons/StylefireLogo';\nimport FramesyncLogo from '~/components/icons/FramesyncLogo';\nimport { color } from './vars';\nimport PopcornLogo from '../components/icons/PopcornLogo';\n\nconst generateTheme = (name, props) => ({\n  data: {\n    menus: menus[name] || menus.pure, // Hack while blog is being published under popmotion\n    content: content[name] || content.pure,\n    rootUrl: name === 'popmotion' ? '/' : `/${name}`,\n  },\n  ...props,\n});\n\nconst themeSettings = {\n  framerMotion: {\n    id: 'framer-motion',\n    name: 'Framer Motion',\n    tagline: 'A truly simple React animation and gesture library.',\n    url: 'https://framer.com/motion',\n    color: {\n      base: '#f08',\n      baseShadow: '#c0c',\n      twist: '#d0e',\n      action: '#09f',\n      actionHighlight: '#09f',\n    },\n    Logo: () => (\n      <svg\n        xmlns=\"http://www.w3.org/2000/svg\"\n        width=\"80px\"\n        viewBox=\"0 0 100 100\"\n      >\n        <defs>\n          <linearGradient id=\"pink\" gradientTransform=\"rotate(90 .5 .5)\">\n            <stop offset=\"0\" stopColor=\"#f08\"></stop>\n            <stop offset=\"1\" stopColor=\"#d0e\"></stop>\n          </linearGradient>\n          <linearGradient id=\"purple\" gradientTransform=\"rotate(90 .5 .5)\">\n            <stop offset=\"0\" stopColor=\"#09f\"></stop>\n            <stop offset=\"1\" stopColor=\"#40f\"></stop>\n          </linearGradient>\n          <linearGradient id=\"blue\" gradientTransform=\"rotate(90 .5 .5)\">\n            <stop offset=\"0\" stopColor=\"#09f\"></stop>\n            <stop offset=\"1\" stopColor=\"#09f\"></stop>\n          </linearGradient>\n        </defs>\n        <path d=\"M0 100V0l50 50z\" fill=\"url(#pink)\"></path>\n        <path d=\"M100 0v50l-50 50-25-25z\" fill=\"url(#purple)\"></path>\n        <path d=\"M100 50v50L75 75z\" fill=\"url(#blue)\"></path>\n      </svg>\n    ),\n  },\n  popmotion: {\n    id: 'popmotion',\n    name: 'Popmotion',\n    url: '/',\n    tagline: 'Simple libraries for delightful interfaces',\n    headerNavLinks: [\n      {\n        href: '/blog',\n        label: 'Blog',\n        id: 'blog',\n      },\n    ],\n    Logo: PopmotionLogo,\n    homepageLogoSize: {\n      width: 283,\n      height: 64,\n    },\n    headerLogoSize: {\n      width: 124,\n      height: 29,\n    },\n    footerLogoSize: {\n      width: 215,\n      height: 43,\n    },\n    color: {\n      base: '#FF1C68',\n      baseShadow: '#810066',\n      twist: '#960076',\n      action: '#049CD4',\n      actionHighlight: '#252942',\n    },\n    // Deprecated colors\n    actionColor: color.blue,\n    brandColor: color.brand,\n\n    mastheadBackground: `linear-gradient(${color.brand}, ${color.brandBurn})`,\n    shareImage: 'https://popmotion.io/images/twitter-card.png',\n  },\n  pose: {\n    id: 'pose',\n    name: 'Pose',\n    url: '/pose',\n    tagline: 'Declarative motion system for React, React Native, and Vue',\n    sections: ['api', 'learn', 'examples'],\n    headerNavLinks: [\n      {\n        href: '/pose/api',\n        label: 'API',\n        id: 'api',\n      },\n      {\n        href: '/pose/learn/get-started',\n        label: 'Learn',\n        id: 'learn',\n      },\n      {\n        href: '/pose/examples',\n        label: 'Examples',\n        id: 'examples',\n      },\n    ],\n    Logo: PoseLogo,\n    homepageLogoSize: {\n      width: 175,\n      height: 53,\n    },\n    headerLogoSize: {\n      width: 127,\n      height: 40,\n    },\n    footerLogoSize: {\n      width: 193,\n      height: 70,\n    },\n    mastheadBackground: `linear-gradient(${color.pink}, ${color.purple})`,\n    color: {\n      base: '#ED00BB',\n      baseShadow: '#5B0089',\n      twist: '#A100F6',\n      action: '#0866C2',\n    },\n    // Deprecated colors\n    actionColor: color.blue,\n    brandColor: color.purple,\n    shareImage: 'https://popmotion.io/images/pose-twitter-card.png',\n  },\n  pure: {\n    id: 'pure',\n    name: 'Popmotion Pure',\n    url: '/pure',\n    tagline: 'A functional, flexible JavaScript motion library',\n    sections: ['api', 'learn'],\n    headerNavLinks: [\n      {\n        href: '/api',\n        label: 'API',\n        id: 'api',\n      },\n      {\n        href: '/learn/get-started',\n        label: 'Learn',\n        id: 'learn',\n      },\n    ],\n    Logo: PureLogo,\n    homepageLogoSize: {\n      width: 140,\n      height: 65,\n    },\n    headerLogoSize: {\n      width: 106,\n      height: 50,\n    },\n    footerLogoSize: {\n      width: 150,\n      height: 70,\n    },\n    color: {\n      base: '#FF1C68',\n      baseShadow: '#810066',\n      twist: '#960076',\n      action: '#0866C2',\n    },\n    // Deprecated colors\n    actionColor: color.blue,\n    brandColor: color.brand,\n\n    mastheadBackground: `linear-gradient(${color.brand}, ${color.brandBurn})`,\n    shareImage: 'https://popmotion.io/images/twitter-card.png',\n  },\n  stylefire: {\n    id: 'stylefire',\n    name: 'Stylefire',\n    url: '/stylefire',\n    tagline: 'Simple HTML & SVG styler, optimised for animation',\n    sections: ['api'],\n    headerNavLinks: [\n      {\n        href: '/stylefire/api',\n        label: 'API',\n        id: 'api',\n      },\n    ],\n    Logo: StylefireLogo,\n    homepageLogoSize: {\n      width: 204,\n      height: 54,\n    },\n    headerLogoSize: {\n      width: 130,\n      height: 36,\n    },\n    footerLogoSize: {\n      width: 188,\n      height: 55,\n    },\n    mastheadBackground: `linear-gradient(${color.orange}, ${color.orangeBurn})`,\n    color: {\n      base: '#FFE400',\n      baseShadow: '#CB4300',\n      twist: '#FF6A25',\n      action: '#0866C2',\n    },\n    // Deprecated colors\n    actionColor: color.orangeBurn,\n    brandColor: color.orange,\n    shareImage: 'https://popmotion.io/images/pose-twitter-card.png',\n  },\n  popcorn: {\n    id: 'popcorn',\n    name: 'Popcorn',\n    url: '/popcorn',\n    tagline: 'Utility functions for animation and interaction designers.',\n    sections: ['api'],\n    headerNavLinks: [\n      {\n        href: '/popcorn',\n        label: 'API',\n        id: 'api',\n      },\n    ],\n    Logo: PopcornLogo,\n    homepageLogoSize: {\n      width: 190,\n      height: 45,\n    },\n    headerLogoSize: {\n      width: 140,\n      height: 33,\n    },\n    footerLogoSize: {\n      width: 210,\n      height: 50,\n    },\n    color: {\n      base: '#95FF13',\n      baseShadow: '#00CF93',\n      twist: '#00CF93',\n      action: '#06A69D',\n    },\n    shareImage: 'https://popmotion.io/images/twitter-card-popcorn.png',\n  },\n  framesync: {\n    id: 'framesync',\n    name: 'Framesync',\n    url: '/api/framesync',\n    tagline: 'Unity-inspired render loop for browsers',\n    headerNavLinks: [],\n    Logo: FramesyncLogo,\n    homepageLogoSize: {\n      width: 190,\n      height: 40,\n    },\n    headerLogoSize: {\n      width: 127,\n      height: 40,\n    },\n    footerLogoSize: {\n      width: 240,\n      height: 50,\n    },\n    mastheadBackground: `linear-gradient(${color.pink}, ${color.purple})`,\n    color: {\n      base: '#00CDE5',\n      baseShadow: '#012A52',\n      twist: '#0866C2',\n      action: '#0866C2',\n    },\n    // Deprecated colors\n    actionColor: color.blue,\n    brandColor: color.purple,\n    shareImage: 'https://popmotion.io/images/pose-twitter-card.png',\n  },\n};\n\nexport default Object.keys(themeSettings).reduce((compiledThemes, name) => {\n  compiledThemes[name] = generateTheme(name, themeSettings[name]);\n  return compiledThemes;\n}, {});\n"
  },
  {
    "path": "packages/site/styles/vars.js",
    "content": "import { css } from 'styled-components';\n\nexport const verticalGradient = (from, to, start = 0, end = 100) =>\n  `linear-gradient(to bottom, ${from} ${start}%, ${to} ${end}%)`;\n\n// Deprecated - migrate to single `color` export\nexport const WHITE = '#fff';\nexport const BLACK = '#3d454e';\nexport const SUPER_LIGHT_GREY = '#FAFAFA';\nexport const LIGHT_GREY = '#f2f2f2';\n\nexport const PINK = '#FF1C68';\nexport const PINK_BURN = '#DB0068';\n\nexport const BLUE = '#09f';\nexport const BLUE_BURN = '#064FB5';\n\nexport const GREEN = '#14D790';\nconst PURPLE = '#9B65DE';\n\nexport const BRAND = PINK;\nexport const BRAND_BURN = PINK_BURN;\nexport const BRAND_GRADIENT = verticalGradient(PINK, PINK_BURN);\n\nexport const ACTION = BLUE;\nexport const ACTION_BURN = BLUE_BURN;\nexport const ACTION_GRADIENT = verticalGradient(BLUE, BLUE_BURN);\n\nexport const ENTITY = PURPLE;\n\nexport const color = {\n  black: '#252942',\n  blue: '#09f',\n  green: '#14D790',\n  white: '#fff',\n  pink: '#FF00C8',\n  purple: '#A100F6',\n  brand: '#FF1C68',\n  brandBurn: '#960076',\n  orange: '#F30',\n  orangeBurn: '#FF8213',\n  yellow: '#FFE42B',\n  grey: '#5E606C',\n  lightGrey: '#ECECEC',\n  superLightGrey: '#fafafa',\n};\n\nexport const font = {\n  body: `\n    font-family: 'PT Sans', sans-serif;\n    font-weight: 400;\n  `,\n  code: `\n    font-family: 'Inconsolata', monospace;\n    font-weight: 400;\n  `,\n  bold: `font-weight: 700;`,\n};\n\nexport const SKEW = '-5.7deg';\nexport const UNSKEW = '5.7deg';\n\nconst COL_WIDTH = 15;\n\nexport const cols = (num) => `${num * COL_WIDTH}px`;\n\nconst breakpoints = {\n  large: cols(72),\n  medium: cols(50),\n  small: cols(26),\n};\n\nexport const media = Object.keys(breakpoints).reduce((acc, label) => {\n  acc[label] = (...args) => css`\n    @media (max-width: ${breakpoints[label]}) {\n      ${css(...args)};\n    }\n  `;\n\n  return acc;\n}, {});\n"
  },
  {
    "path": "packages/site/templates/Popcorn/index.js",
    "content": "import ContentTemplate from '~/templates/content/Template';\nimport Footer from '~/templates/global-new/Footer';\nimport { createElement } from 'react';\nimport settings from '~/data/settings.json';\nimport docs from '~/docs/popcorn/index.md';\nimport marksy from 'marksy/components';\nimport SiteLink from '~/components/layout/SiteLink';\nimport styled from 'styled-components';\nimport { CTA } from '../Popmotion/Masthead/styled';\nimport {\n  A,\n  H1,\n  H2,\n  H3,\n  H4,\n  H5,\n  P,\n  Li,\n  Ol,\n  Ul,\n  Hr,\n  Code,\n  Blockquote,\n  ArticleHeader,\n  Video\n} from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\n\nconst Container = styled.article`\n  padding-top: 30px;\n`;\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote\n  }\n});\n\nconst { tree, toc } = convertMarkdown(docs);\n\nexport default () => (\n  <ContentTemplate\n    id=\"popcorn\"\n    section=\"api\"\n    title=\"Popcorn is a collection of utility functions for JavaScript animation\"\n    description=\"Popcorn is the Lodash of animation. It contains functions for easing, geometry, time and interpolation, \"\n    theme=\"popcorn\"\n  >\n    {tree}\n  </ContentTemplate>\n);\n"
  },
  {
    "path": "packages/site/templates/Popmotion/FinalCTA/index.js",
    "content": "import { Container, ContentContainer } from './styled';\nimport { BlurbText } from '~/templates/Popmotion/USPs/styled';\nimport { CTA } from '../Masthead/styled';\nimport Link from 'next/link';\n\nexport default () => (\n  <Container>\n    <ContentContainer>\n      <BlurbText style={{ marginBottom: 40, maxWidth: '600px' }}>\n        Pick and choose any part of Popmotion by importing modules individually.\n      </BlurbText>\n      <BlurbText style={{ marginBottom: 40, maxWidth: '600px' }}>\n        Or take it all for 11.7kb!\n      </BlurbText>\n      <CTA brandFill>\n        <Link href=\"/learn/get-started\" prefetch>\n          <a>Get started</a>\n        </Link>\n      </CTA>\n    </ContentContainer>\n  </Container>\n);\n"
  },
  {
    "path": "packages/site/templates/Popmotion/FinalCTA/styled.js",
    "content": "import styled from 'styled-components';\nimport { Centered } from '~/templates/global/grid';\nimport { cols, LIGHT_GREY } from '~/styles/vars';\n\nexport const Container = styled.section`\n  padding-top: ${cols(4)};\n  border-top: ${LIGHT_GREY} 1px solid;\n  border-bottom: none;\n`;\n\nexport const ContentContainer = styled(Centered)`\n  display: flex;\n  flex-direction: column;\n  margin: 0 auto;\n`;\n"
  },
  {
    "path": "packages/site/templates/Popmotion/Header/index.js",
    "content": "import SplitText from 'react-pose-text';\nimport styled from 'styled-components';\nimport { ActionLink } from '~/templates/global-new/styled';\nimport { color, media } from '~/styles/vars';\n\nconst Container = styled.div`\n  height: 320px;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  text-align: center;\n  flex-direction: column;\n\n  ${media.medium`height: 180px;`} ${media.small`height: 140px;`};\n`;\n\nconst HeaderText = styled.h2`\n  margin-bottom: 30px;\n\n  ${media.medium`margin-bottom: 15px`};\n\n  div {\n    text-shadow: 0 1px 1px rgba(0, 0, 0, 0.12);\n    color: ${color.white};\n    font-size: 24px;\n    font-weight: 700;\n\n    ${media.medium`\n      font-size: 22px;`};\n    ${media.small`\n      font-size: 18px;`};\n  }\n`;\n\nconst charPoses = {\n  hidden: { opacity: 0, y: 10 },\n  visible: {\n    opacity: 1,\n    y: 0,\n    delay: ({ charIndex }) => charIndex * 10\n  }\n};\n\nexport default () => (\n  <Container>\n    <HeaderText>\n      <SplitText charPoses={charPoses} initialPose=\"hidden\" pose=\"visible\">\n        A functional, flexible JavaScript animation library\n      </SplitText>\n    </HeaderText>\n    <ActionLink white cta href=\"/learn/get-started\" preload>\n      Get started\n    </ActionLink>\n  </Container>\n);\n"
  },
  {
    "path": "packages/site/templates/Popmotion/Masthead/index.js",
    "content": "import { withTheme } from 'styled-components';\nimport SiteLink from '~/components/layout/SiteLink';\nimport {\n  Container,\n  MastheadContainer,\n  Title,\n  Logo,\n  LogoContainer,\n  LogoText,\n  Blurb,\n  CTA\n} from './styled';\nimport Link from 'next/link';\n\nconst Masthead = ({ children, theme, getStarted = true }) => (\n  <Container>\n    {children}\n    <MastheadContainer>\n      <Title>\n        <LogoText>{theme.name}</LogoText>\n        <LogoContainer {...theme.homepageLogoSize}>\n          <theme.Logo id=\"homepage-logo\" />\n        </LogoContainer>\n      </Title>\n      <Blurb>{theme.tagline}</Blurb>\n      {getStarted ? (\n        <CTA>\n          <SiteLink href=\"/learn/get-started\" prefetch>\n            Quick start\n          </SiteLink>\n        </CTA>\n      ) : null}\n    </MastheadContainer>\n  </Container>\n);\n\nexport default withTheme(Masthead);\n"
  },
  {
    "path": "packages/site/templates/Popmotion/Masthead/styled.js",
    "content": "import styled, { css } from 'styled-components';\nimport {\n  WHITE,\n  BLACK,\n  ACTION_GRADIENT,\n  ACTION_BURN,\n  LIGHT_GREY,\n  UNSKEW,\n  SKEW,\n  cols,\n  media,\n  color\n} from '~/styles/vars';\nimport { fontSize, fontBold } from '~/styles/fonts';\n\nexport const Container = styled.section`\n  background: ${({ theme }) => theme.mastheadBackground};\n  z-index: 0;\n\n  svg path {\n    fill: ${WHITE};\n  }\n\n  li a:hover {\n    color: ${WHITE};\n  }\n`;\n\nexport const MastheadContainer = styled.section`\n  display: flex;\n  flex-direction: column;\n  flex-align: center;\n  justify-content: center;\n  text-align: center;\n  margin: 0 ${cols(4)};\n  padding-bottom: ${cols(4)};\n  position: relative;\n  z-index: 1;\n\n  ${media.medium`\n    margin: 0 ${cols(2)};\n    padding-bottom: ${cols(2)};\n  `};\n`;\n\nexport const Title = styled.h1`\n  display: block;\n  overflow: hidden;\n  margin-bottom: ${cols(1)};\n`;\n\nexport const LogoContainer = styled.div`\n  svg {\n    ${({ width, height }) => `\n      width: ${width}px!important; // eugh\n      height: ${height}px!important;\n    `};\n  }\n\n  ${media.medium`\n    svg {\n      ${({ width, height }) => `\n        width: ${width * 0.75}px!important;\n        height: ${height * 0.75}px!important;\n      `}\n    }\n  `};\n\n  ${media.small`\n    svg {\n      ${({ width, height }) => `\n        width: ${width * 0.6}px!important;\n        height: ${height * 0.6}px!important;\n      `}\n    }\n  `};\n`;\n\nexport const LogoText = styled.div`\n  width: 0px;\n  height: 0px;\n  text-indent: -9999px;\n`;\n\nexport const Blurb = styled.h2`\n  ${fontSize(24)}\n  ${fontBold}\n  margin-bottom: ${cols(3)};\n  color: ${WHITE};\n  \n  ${media.medium`\n    ${fontSize(18)}\n    margin-bottom: ${cols(2)};\n  `}\n`;\n\nexport const CTA = styled.div`\n  background: ${WHITE};\n  margin: 0 auto;\n  display: flex;\n  transform: skewX(${SKEW});\n  transition: transform 100ms cubic-bezier(.17,.67,.34,1.54);\n  box-shadow: 0 2px 0 0 black;\n  justify-content: stretch;\n\n  &:hover {\n    transform: skewX(${SKEW}) scale(1.1);\n  }\n\n  a, button {\n    ${fontSize(24)}\n    ${fontBold}\n    color: ${BLACK};\n    cursor: pointer;\n    text-decoration: none;\n    padding: ${cols(1)} ${cols(2)};\n    transform: skewX(${UNSKEW});\n    text-align: center;\n    display: block;\n    width: 100%;\n  }\n\n  ${media.medium`\n    a {\n      ${fontSize(18)}\n    }\n  `}\n  \n  ${props =>\n    props.brandFill &&\n    css`\n      background: ${props.theme.actionColor};\n\n      a {\n        color: ${color.white};\n      }\n    `};\n`;\n"
  },
  {
    "path": "packages/site/templates/Popmotion/USPs/Example.js",
    "content": "import {\n  ExampleContainer,\n  ExampleHeader,\n  Description,\n  CenteredContent\n} from './styled';\nimport Link from 'next/link';\n\nexport default ({ title, children, link, description }) => (\n  <ExampleContainer>\n    <CenteredContent>\n      <ExampleHeader>\n        {link ? (\n          <Link href={link}><a>{title}</a></Link>\n        ) : title}\n      </ExampleHeader>\n      <Description>{description}</Description>\n    </CenteredContent>\n    {children}\n  </ExampleContainer>\n);"
  },
  {
    "path": "packages/site/templates/Popmotion/USPs/ExampleSection.js",
    "content": "import { SectionContainer, SectionHeader } from './styled';\n\nexport default ({ title, children }) => (\n  <SectionContainer>\n    {title && <SectionHeader>{title}</SectionHeader>}\n    {children}\n  </SectionContainer>\n);"
  },
  {
    "path": "packages/site/templates/Popmotion/USPs/index.js",
    "content": "import { Container, Blurb } from './styled';\n\nexport default () => (\n  <Container>\n    <Blurb>These are the legacy docs for Popmotion 8.</Blurb>\n  </Container>\n);\n"
  },
  {
    "path": "packages/site/templates/Popmotion/USPs/styled.js",
    "content": "import styled from 'styled-components';\nimport { cols, media } from '~/styles/vars';\nimport { Centered } from '~/templates/global/grid';\nimport { fontSize, lineHeight, fontBold } from '~/styles/fonts';\n\nconst MAX_WIDTH = cols(60);\n\nexport const Container = styled.section`\n  display: flex;\n  align-items: center;\n  flex-direction: column;\n`;\n\nconst BlurbContainer = styled(Centered)`\n  display: flex;\n  align-items: center;\n  padding: ${cols(1)};\n  margin-bottom: ${cols(4)};\n  width: 100%;\n\n  span {\n    background: #eee;\n    flex: 1;\n    height: 1px;\n  }\n\n  ${media.medium`\n  margin-bottom: ${cols(2)};\n  `};\n  ${media.small`\n    display: block;\n    span {\n      display: none;\n    }\n  `};\n`;\n\nexport const BlurbText = styled.p`\n  ${fontSize(24)}\n  ${lineHeight(32)}\n  max-width: ${cols(32)};\n  text-align: center;\n  padding-left: ${cols(2)};\n  padding-right: ${cols(2)};\n\n  ${media.medium`\n    ${fontSize(18)}\n    ${lineHeight(26)}\n    padding-left: ${cols(1)};\n    padding-right: ${cols(1)};\n  `}\n`;\n\nexport const Blurb = ({ children }) => (\n  <BlurbContainer>\n    <span />\n    <BlurbText>{children}</BlurbText>\n    <span />\n  </BlurbContainer>\n);\n\nexport const SectionContainer = styled.section`\n  width: 100%;\n  margin-bottom: ${cols(2)};\n  overflow-x: hidden;\n`;\n\nexport const SectionHeader = styled.h2`\n  ${fontSize(48)} ${fontBold}\n  text-align: center;\n  margin-bottom: ${cols(2)};\n\n  ${media.medium`\n    ${fontSize(36)}\n  `} ${media.small`\n    ${fontSize(28)}\n  `};\n`;\n\nexport const ExampleContainer = styled.div`\n  margin-bottom: ${cols(2)};\n`;\n\nexport const ExampleHeader = styled.h3`\n  ${fontSize(28)}\n  ${lineHeight(28)}\n  ${fontBold}\n  margin-bottom: ${cols(1)};\n  display: block;\n  width: 100%;\n\n  a {\n    ${fontBold}\n  }\n\n  ${media.medium`\n    ${fontSize(22)}\n    ${lineHeight(22)}\n  `}\n  \n  ${media.small`\n    ${fontSize(18)}\n    ${lineHeight(18)}\n  `}\n`;\n\nexport const Description = styled.p`\n  ${fontSize(18)} ${lineHeight(28)}\n  width: 50%;\n\n  ${media.medium`\n    width: 100%;\n  `} ${media.small`\n    ${fontSize(14)}\n    ${lineHeight(22)}\n    width: 100%;\n  `};\n`;\n\nexport const LiveContainer = styled.div``;\n\nexport const CenteredContent = styled.div`\n  max-width: ${MAX_WIDTH};\n  margin: 0 auto;\n  display: flex;\n  flex-direction: column;\n\n  ${media.large`\n    margin: 0 ${cols(1)}\n  `};\n`;\n"
  },
  {
    "path": "packages/site/templates/Popmotion/index.js",
    "content": "import Homepage from '~/templates/homepage';\nimport Header from './Header';\nimport Footer from '~/templates/global-new/Footer';\n\nexport default () => (\n  <Homepage\n    title=\"Popmotion 8 | A functional, flexible JavaScript animation library\"\n    theme=\"pure\"\n    Header={Header}\n  >\n    <Footer />\n  </Homepage>\n);\n"
  },
  {
    "path": "packages/site/templates/Pose/Header/index.js",
    "content": "import SplitText from 'react-pose-text';\nimport styled from 'styled-components';\nimport { ActionLink } from '~/templates/global-new/styled';\nimport { color, media } from '~/styles/vars';\n\nconst Container = styled.div`\n  height: 320px;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  text-align: center;\n  flex-direction: column;\n\n  ${media.medium`height: 180px;`} ${media.small`height: 140px;`};\n`;\n\nconst HeaderText = styled.h2`\n  margin-bottom: 30px;\n\n  ${media.medium`margin-bottom: 15px`};\n\n  div {\n    text-shadow: 0 1px 1px rgba(0, 0, 0, 0.12);\n    color: ${color.white};\n    font-size: 24px;\n    font-weight: 700;\n\n    ${media.medium`\n      font-size: 22px;`};\n    ${media.small`\n      font-size: 18px;`};\n  }\n`;\n\nconst charPoses = {\n  hidden: { opacity: 0, y: 10 },\n  visible: {\n    opacity: 1,\n    y: 0,\n    delay: ({ charIndex }) => charIndex * 10\n  }\n};\n\nexport default () => (\n  <Container>\n    <HeaderText>\n      <SplitText charPoses={charPoses} initialPose=\"hidden\" pose=\"visible\">\n        A truly simple animation library for React, React Native, and Vue\n      </SplitText>\n    </HeaderText>\n    <ActionLink white cta href=\"/pose/learn/get-started\" prefetch>\n      Get started\n    </ActionLink>\n  </Container>\n);\n"
  },
  {
    "path": "packages/site/templates/Pose/USPs/AnimateAnything.js",
    "content": "import Template from '~/templates/Popmotion/LiveExamples/Template';\nimport {\n  Carousel,\n  Item,\n  AlignCenter\n} from '~/templates/Popmotion/LiveExamples/styled';\nimport { styler, value, listen, pointer, decay, transform } from 'popmotion';\nimport posed from 'react-pose';\nimport styled from 'styled-components';\nimport { color } from '~/styles/vars';\n\nconst props = {\n  rest: {\n    x: 0,\n    y: 0,\n    background: 'rgba(161, 0, 246, 0)',\n    boxShadow: '0px 0px 0px rgba(0, 0, 0, 0)',\n    transition: { duration: 700 }\n  },\n  popped: {\n    x: -10,\n    y: -10,\n    background: 'rgba(161, 0, 246, 1)',\n    boxShadow: '10px 10px 20px rgba(161, 0, 246, 0.2)',\n    transition: { duration: 700 }\n  }\n};\n\nconst Box = styled(posed.div(props))`\n  width: 100px;\n  height: 100px;\n`;\n\nconst code = `popped: {\n  x: -10,\n  y: -10,\n  background: 'rgba(161, 0, 246, 1)',\n  boxShadow: '10px 10px 20px rgba(161, 0, 246, 0.2)',\n  transition: { duration: 700 }\n}`;\n\nclass Example extends React.Component {\n  state = { isVisible: false };\n\n  componentDidMount() {\n    this.interval = setInterval(this.toggleVisibility, 1000);\n  }\n\n  componentWillUnmount() {\n    clearInterval(this.interval);\n  }\n\n  toggleVisibility = () => this.setState({ isVisible: !this.state.isVisible });\n\n  render() {\n    return <Box pose={this.state.isVisible ? 'popped' : 'rest'} />;\n  }\n}\n\nexport default () => (\n  <Template code={code}>\n    <AlignCenter>\n      <Example />\n    </AlignCenter>\n  </Template>\n);\n"
  },
  {
    "path": "packages/site/templates/Pose/USPs/ChildrenExample.js",
    "content": "import Template from '~/templates/Popmotion/LiveExamples/Template';\nimport { AlignCenter } from '~/templates/Popmotion/LiveExamples/styled';\nimport {\n  styler,\n  spring,\n  value,\n  listen,\n  tween,\n  pointer,\n  decay,\n  transform\n} from 'popmotion';\nimport posed from 'react-pose';\nimport styled from 'styled-components';\nimport { color } from '~/styles/vars';\nimport { eachValue } from 'popmotion-pose';\n\nconst Container = styled.div`\n  overflow: hidden;\n`;\n\nconst sidepanelProps = {\n  closed: {\n    x: '-100%'\n  },\n  open: {\n    x: '0%',\n    delayChildren: 100,\n    staggerChildren: 60\n  }\n};\n\nconst itemProps = {\n  closed: {\n    y: 20,\n    opacity: 0\n  },\n  open: {\n    y: 0,\n    opacity: 1\n  }\n};\n\nconst Sidepanel = styled(posed.ul(sidepanelProps))`\n  background: ${color.blue};\n  width: 300px;\n  padding: 20px;\n`;\n\nconst Item = styled(posed.li(itemProps))`\n  width: 100%;\n  border-radius: 5px;\n  height: 35px;\n  background: ${color.white};\n  margin-bottom: 10px;\n\n  &:last-child {\n    margin-bottom: 0;\n  }\n`;\n\nconst code = {\n  react: `const Parent = posed.ul(config)\nconst Child = posed.li(childConfig)\n\n({ items }) => (\n  <Parent pose=\"open\">\n    {items.map(item => <Child />)}\n  </Parent>\n)\n`,\n  vue: `const Component = {\n  components: {\n    Parent: posed.ul(config),\n    Child: posed.li(childConfig)\n  },\n  template: \\`<Parent :pose=\"isOpen ? 'open' : 'closed'\">\n    <Child v-for=\"item in items\" />\n  </Parent>\\`\n}`\n};\n\nclass Example extends React.Component {\n  state = { isVisible: false };\n\n  componentDidMount() {\n    this.interval = setInterval(this.toggleVisibility, 2000);\n  }\n\n  componentWillUnmount() {\n    clearInterval(this.interval);\n  }\n\n  toggleVisibility = () => this.setState({ isVisible: !this.state.isVisible });\n\n  render() {\n    return (\n      <Container>\n        <Sidepanel pose={this.state.isVisible ? 'open' : 'closed'}>\n          <Item key={0} />\n          <Item key={1} />\n          <Item key={2} />\n          <Item key={3} />\n        </Sidepanel>\n      </Container>\n    );\n  }\n}\n\nexport default props => (\n  <Template code={code} {...props}>\n    <AlignCenter>\n      <Example />\n    </AlignCenter>\n  </Template>\n);\n"
  },
  {
    "path": "packages/site/templates/Pose/USPs/CustomExample.js",
    "content": "import Template from '~/templates/Popmotion/LiveExamples/Template';\nimport {\n  Carousel,\n  Item,\n  AlignCenter\n} from '~/templates/Popmotion/LiveExamples/styled';\nimport {\n  styler,\n  spring,\n  value,\n  listen,\n  tween,\n  pointer,\n  decay,\n  transform\n} from 'popmotion';\nimport posed from 'react-pose';\nimport styled from 'styled-components';\nimport { color } from '~/styles/vars';\n\nconst props = {\n  rest: {\n    scale: 1,\n    backgroundColor: color.green\n  },\n  alert: {\n    scale: 1.3,\n    transition: {\n      scale: props => spring({ ...props, stiffness: 200, damping: 0 }),\n      backgroundColor: tween\n    }\n  }\n};\n\nconst Box = styled(posed.div(props))`\n  width: 100px;\n  height: 100px;\n  background: ${color.green};\n  border-radius: 50%;\n  transform: scaleX(0);\n  transform-origin: 50%;\n`;\n\nconst code = `const Circle = posed.div({\n  attention: {\n    scale: 1.3,\n    transition: {\n      type: 'spring',\n      stiffness: 200,\n      damping: 0\n    }\n  }\n})`;\n\nclass Example extends React.Component {\n  state = { isVisible: false };\n\n  componentDidMount() {\n    this.interval = setInterval(this.toggleVisibility, 2000);\n  }\n\n  componentWillUnmount() {\n    clearInterval(this.interval);\n  }\n\n  toggleVisibility = () => this.setState({ isVisible: !this.state.isVisible });\n\n  render() {\n    return <Box pose={this.state.isVisible ? 'alert' : 'rest'} />;\n  }\n}\n\nexport default () => (\n  <Template code={code}>\n    <AlignCenter>\n      <Example />\n    </AlignCenter>\n  </Template>\n);\n"
  },
  {
    "path": "packages/site/templates/Pose/USPs/DeclarativeExample.js",
    "content": "import Template from '~/templates/Popmotion/LiveExamples/Template';\nimport {\n  Carousel,\n  Item,\n  AlignCenter\n} from '~/templates/Popmotion/LiveExamples/styled';\nimport { styler, value, listen, pointer, decay, transform } from 'popmotion';\nimport posed from 'react-pose';\nimport styled from 'styled-components';\nimport { color } from '~/styles/vars';\n\nconst props = {\n  open: { scale: 1 },\n  closed: { scale: 0 }\n};\n\nconst Box = styled(posed.div(props))`\n  width: 100px;\n  height: 100px;\n  background: ${color.blue};\n  border-radius: 50%;\n  transform: scaleX(0);\n  transform-origin: 50%;\n`;\n\nconst code = {\n  react: `({ isOpen }) =>\n  <Component pose={isOpen ? 'open' : 'closed'} />`,\n  vue: `<template>\n  <Component :pose=\"isOpen ? 'open' : 'closed'\" />  \n</template>`\n};\n\nclass Example extends React.Component {\n  state = { isVisible: false };\n\n  componentDidMount() {\n    this.interval = setInterval(this.toggleVisibility, 1000);\n  }\n\n  componentWillUnmount() {\n    clearInterval(this.interval);\n  }\n\n  toggleVisibility = () => this.setState({ isVisible: !this.state.isVisible });\n\n  render() {\n    return <Box pose={this.state.isVisible ? 'open' : 'closed'} />;\n  }\n}\n\nexport default props => (\n  <Template code={code} {...props}>\n    <AlignCenter>\n      <Example />\n    </AlignCenter>\n  </Template>\n);\n"
  },
  {
    "path": "packages/site/templates/Pose/USPs/DraggableExample.js",
    "content": "import Template from '~/templates/Popmotion/LiveExamples/Template';\nimport {\n  Carousel,\n  Item,\n  AlignCenter\n} from '~/templates/Popmotion/LiveExamples/styled';\nimport {\n  styler,\n  value,\n  listen,\n  pointer,\n  decay,\n  spring,\n  transform\n} from 'popmotion';\nimport posed from 'react-pose';\nimport styled from 'styled-components';\nimport { color } from '~/styles/vars';\n\nconst props = {\n  hoverable: true,\n  draggable: 'x',\n  dragBounds: { left: '-100%', right: '100%' },\n  init: { scale: 1 },\n  hover: { scale: 1.2 },\n  drag: { scale: 1.1 }\n};\n\nconst Box = styled(posed.div(props))`\n  width: 100px;\n  height: 100px;\n  background: ${color.brand};\n  transform: scaleX(0);\n  transform-origin: 50%;\n  color: white;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  font-weight: bold;\n`;\n\nconst code = `const Box = posed.div({\n  hoverable: true,\n  draggable: 'x',\n  dragBounds: { left: '-100%', right: '100%' },\n  init: { scale: 1 },\n  hover: { scale: 1.2 },\n  drag: { scale: 1.1 }\n})`;\n\nclass Example extends React.Component {\n  render() {\n    return <Box pose={'init'}>Drag</Box>;\n  }\n}\n\nexport default () => (\n  <Template code={code}>\n    <AlignCenter>\n      <Example />\n    </AlignCenter>\n  </Template>\n);\n"
  },
  {
    "path": "packages/site/templates/Pose/USPs/FlipExample.js",
    "content": "import Template from '~/templates/Popmotion/LiveExamples/Template';\nimport {\n  Carousel,\n  Item,\n  AlignCenter\n} from '~/templates/Popmotion/LiveExamples/styled';\nimport { tween, value, listen, pointer, decay, transform } from 'popmotion';\nimport posed from 'react-pose';\nimport styled from 'styled-components';\nimport pose from 'popmotion-pose';\nimport { color } from '~/styles/vars';\n\nconst props = {\n  left: { height: '50px', left: '-50px' },\n  right: { height: '100px', left: '50px' }\n};\n\nconst code = `// Vanilla & React Pose only\nawait poser.set('childOut')\nawait poser.flip(() => {\n  poser.clearChildren()\n  parentElement.removeChild(parent.firstChild)\n  parentElement.appendChild(newChild)\n  poser.addChild(newChild, childProps)\n})\nposer.set('childIn')`;\n\nconst Modal = styled.div`\n  background: ${color.green};\n  width: 300px;\n  padding: 20px;\n  overflow: hidden;\n\n  > div {\n    background: white;\n    height: 40px;\n    margin-bottom: 10px;\n    opacity: 0;\n    border-radius: 5px;\n\n    &:last-child {\n      margin-bottom: 0;\n    }\n  }\n`;\n\nconst modalProps = {\n  itemsOut: {\n    staggerChildren: 50\n  }\n};\nconst modalItemProps = {\n  initialPose: 'itemsOut',\n  flip: {\n    transition: tween\n  },\n  itemsOut: {\n    x: -50,\n    opacity: 0,\n    transition: tween\n  },\n  itemsIn: {\n    x: 0,\n    opacity: 1,\n    transition: tween\n  }\n};\n\nclass Example extends React.Component {\n  a = [0, 1, 2, 3];\n  b = [4, 5, 6];\n\n  state = {\n    list: this.a\n  };\n\n  listRefs = new Set();\n\n  setContainerRef = ref => {\n    if (ref) {\n      this.ref = ref;\n    } else if (this.modalPoser) {\n      this.modalPoser.destroy();\n    }\n  };\n\n  setItemRef = ref => {\n    if (ref) {\n      this.listRefs.add(ref);\n    } else if (this.modalPoser) {\n      // remove\n    }\n  };\n\n  componentDidMount() {\n    this.modalPoser = pose(this.ref, modalProps);\n    this.listRefs.forEach(el => this.modalPoser.addChild(el, modalItemProps));\n    this.listRefs.clear();\n\n    this.modalPoser.set('itemsIn');\n\n    this.interval = setInterval(() => {\n      this.modalPoser.set('itemsOut').then(() => {\n        this.modalPoser.clearChildren();\n        this.modalPoser.measure();\n        this.setState({\n          list: this.state.list === this.a ? this.b : this.a\n        });\n      });\n    }, 5000);\n  }\n\n  componentWillUnmount() {\n    clearInterval(this.interval);\n  }\n\n  componentDidUpdate() {\n    this.listRefs.forEach(el => this.modalPoser.addChild(el, modalItemProps));\n    this.listRefs.clear();\n    this.modalPoser.flip().then(() => this.modalPoser.set('itemsIn'));\n  }\n\n  render() {\n    return (\n      <Modal ref={this.setContainerRef}>\n        {this.state.list.map(i => (\n          <div key={i} ref={this.setItemRef} />\n        ))}\n      </Modal>\n    );\n  }\n}\n\nexport default () => (\n  <Template code={code}>\n    <AlignCenter>\n      <Example />\n    </AlignCenter>\n  </Template>\n);\n"
  },
  {
    "path": "packages/site/templates/Pose/USPs/PassiveExample.js",
    "content": "import Template from '~/templates/Popmotion/LiveExamples/Template';\nimport {\n  Carousel,\n  Item,\n  AlignCenter\n} from '~/templates/Popmotion/LiveExamples/styled';\nimport { styler, value, listen, pointer, decay, transform } from 'popmotion';\nimport posed from 'react-pose';\nimport styled from 'styled-components';\nimport { color } from '~/styles/vars';\nconst { interpolate } = transform;\nconst props = {\n  draggable: 'x',\n  passive: {\n    opacity: ['x', interpolate([-200, -100, 100, 200], [0, 1, 1, 0])]\n  }\n};\n\nconst Box = styled(posed.div(props))`\n  width: 100px;\n  height: 100px;\n  background: ${color.blue};\n  border-radius: 50%;\n  transform: scaleX(0);\n  transform-origin: 50%;\n  color: white;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  font-weight: bold;\n`;\n\nconst code = `// React, Vue & vanilla use Popmotion's functional pipelines\npassive: {\n  opacity: ['x', interpolate(\n    [-200, -100, 100, 200],\n    [0, 1, 1, 0]\n  )]\n}\n\n// React Native uses React Animated's interpolate function\npassive: {\n  opacity: ['x', {\n    inputRange: [-200, -100, 100, 200],\n    outputRange: [0, 1, 1, 0]\n  }]\n}`;\n\nclass Example extends React.Component {\n  state = { isVisible: false };\n\n  componentDidMount() {\n    this.interval = setInterval(this.toggleVisibility, 1000);\n  }\n\n  componentWillUnmount() {\n    clearInterval(this.interval);\n  }\n\n  toggleVisibility = () => this.setState({ isVisible: !this.state.isVisible });\n\n  render() {\n    return <Box pose={this.state.isVisible ? 'open' : 'closed'}>Drag</Box>;\n  }\n}\n\nexport default () => (\n  <Template code={code}>\n    <AlignCenter>\n      <Example />\n    </AlignCenter>\n  </Template>\n);\n"
  },
  {
    "path": "packages/site/templates/Pose/USPs/PluginsExample.js",
    "content": "import Template from '~/templates/Popmotion/LiveExamples/Template';\nimport { AlignCenter } from '~/templates/Popmotion/LiveExamples/styled';\nimport posed, { PoseGroup } from 'react-pose';\nimport styled from 'styled-components';\nimport { color } from '~/styles/vars';\nimport trackVisibility from '~/templates/Popmotion/LiveExamples/track-visibility';\nimport SplitText from 'react-pose-text';\n\nconst code = `const charPoses = {\n  hidden: { y: 10, opacity: 0 },\n  visible: {\n    y: 0,\n    opacity: 1,\n    delay: ({ charIndex }) => charIndex * 50\n  }\n};\n\n({ isVisible }) => (\n  <SplitText\n    pose={isVisible ? 'visible' : 'hidden'}\n    charPoses={charPoses}\n  >\n    React Pose Text\n  </SplitText>\n)`;\n\nconst charPoses = {\n  hidden: { y: 10, opacity: 0 },\n  visible: {\n    y: 0,\n    opacity: 1,\n    delay: ({ charIndex }) => charIndex * 50\n  }\n};\n\nclass Example extends React.Component {\n  render() {\n    return (\n      <Container>\n        <SplitText\n          pose={this.props.isVisible ? 'visible' : 'hidden'}\n          charPoses={charPoses}\n        >\n          React Pose Text\n        </SplitText>\n      </Container>\n    );\n  }\n}\n\nexport default trackVisibility(({ isVisible }) => (\n  <Template code={code}>\n    <AlignCenter>\n      <Example />\n    </AlignCenter>\n  </Template>\n));\n"
  },
  {
    "path": "packages/site/templates/Pose/USPs/ReactExample.js",
    "content": "import Template from '~/templates/Popmotion/LiveExamples/Template';\nimport { AlignCenter } from '~/templates/Popmotion/LiveExamples/styled';\nimport {\n  styler,\n  spring,\n  value,\n  listen,\n  tween,\n  pointer,\n  decay,\n  transform\n} from 'popmotion';\nimport posed, { PoseGroup } from 'react-pose';\nimport styled from 'styled-components';\nimport { color } from '~/styles/vars';\n\nconst Container = styled.div`\n  overflow: hidden;\n`;\n\nconst sidepanelProps = {};\n\nconst itemProps = {\n  closed: {\n    y: 20,\n    opacity: 0\n  },\n  open: {\n    y: 0,\n    opacity: 1\n  }\n};\n\nconst Sidepanel = styled(posed.ul(sidepanelProps))`\n  width: 300px;\n  padding: 20px;\n`;\n\nconst Item = styled(posed.li())`\n  width: 100%;\n  border-radius: 5px;\n  height: 35px;\n  background: ${color.white};\n  margin-bottom: 10px;\n\n  &:last-child {\n    margin-bottom: 0;\n  }\n\n  &[data-key='0'] {\n    background: ${color.green};\n  }\n\n  &[data-key='1'] {\n    background: ${color.brand};\n  }\n\n  &[data-key='2'] {\n    background: ${color.blue};\n  }\n\n  &[data-key='3'] {\n    background: ${color.purple};\n  }\n`;\n\nconst code = `// PoseGroup currently React DOM only\n\nconst Item = posed.li()\n\nconst List = ({ items }) => (\n  <ul>\n    <PoseGroup>\n      {items.map(item => <Item key={item.key} />)}\n    </PoseGroup>\n  </ul>\n)`;\n\nfunction shuffle(array) {\n  var currentIndex = array.length,\n    temporaryValue,\n    randomIndex;\n\n  // While there remain elements to shuffle...\n  while (0 !== currentIndex) {\n    // Pick a remaining element...\n    randomIndex = Math.floor(Math.random() * currentIndex);\n    currentIndex -= 1;\n\n    // And swap it with the current element.\n    temporaryValue = array[currentIndex];\n    array[currentIndex] = array[randomIndex];\n    array[randomIndex] = temporaryValue;\n  }\n\n  return array;\n}\n\nclass Example extends React.Component {\n  state = { items: [0, 1, 2, 3] };\n\n  componentDidMount() {\n    this.interval = setInterval(this.toggleVisibility, 2000);\n  }\n\n  componentWillUnmount() {\n    clearInterval(this.interval);\n  }\n\n  toggleVisibility = () => this.setState({ items: shuffle(this.state.items) });\n\n  render() {\n    return (\n      <Container>\n        <Sidepanel>\n          <PoseGroup>\n            {this.state.items.map(item => <Item data-key={item} key={item} />)}\n          </PoseGroup>\n        </Sidepanel>\n      </Container>\n    );\n  }\n}\n\nexport default () => (\n  <Template code={code}>\n    <AlignCenter>\n      <Example />\n    </AlignCenter>\n  </Template>\n);\n"
  },
  {
    "path": "packages/site/templates/Pose/USPs/ZeroConfigExample.js",
    "content": "import Template from '~/templates/Popmotion/LiveExamples/Template';\nimport {\n  Carousel,\n  Item,\n  AlignCenter\n} from '~/templates/Popmotion/LiveExamples/styled';\nimport { styler, value, listen, pointer, decay, transform } from 'popmotion';\nimport posed from 'react-pose';\nimport styled from 'styled-components';\nimport { color } from '~/styles/vars';\n\nconst props = {\n  left: { x: '-100%' },\n  right: { x: '100%' }\n};\n\nconst Box = styled(posed.div(props))`\n  width: 100px;\n  height: 100px;\n  background: ${color.brand};\n  transform: translateX(-100%);\n`;\n\nconst code = {\n  react: `const Box = posed.div({\n  left: { x: -100 },\n  right: { x: 100 }\n})\n\nconst Component = ({ position }) =>\n  <Box pose={position} />`,\n  vue: `const Component = {\n  components: {\n    Box: posed.div({\n      left: { x: -100 },\n      right: { x: 100 }\n    })\n  },\n  template: \\`<Box :pose=\"position\" />\\`\n}`\n};\n\nclass Example extends React.Component {\n  state = { isVisible: true };\n\n  componentDidMount() {\n    this.interval = setInterval(this.toggleVisibility, 1000);\n  }\n\n  componentWillUnmount() {\n    clearInterval(this.interval);\n  }\n\n  toggleVisibility = () => this.setState({ isVisible: !this.state.isVisible });\n\n  render() {\n    return <Box pose={this.state.isVisible ? 'left' : 'right'} />;\n  }\n}\n\nexport default props => (\n  <Template code={code} {...props}>\n    <AlignCenter>\n      <Example />\n    </AlignCenter>\n  </Template>\n);\n"
  },
  {
    "path": "packages/site/templates/Pose/USPs/index.js",
    "content": "import styled from 'styled-components';\nimport ZeroConfigExample from './ZeroConfigExample';\nimport DeclarativeExample from './DeclarativeExample';\nimport DraggableExample from './DraggableExample';\nimport PassiveExample from './PassiveExample';\nimport ReactExample from './ReactExample';\nimport { Strong } from '~/templates/global/styled';\nimport CustomExample from './CustomExample';\nimport ChildrenExample from './ChildrenExample';\nimport FlipExample from './FlipExample';\nimport PluginsExample from './PluginsExample';\nimport Link from 'next/link';\nimport { CTA } from '~/templates/Popmotion/Masthead/styled';\nimport AnimateAnythingExample from './AnimateAnything';\nimport { ActionLink } from '~/templates/global-new/styled';\n\nconst MoreExamples = styled.div`\n  margin: 20px auto 50px;\n`;\n\nexport default class Examples extends React.Component {\n  state = { framework: 'react' };\n\n  setFramework = (framework) => () => this.setState({ framework });\n\n  setFrameworkTo = {\n    vue: this.setFramework('vue'),\n    react: this.setFramework('react'),\n  };\n\n  render() {\n    return (\n      <Container>\n        <BlurbText style={{ marginBottom: 40, maxWidth: '600px' }}>\n          These are legacy docs for Pose. Please upgrade to{' '}\n          <a href=\"https://framer.com/motion\">Framer Motion</a>.\n        </BlurbText>\n        <ActionLink cta href=\"/pose/learn/get-started\" prefetch>\n          Get started\n        </ActionLink>\n\n        <MoreExamples>\n          <Link href=\"/pose/examples\">\n            <a>See all examples</a>\n          </Link>\n        </MoreExamples>\n      </Container>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/site/templates/Pose/index.js",
    "content": "import Homepage from '~/templates/homepage';\nimport Header from './Header';\nimport Footer from '~/templates/global-new/Footer';\n\nimport styled from 'styled-components';\n\nconst Notice = styled.section`\n  width: 100%;\n  max-width: 900px;\n  margin: 20px auto 50px;\n  background: #f4f4f4;\n  border-left: 4px solid #ff1c68;\n  padding: 20px;\n\n  h2 {\n    font-weight: 800;\n    margin-bottom: 20px;\n    font-size: 24px;\n  }\n`;\n\nexport default () => (\n  <Homepage\n    title=\"Pose | A truly simple animation library for React, React Native, and Vue\"\n    theme=\"pose\"\n    Header={Header}\n  >\n    <Notice>\n      <h2>⚠️ Notice</h2>\n      <p>\n        React Pose for web has been <strong>deprecated</strong> by{' '}\n        <a href=\"https://framer.com/motion\">Framer Motion</a>.\n      </p>\n    </Notice>\n    <Footer />\n  </Homepage>\n);\n"
  },
  {
    "path": "packages/site/templates/Stylefire/index.js",
    "content": "import Homepage from '~/templates/homepage';\nimport Footer from '~/templates/global-new/Footer';\nimport { createElement } from 'react';\nimport settings from '~/data/settings.json';\nimport docs from '~/docs/stylefire/index.md';\nimport marksy from 'marksy/components';\nimport SiteLink from '~/components/layout/SiteLink';\nimport styled from 'styled-components';\nimport { CTA } from '../Popmotion/Masthead/styled';\nimport {\n  A,\n  H1,\n  H2,\n  H3,\n  H4,\n  H5,\n  P,\n  Li,\n  Ol,\n  Ul,\n  Hr,\n  Code,\n  Blockquote,\n  ArticleHeader,\n  Video\n} from '~/templates/global/styled';\nimport { Img } from '~/templates/content/styled';\n\nconst Container = styled.article`\n  padding-top: 30px;\n`;\n\nconst convertMarkdown = marksy({\n  createElement,\n  elements: {\n    a: A,\n    h1: ArticleHeader,\n    h2: H2,\n    h3: H3,\n    h4: H4,\n    h5: H5,\n    p: P,\n    code: Code,\n    li: Li,\n    ul: Ul,\n    hr: Hr,\n    img: Img,\n    blockquote: Blockquote\n  }\n});\n\nconst { tree, toc } = convertMarkdown(docs);\n\nexport default () => (\n  <Homepage\n    title=\"Stylefire | A style setter for HTML and SVG, optimised for animation\"\n    theme=\"stylefire\"\n    Header={() => null}\n  >\n    <Container>{tree}</Container>\n    <CTA style={{ width: 220 }} brandFill>\n      <SiteLink href=\"/api\" prefetch>\n        Read API docs\n      </SiteLink>\n    </CTA>\n    <Footer />\n  </Homepage>\n);\n"
  },
  {
    "path": "packages/site/templates/blog/components/BlogItem/index.js",
    "content": "import Link from 'next/link';\nimport { Container, Title, Description, Date } from './styled';\n\nexport default ({ id, title, description, published }) => (\n  <Container>\n    <Link href={`/blog/${id}`}>\n      <a>\n        <Title>{title}</Title>\n        <Date>{published}</Date>\n        <Description>{description}</Description>\n      </a>\n    </Link>\n  </Container>\n);\n"
  },
  {
    "path": "packages/site/templates/blog/components/BlogItem/styled.js",
    "content": "import styled from 'styled-components';\nimport { font, media, color } from '~/styles/vars';\nimport { P } from '~/templates/global-new/styled';\n\nexport const Container = styled.li`\n  margin-bottom: 40px;\n\n  ${({ isSection }) =>\n    isSection &&\n    `\n    border-bottom: 1px solid ${color.lightGrey};\n  `} a:visited {\n    opacity: 0.75;\n  }\n\n  a h2,\n  a h3 {\n    ${({ theme }) => `color: ${theme.color.action}`};\n  }\n`;\n\nexport const Title = styled.h2`\n  font-size: 24px;\n  ${font.bold};\n  letter-spacing: -0.1px;\n  display: inline;\n  margin-bottom: 10px;\n  margin-right: 6px;\n  ${({ theme }) => `color: ${color.black}`};\n\n  ${media.medium`\n    font-size: 20px;\n  `};\n\n  a {\n    ${({ theme }) => `color: ${theme.color.action}`};\n    ${font.bold};\n  }\n`;\n\nexport const Subtitle = styled(Title.withComponent('h3'))`\n  font-size: 18px;\n\n  ${media.medium`\n    font-size: 14px;\n  `};\n\n  a {\n    ${font.bold};\n  }\n`;\n\nexport const Date = styled.span`\n  opacity: 0.6;\n  ${media.medium`\n    display: block;\n    margin-top: 4px;\n    font-size: 14px;\n  `};\n`;\n\nexport const Description = styled(P)`\n  margin-top: 5px;\n`;\n\nexport const TitleContainer = styled.div`\n  margin-bottom: 40px;\n`;\n"
  },
  {
    "path": "packages/site/templates/blog/index.js",
    "content": "import { Fragment } from 'react';\nimport BlogItem from './components/BlogItem';\nimport { withTheme } from 'styled-components';\n\nconst BlogList = ({ theme, numItems }) => {\n  const content = theme.data.content.blog;\n  const menu = theme.data.menus.blog;\n  const filteredMenu = menu.filter(({ id }) => content[id].draft !== true);\n  const menuSubsection = filteredMenu.slice(0, numItems);\n  return (\n    <ul>\n      {menuSubsection.map(({ id, title }) => (\n        <BlogItem\n          id={id}\n          key={id}\n          title={title}\n          description={content[id].description}\n          published={content[id].published}\n        />\n      ))}\n    </ul>\n  );\n};\n\nexport default withTheme(BlogList);\n"
  },
  {
    "path": "packages/site/templates/content/ContentCTA/index.js",
    "content": "import React from 'react';\nimport { Container, Content, P, Support } from './styled';\nimport Link from 'next/link';\n\nexport default ({ children }) => (\n  <Container>\n    <Content>\n      <P>\n        Hey! Did you find this article useful? Popmotion relies on contributions\n        from the community to operate.\n      </P>\n      <Support>\n        <Link href=\"/support\">Support us</Link>\n      </Support>\n    </Content>\n  </Container>\n);\n"
  },
  {
    "path": "packages/site/templates/content/ContentCTA/styled.js",
    "content": "import styled from 'styled-components';\nimport { color } from '~/styles/vars';\nimport { Centered } from '~/templates/global/grid';\nimport { P as Paragraph } from '~/templates/global/styled';\n\nexport const Container = styled(Centered)`\n  background-image: linear-gradient(-180deg, #fff51c 0%, #e88003 100%);\n  padding: 5px;\n  margin-top: 80px;\n`;\n\nexport const Content = styled.div`\n  background: ${color.white};\n  padding: 20px;\n`;\n\nexport const P = styled(Paragraph)`\n  margin: 0;\n`;\n\nexport const Support = styled.div`\n  margin-top: 20px;\n\n  a {\n    font-size: 22px;\n    font-weight: bold;\n  }\n`;\n"
  },
  {
    "path": "packages/site/templates/content/ContentNav.js",
    "content": "import React from 'react';\nimport SiteLink from '~/components/layout/SiteLink';\nimport styled, { css, withTheme } from 'styled-components';\nimport { Centered } from '~/templates/global/grid';\nimport DropDownArrow from '~/components/icons/DropDownArrow';\nimport { fontSize, fontBold, lineHeight } from '~/styles/fonts';\nimport { ENTITY, cols, media } from '~/styles/vars';\nimport sectionNames from '~/data/section-names.json';\n\nexport const ContentNavArea = styled.div`\n  width: ${cols(14)};\n  margin-top: ${cols(1)};\n  z-index: 2;\n\n  ${media.large`\n    position: relative;\n    width: auto;\n    border: 1px solid ${ENTITY};\n    margin-top: 0;\n    margin-bottom: ${cols(2)};\n  `};\n`;\n\nconst CategoryContainer = styled.li`\n  margin-bottom: ${cols(2)};\n`;\n\nconst selectable = ({ isSelected }) =>\n  isSelected &&\n  css`\n  a {\n    ${fontBold}\n    color: ${ENTITY};\n  }\n`;\n\nconst CategoryTitle = styled.h2`\n  ${fontSize(18)}\n  margin-bottom: ${cols(1)};\n  ${selectable}\n\n  a {\n    text-decoration: none;\n\n    &:hover {\n      color: #0866C2;\n    }\n  }\n`;\n\nconst MenuItem = styled.li`\n  ${fontSize(14)} ${lineHeight(18)}\n  margin-bottom: 5px;\n  margin-left: ${cols(1)};\n  ${selectable} a {\n    text-decoration: none;\n\n    &:hover {\n      color: #0866c2;\n    }\n  }\n`;\n\nconst MenuToggle = styled.div`\n  position: relative;\n  ${fontSize(18)}\n  ${fontBold}\n  border-bottom: 1px solid ${({ theme }) => theme.color.base};\n  width: 100%;\n  padding-bottom: ${cols(1)};\n  margin-bottom: ${cols(2)};\n\n  ${media.large`\n    cursor: pointer;\n    position: relative;\n    border: none;\n    ${fontSize(18)}\n    padding: ${cols(1)};\n    margin-bottom: 0;\n  `}\n`;\n\nconst Menu = styled.ul`\n  ${media.large`\n    display: ${({ isOpen }) => (isOpen ? 'block' : 'none')};\n    padding: ${cols(1)};\n  `};\n`;\n\nconst DropDownMenuIcon = styled(DropDownArrow)`\n  position: absolute;\n  right: ${cols(1)};\n  top: 50%;\n  margin-top: -5px;\n  ${({ isOpen }) => isOpen && 'transform: rotate(180deg);'} display: none;\n  ${media.large`display: block;`};\n`;\n\nconst Item = ({ id, title, contentId, section, draft }) => (\n  <MenuItem isSelected={id === contentId}>\n    <SiteLink href={`/${section}/${id}`}>{title}</SiteLink>\n  </MenuItem>\n);\n\nconst Category = ({ id, title, contentId, content, section, posts }) => (\n  <CategoryContainer>\n    <CategoryTitle isSelected={id === contentId}>\n      {content[id] ? (\n        <SiteLink href={`/${section}/${id}`}>{title}</SiteLink>\n      ) : (\n        title\n      )}\n    </CategoryTitle>\n    {posts ? (\n      <ul>\n        {posts.map(\n          post =>\n            !content[post.id].draft && (\n              <Item\n                key={post.id}\n                {...post}\n                contentId={contentId}\n                section={section}\n              />\n            )\n        )}\n      </ul>\n    ) : null}\n  </CategoryContainer>\n);\n\nclass ContentNav extends React.PureComponent {\n  render() {\n    const { section, id, theme, isOpen, toggleMenu } = this.props;\n    const menu = theme.data.menus[section];\n    const content = theme.data.content[section];\n\n    return (\n      <ContentNavArea pose={isOpen ? 'open' : 'closed'}>\n        <MenuToggle onClick={toggleMenu}>\n          {sectionNames[section]}\n          <DropDownMenuIcon isOpen={isOpen} />\n        </MenuToggle>\n        <Menu isOpen={isOpen}>\n          {menu.map(category => (\n            <Category\n              key={category.id}\n              {...category}\n              content={content}\n              contentId={id}\n              section={section}\n            />\n          ))}\n        </Menu>\n      </ContentNavArea>\n    );\n  }\n}\n\nexport default withTheme(ContentNav);\n"
  },
  {
    "path": "packages/site/templates/content/MenuPage/index.js",
    "content": "import { Fragment } from 'react';\nimport SiteLink from '~/components/layout/SiteLink';\nimport {\n  Container,\n  Title,\n  Description,\n  Date,\n  Subtitle,\n  TitleContainer\n} from '../../blog/components/BlogItem/styled';\nimport { withTheme } from 'styled-components';\n\nconst MenuItem = ({ id, title, content, section }) => (\n  <Container>\n    <Subtitle>\n      <SiteLink href={`/${section}/${id}`}>{title}</SiteLink>\n    </Subtitle>\n    <Description>{content[id].description}</Description>\n  </Container>\n);\n\nconst MenuSection = ({ id, title, content, section, posts }) => (\n  <Container isSection>\n    <TitleContainer>\n      {content[id] ? (\n        <Fragment>\n          <Title>\n            <SiteLink href={`/${section}/${id}`}>{title}</SiteLink>\n          </Title>\n          <Description>{content[id].description}</Description>\n        </Fragment>\n      ) : (\n        <Title>{title}</Title>\n      )}\n    </TitleContainer>\n    {posts ? (\n      <ul>\n        {posts.map(sl => (\n          <MenuItem\n            id={sl.id}\n            key={sl.id}\n            title={sl.title}\n            content={content}\n            section={section}\n          />\n        ))}\n      </ul>\n    ) : null}\n  </Container>\n);\n\nconst BlogList = ({ theme, section }) => {\n  const { generateSiteUrl } = theme.data;\n  const content = theme.data.content[section];\n  const menu = theme.data.menus[section];\n\n  return (\n    <ul>\n      {menu.map(({ id, title, posts }) => (\n        <MenuSection\n          id={id}\n          key={id}\n          content={content}\n          section={section}\n          title={title}\n          posts={posts}\n        />\n      ))}\n    </ul>\n  );\n};\n\nexport default withTheme(BlogList);\n"
  },
  {
    "path": "packages/site/templates/content/PostDetails/index.js",
    "content": "import styled from 'styled-components';\nimport { color, media } from '~/styles/vars';\nimport { Centered } from '~/templates/global/grid';\n\nconst Container = styled(Centered)`\n  display: flex;\n  align-items: center;\n  margin-bottom: 15px;\n\n  span {\n    color: ${color.grey};\n    font-size: 14px;\n\n    ${media.small`font-size: 12px;`};\n  }\n\n  > * {\n    margin-right: 10px;\n  }\n`;\n\nconst avatarSize = '30px';\nconst Avatar = styled.div`\n  width: ${avatarSize};\n  height: ${avatarSize};\n  border-radius: 50%;\n  overflow: hidden;\n\n  img {\n    width: ${avatarSize};\n    height: ${avatarSize};\n  }\n`;\n\nconst Name = styled.span``;\n\nexport default ({ published, name, avatar }) => (\n  <Container>\n    {avatar && (\n      <Avatar>\n        <img src={avatar} alt={`Avatar of ${name}`} />\n      </Avatar>\n    )}\n    {name && <span>{name}</span>}\n    {name && published && <span>{`|`}</span>}\n    {published && <span>{published}</span>}\n  </Container>\n);\n"
  },
  {
    "path": "packages/site/templates/content/TableOfContents/index.js",
    "content": "import { Container, List, Item, Link, Header } from './styled';\n\nconst generateSection = (list, maxLevel) => (\n  <List>{list.map((item) => generateLink(item, maxLevel))}</List>\n);\n\nconst generateLink = ({ title, id, children, level }, maxLevel) => {\n  return maxLevel !== undefined && level > maxLevel ? null : (\n    <Item key={id}>\n      <Link href={`#${id}`}>{title}</Link>\n      {children && generateSection(children, maxLevel)}\n    </Item>\n  );\n};\n\nexport default ({ toc, maxLevel }) => (\n  <Container>\n    <Header>Contents</Header>\n    {generateSection(toc[0].children, maxLevel)}\n  </Container>\n);\n"
  },
  {
    "path": "packages/site/templates/content/TableOfContents/styled.js",
    "content": "import styled from 'styled-components';\nimport { Centered } from '~/templates/global/grid';\nimport { color, cols, font } from '~/styles/vars';\n\nexport const Container = styled(Centered.withComponent('nav'))`\n  margin-top: 40px;\n  margin-bottom: 20px;\n  padding: 20px;\n  background: ${color.superLightGrey};\n`;\n\nexport const Header = styled.h2`\n  border-bottom: 1px solid var(--color-popmotion);\n  padding: 0 0 10px;\n  margin-bottom: 20px;\n  ${font.bold};\n`;\n\nexport const List = styled.ul``;\n\nexport const Item = styled.li`\n  li {\n    padding-left: ${cols(1)};\n  }\n  margin-top: 10px;\n  margin-bottom: 10px;\n`;\n\nexport const Link = styled.a``;\n"
  },
  {
    "path": "packages/site/templates/content/Template.js",
    "content": "import {\n  Container,\n  ContentArea,\n  NextLink,\n  NextLinkContainer,\n  NextLinkSmall,\n  EmptyCol\n} from './styled';\nimport { Content } from '~/templates/global/grid';\nimport ContentNav from './ContentNav';\nimport GlobalTemplate from '~/templates/global/Template';\nimport ContentPage from '~/templates/global-new/ContentPage';\nimport PostDetails from './PostDetails';\nimport themes from '~/styles/themes';\nimport authorData from '~/data/authors.json';\n\nexport default class Template extends React.PureComponent {\n  state = {\n    isMenuOpen: false\n  };\n\n  toggleMenu = () => {\n    const { isMenuOpen } = this.state;\n    this.setState({ isMenuOpen: !isMenuOpen });\n  };\n\n  render() {\n    const {\n      children,\n      title,\n      id,\n      description,\n      section,\n      published,\n      author,\n      theme,\n      next\n    } = this.props;\n    const { isMenuOpen } = this.state;\n\n    return (\n      <GlobalTemplate\n        title={`${title} | ${themes[theme].name}`}\n        description={description}\n        theme={theme}\n      >\n        <ContentPage section={section}>\n          <Container>\n            {section !== 'blog' ? (\n              <ContentNav\n                isOpen={isMenuOpen}\n                toggleMenu={this.toggleMenu}\n                section={section}\n                id={id}\n              />\n            ) : (\n              <EmptyCol />\n            )}\n            <ContentArea pose=\"flip\">\n              <Content>\n                {published || authorData[author] ? (\n                  <PostDetails\n                    published={published}\n                    name={\n                      author && authorData[author] && authorData[author].name\n                    }\n                    avatar={\n                      author && authorData[author] && authorData[author].avatar\n                    }\n                  />\n                ) : null}\n                {children}\n                {next && themes[theme].data.content[section][next] ? (\n                  <NextLinkContainer>\n                    <NextLink href={`/${section}/${next}`} prefetch>\n                      <NextLinkSmall>Next</NextLinkSmall>\n                      {themes[theme].data.content[section][next].title}\n                    </NextLink>\n                  </NextLinkContainer>\n                ) : null}\n              </Content>\n            </ContentArea>\n          </Container>\n        </ContentPage>\n      </GlobalTemplate>\n    );\n  }\n}\n"
  },
  {
    "path": "packages/site/templates/content/styled.js",
    "content": "import styled from 'styled-components';\nimport { fontSize, fontBold } from '~/styles/fonts';\nimport { cols, BLACK, LIGHT_GREY, BRAND, media } from '~/styles/vars';\nimport { htmlUnencode } from '~/utils/string';\nimport SiteLink from '~/components/layout/SiteLink';\nimport { Centered } from '~/templates/global/grid';\nimport posed from 'react-pose';\n\nexport const Container = styled.div`\n  position: relative;\n  margin: 75px 0;\n  display: flex;\n  justify-content: space-between;\n\n  ${media.large`display: block;`};\n`;\n\nexport const ContentArea = styled(\n  posed.div({\n    flip: {\n      transition: { type: 'spring', stiffness: 1000, damping: 35 }\n    }\n  })\n)`\n  width: calc(100% - (100vw - ${cols(48)}) / 2);\n\n  ${media.large`width: 100%;`};\n`;\n\nconst ImgFrame = styled.span`\n  max-width: ${cols(43)};\n  border-bottom: 1px solid ${LIGHT_GREY};\n  display: block;\n  padding: ${cols(1)} 0 ${cols(2)};\n`;\n\nconst Image = styled.img`\n  margin: 0 auto;\n  display: block;\n  max-width: 90vw;\n`;\n\nconst Caption = styled.span`\n  ${fontSize(14)}\n  color: ${BLACK};\n  display: block;\n  text-align: center;\n  margin-top: ${cols(1)};\n`;\n\nexport const Img = ({ className, alt, ...props }) => (\n  <ImgFrame className={className} {...props}>\n    <Image {...props} />\n    {alt ? <Caption>{htmlUnencode(alt)}</Caption> : null}\n  </ImgFrame>\n);\n\nexport const NextLinkContainer = styled(Centered)`\n  border-top: 1px ${BRAND} solid;\n  margin-top: ${cols(2)};\n  padding-top: ${cols(2)};\n  padding-bottom: ${cols(2)};\n  display: flex;\n  justify-content: flex-end;\n\n  a {\n    display: flex;\n    flex-direction: column;\n    align-items: flex-end;\n    font-size: 28px;\n    ${fontBold};\n\n    span {\n      font-size: 18px;\n      font-weight: normal;\n    }\n  }\n`;\n\nexport const NextLink = styled(SiteLink)`\n  display: block;\n`;\n\nexport const NextLinkSmall = styled.span``;\n\nexport const EmptyCol = styled.div`\n  width: 150px;\n`;\n"
  },
  {
    "path": "packages/site/templates/global/Analytics.js",
    "content": "const analyticsCode = `\n  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){\n  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),\n  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)\n  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');\n\n  ga('create', 'UA-3215563-7', 'auto');\n  ga('send', 'pageview');\n`;\n\nexport default () => (\n  <script dangerouslySetInnerHTML={{__html: analyticsCode}} />\n);\n"
  },
  {
    "path": "packages/site/templates/global/Footer.js",
    "content": "import styled from 'styled-components';\nimport Logo from '~/components/icons/Logo';\nimport { fontSize, fontBold } from '~/styles/fonts';\nimport { cols, color, media } from '~/styles/vars';\nimport themes from '~/styles/themes';\nimport { CenteredContent } from '../Popmotion/USPs/styled';\nimport SocialLinks from '~/templates/global/SocialLinks';\n\nconst YEAR = new Date().getFullYear();\n\nconst Container = styled.div`\n  padding-top: 90px;\n  padding-bottom: 90px;\n  background: linear-gradient(#262e34, #101416);\n  margin-top: ${cols(4)};\n\n  p,\n  h2 {\n    ${fontBold};\n    color: ${color.white};\n    text-align: center;\n  }\n`;\n\nconst Header = styled.header`\n  display: flex;\n  align-items: center;\n\n  span {\n    background: #3f4d56;\n    flex: 1;\n    height: 1px;\n  }\n\n  ${media.small`\n    display: block;\n    span {\n      display: none;\n    }\n  `};\n`;\n\nconst HeaderText = styled.h2`\n  font-size: 24px;\n  flex-shrink: 0;\n  padding-left: ${cols(1)};\n  padding-right: ${cols(1)};\n`;\n\nconst LibraryList = styled.ul`\n  display: flex;\n  flex-wrap: wrap;\n  margin-top: ${cols(4)};\n  margin-bottom: ${cols(2)};\n`;\n\nconst LibraryContainer = styled.li`\n  flex: 50% 0 0;\n  overflow: hidden;\n  margin-bottom: ${cols(4)};\n\n  ${media.medium`\n    flex: 100% 0 0;\n  `} p {\n    max-width: 50%;\n    text-align: center;\n  }\n\n  a {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n  }\n`;\n\nconst LogoContainer = styled.div`\n  height: 80px;\n  display: flex;\n  align-items: center;\n`;\n\nconst Copyright = styled.p`\n  font-size: 14px;\n`;\n\nconst MadeInfo = styled.p`\n  font-size: 24px;\n  margin-bottom: 10px;\n`;\n\nconst SocialLinksContainer = styled.div`\n  margin: ${cols(2)} auto 0;\n  path {\n    fill: white;\n  }\n`;\n\nconst Library = ({ library }) => {\n  const { title, url, tagline, Logo, footerLogoSize } = library;\n  return (\n    <LibraryContainer>\n      <a href={url} alt={title}>\n        <LogoContainer>\n          <Logo {...footerLogoSize} />\n        </LogoContainer>\n        <p>{tagline}</p>\n      </a>\n    </LibraryContainer>\n  );\n};\n\nexport default () => (\n  <Container>\n    <CenteredContent>\n      <Header>\n        <span />\n        <HeaderText>Libraries to move the web</HeaderText>\n        <span />\n      </Header>\n      <LibraryList>\n        {Object.keys(themes)\n          .filter(theme => theme !== 'popmotion')\n          .map(key => <Library library={themes[key]} />)}\n      </LibraryList>\n      <MadeInfo>{`Made in London with 🌯`}</MadeInfo>\n      <Copyright>{`© 2014-2018 Matt Perry`}</Copyright>\n      <SocialLinksContainer>\n        <SocialLinks />\n      </SocialLinksContainer>\n    </CenteredContent>\n  </Container>\n);\n"
  },
  {
    "path": "packages/site/templates/global/Header.js",
    "content": "import Link from 'next/link';\nimport styled, { withTheme } from 'styled-components';\nimport SectionNav from './SectionNav';\nimport SocialLinks from '~/templates/global/SocialLinks';\nimport Logo from '~/components/icons/Logo';\nimport Icon from '~/components/icons/PopmotionIcon';\nimport settings from '~/data/settings.json';\nimport { cols, media } from '~/styles/vars';\nimport { Centered } from '~/templates/global/grid';\n\nconst HeaderContainer = styled.nav`\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  position: relative;\n  padding: 25px ${cols(2)};\n  margin-bottom: ${cols(4)};\n  height: 91px;\n  background: ${props =>\n    props.isHomepage\n      ? 'linear-gradient(rgba(0,0,0,0.2), rgba(0,0,0,0))'\n      : 'none'};\n\n  ${media.large`\n    margin-bottom: ${cols(2)};\n    height: 87px;\n  `} ${media.small`\n    padding: ${cols(1)};\n    height: auto;\n    flex-direction: column;\n    align-items: center;\n  `};\n`;\n\nconst NavArea = styled.nav`\n  display: flex;\n  align-items: center;\n  ${props => !props.isHomepage && 'position: absolute;'} top: 50%;\n  transform: translateY(-50%);\n`;\n\nconst LogoArea = styled(NavArea)`\n  left: ${cols(2)};\n  ${media.large`\n    position: static;\n    transform: none;\n    margin-right: ${cols(2)};\n  `} ${props => props.isHomepage && `display: none;`};\n\n  ${media.small`\n    display: block;\n    position: static;\n    margin: 0;\n    margin-bottom: 5px;\n  `};\n`;\n\nconst SectionNavArea = styled(Centered)`\n  width: 100%;\n  ${media.large`margin-left: ${cols(1)};`} ${props =>\n    props.isHomepage &&\n    `\n    margin: 0;\n  `};\n\n  ${media.small`\n    margin: 0;\n    display: flex;\n    justify-content: center;\n  `};\n`;\n\nconst SocialArea = styled(NavArea)`\n  right: ${cols(2)};\n\n  ${media.medium`\n    display: none;\n  `};\n`;\n\nconst Header = ({ section, isHomepage, theme }) => (\n  <HeaderContainer isHomepage={isHomepage}>\n    <LogoArea isHomepage={isHomepage}>\n      {!isHomepage ? (\n        <Link href={theme.data.rootUrl}>\n          <a name=\"Homepage\">\n            <theme.Logo {...theme.headerLogoSize} />\n          </a>\n        </Link>\n      ) : null}\n    </LogoArea>\n    <SectionNavArea isHomepage={isHomepage}>\n      <SectionNav section={section} isHomepage={isHomepage} />\n    </SectionNavArea>\n    <SocialArea>\n      <SocialLinks />\n    </SocialArea>\n  </HeaderContainer>\n);\n\nexport default withTheme(Header);\n"
  },
  {
    "path": "packages/site/templates/global/SectionNav.js",
    "content": "import styled, { withTheme } from 'styled-components';\nimport SiteLink from '~/components/layout/SiteLink';\nimport { fontSize, fontBold } from '~/styles/fonts';\nimport { ACTION, ENTITY, WHITE, BLACK, cols, media, SKEW } from '~/styles/vars';\nimport sectionNames from '~/data/section-names.json';\nimport routes from '~/data/route-paths.json';\n\nconst MenuItem = styled.li`\n  ${fontSize(18)} display: inline;\n  padding-bottom: 4px;\n  margin-right: ${cols(2)};\n  position: relative;\n\n  &:last-child {\n    margin-right: 0;\n  }\n\n  ${({ isSelected }) =>\n    isSelected &&\n    `\n    &:after {\n      content: '';\n      display: block;\n      background: ${ENTITY};\n      position: absolute;\n      bottom: -3px;\n      right: 0;\n      left: 0;\n      height: 4px;\n      transform: skewX(${SKEW});\n    }\n  `} ${media.large`\n    ${fontSize(16)}\n    margin-right: ${cols(1)};\n  `} a {\n    color: ${props => (props.isHomepage ? WHITE : BLACK)};\n    text-decoration: none;\n    ${fontBold};\n  }\n`;\n\nconst SectionNav = ({ section, theme, isHomepage }) => (\n  <ul>\n    {theme.sections.map(name => (\n      <MenuItem\n        key={name}\n        isSelected={section === name}\n        isHomepage={isHomepage}\n      >\n        <SiteLink href={routes[name]} name={sectionNames[name]}>\n          {sectionNames[name]}\n        </SiteLink>\n      </MenuItem>\n    ))}\n  </ul>\n);\n\nexport default withTheme(SectionNav);\n"
  },
  {
    "path": "packages/site/templates/global/SocialLinks.js",
    "content": "import React from 'react';\nimport styled from 'styled-components';\nimport GitHub from '~/components/icons/GitHub';\nimport Twitter from '~/components/icons/Twitter';\nimport settings from '~/data/settings.json';\nimport { cols, media } from '~/styles/vars';\n\nconst IconLink = styled.a`\n  margin-left: ${cols(1)};\n`;\n\nconst TwitterLink = styled(IconLink)`\n  margin-left: none;\n  transform: translateY(2px);\n`;\n\nconst GitHubIcon = styled(GitHub)``;\nconst TwitterIcon = styled(Twitter)``;\n\nexport default () => (\n  <React.Fragment>\n    <TwitterLink href={settings.twitterUrl} name=\"Popmotion Twitter\">\n      <TwitterIcon />\n    </TwitterLink>\n    <IconLink href={settings.githubUrl} name=\"Popmotion GitHub\">\n      <GitHubIcon />\n    </IconLink>\n  </React.Fragment>\n);\n"
  },
  {
    "path": "packages/site/templates/global/Template.js",
    "content": "import { Fragment } from 'react';\nimport { createGlobalStyle, ThemeProvider } from 'styled-components';\nimport NProgress from 'nprogress';\nimport Head from 'next/head';\nimport Router from 'next/router';\nimport reset from '~/styles/reset';\nimport nprogressStyles from '~/styles/nprogress';\nimport { BRAND } from '~/styles/vars';\nimport themes from '~/styles/themes';\nimport settings from '~/data/settings.json';\nimport * as popmotion from 'popmotion';\n\nif (typeof window !== 'undefined') {\n  console.log(\n    'Hey explorer! You can play around with Popmotion right from your console, by using window.popmotion.'\n  );\n  window.popmotion = popmotion;\n}\n\nRouter.onRouteChangeStart = () => NProgress.start();\nRouter.onRouteChangeComplete = () => {\n  if (typeof window !== 'undefined' && typeof window.Prism !== 'undefined') {\n    window.Prism.highlightAll();\n  }\n  NProgress.done();\n};\nRouter.onRouteChangeError = () => NProgress.done();\n\nconst Global = createGlobalStyle`\n  ${reset}\n  ${nprogressStyles}\n`;\n\nexport default ({ children, title, theme, description, image }) => (\n  <Fragment>\n    <Global />\n    <Head>\n      <meta name=\"theme-color\" content={BRAND} />\n      <meta name=\"msapplication-navbutton-color\" content={BRAND} />\n      <meta name=\"apple-mobile-web-app-title\" content={settings.siteName} />\n      <meta property=\"og:site_name\" content={settings.siteName} />\n      <meta property=\"og:title\" content={title} />\n      <meta\n        property=\"og:description\"\n        content={description || themes[theme].tagline}\n      />\n      <meta property=\"og:image\" content={image || themes[theme].shareImage} />\n      <meta property=\"twitter:site\" content={settings.twitterUsername} />\n      <meta name=\"twitter:title\" content={title} />\n      <meta name=\"twitter:description\" content={description} />\n      <meta name=\"twitter:image\" content={image || themes[theme].shareImage} />\n      <title>{title}</title>\n    </Head>\n    <ThemeProvider theme={themes[theme]}>\n      <Fragment>{children}</Fragment>\n    </ThemeProvider>\n  </Fragment>\n);\n"
  },
  {
    "path": "packages/site/templates/global/grid.js",
    "content": "import styled from 'styled-components';\nimport { cols, media, LIGHT_GREY } from '~/styles/vars';\n\nexport const Content = styled.article``;\n\nexport const Centered = styled.div`\n  max-width: ${cols(42)};\n\n  ${media.large`\n    margin-left: 20px;\n    margin-right: 20px;\n  `};\n  ${media.medium`\n    margin-left: ${cols(1)};\n    margin-right: ${cols(1)};\n  `};\n  ${media.small`\n    margin-left: 5px;\n    margin-right: 5px;\n  `};\n`;\n\nexport const MajorCentered = styled(Centered)`\n  width: 100%;\n\n  ${media.large`\n    width: auto;\n    margin-left: 20px;\n  `};\n  ${media.medium`\n    margin-left: ${cols(1)};\n  `};\n  ${media.small`\n    margin-left: 5px;\n    margin-right: 5px;\n  `};\n`;\n\nexport const ArticleHeader = styled(MajorCentered.withComponent('header'))`\n  padding-bottom: 10px;\n  border-bottom: 1px solid ${LIGHT_GREY};\n  margin-bottom: ${cols(2)};\n`;\n\nexport const SectionContainer = styled.li``;\n\nexport const ItemContainer = styled(Centered.withComponent('li'))`\n  border-left: 1px solid ${LIGHT_GREY};\n  padding: ${cols(1)} ${cols(2)};\n  margin-bottom: ${cols(1)};\n\n  ${media.medium`\n    border: 0;\n    padding: 0;\n    margin-bottom: ${cols(2)};\n  `}\n`;\n"
  },
  {
    "path": "packages/site/templates/global/styled.js",
    "content": "import styled from 'styled-components';\nimport { fontSize, fontBold, lineHeight } from '~/styles/fonts';\nimport {\n  LIGHT_GREY,\n  WHITE,\n  cols,\n  color,\n  media,\n  GREEN,\n  PURPLE,\n  ENTITY,\n} from '~/styles/vars';\nimport {\n  Centered,\n  MajorCentered,\n  ArticleHeader as ArticleHeaderPrimitive,\n} from './grid';\nimport SyntaxHighlighter, {\n  registerLanguage,\n} from 'react-syntax-highlighter/dist/light';\nimport js from 'react-syntax-highlighter/dist/languages/javascript';\nimport { codeThemeLarge } from '~/styles/syntax-highlighting';\n\nregisterLanguage('javascript', js);\n\nexport const Strong = styled.strong`\n  ${fontBold};\n`;\n\nexport const A = styled.a`\n  color: #0866c2;\n  text-decoration: none;\n\n  &:hover {\n    color: #064fb5;\n  }\n`;\n\nexport const H1 = styled.h1`\n  ${fontSize(48)}\n  ${lineHeight(54)}\n  ${fontBold}\n  text-align: left;\n\n  ${media.medium`\n    ${fontSize(36)}\n    ${lineHeight(42)}\n  `}\n  ${media.small`\n    ${fontSize(28)}\n    ${lineHeight(32)}\n  `}\n`;\n\nexport const H2 = styled(Centered.withComponent('h2'))`\n  ${fontSize(36)}\n  ${fontBold}\n  margin-top: ${cols(4)};\n  margin-bottom: ${cols(2)};\n  border-bottom: 1px solid ${LIGHT_GREY};\n  padding-bottom: ${cols(1)};\n  ${media.medium`\n    ${fontSize(28)}\n    ${lineHeight(32)}\n    margin-top: ${cols(2)};\n    margin-bottom: ${cols(1)};\n  `}\n  ${media.small`\n    ${fontSize(24)}\n    ${lineHeight(28)}\n  `}\n\n  a {\n    ${fontBold}\n  }\n`;\n\nexport const H3 = styled(Centered.withComponent('h3'))`\n  ${fontSize(24)}\n  ${lineHeight(32)}\n  ${fontBold}\n  margin-top: ${cols(2)};\n  margin-bottom: ${cols(1)};\n  ${media.medium`\n    ${fontSize(24)}\n    ${lineHeight(30)}\n  `}\n  ${media.small`\n    ${fontSize(18)}\n    ${lineHeight(28)}\n  `}\n\n  a {\n    ${fontBold}\n  }\n`;\n\nexport const H4 = styled(Centered.withComponent('h4'))`\n  ${fontSize(20)}\n  margin-top: 2.2rem;\n  margin-bottom: 1.1rem;\n  font-weight: 600;\n  ${media.medium`${fontSize(16)}`}\n`;\n\nexport const H5 = styled(Centered.withComponent('h5'))`\n  ${fontSize(18)}\n  margin-top: 2.2rem;\n  margin-bottom: 1.1rem;\n  font-weight: 600;\n  ${media.medium`${fontSize(14)}`}\n`;\n\nexport const P = styled(Centered.withComponent('p'))`\n  ${fontSize(18)}\n  ${lineHeight(26)}\n  line-height: 1.5;\n  margin-bottom: 1.1rem;\n  word-break: break-word;\n  ${media.medium`\n    ${fontSize(14)}\n    ${lineHeight(22)}\n  `}\n`;\n\nexport const Blockquote = styled(MajorCentered.withComponent('blockquote'))`\n  border-left: 1px solid ${color.lightGrey};\n  background: ${color.superLightGrey};\n  padding: ${cols(1)};\n  margin-bottom: ${cols(2)};\n\n  p {\n    margin: 0;\n  }\n`;\n\nexport const CodeTag = styled.code`\n  background: var(--color-shade);\n  padding: 2px 5px;\n  font-size: 18px;\n  border: none;\n`;\n\nexport const CodeBlock = styled(MajorCentered)`\n  background: var(--color-shade);\n  border-left: 2px solid var(--color-popmotion);\n  margin-bottom: ${cols(3)};\n  font-size: 14px;\n\n  ${media.medium`\n    margin-left: 0;\n    margin-right: 0;\n\n    pre {\n      padding-right: 0!important;\n      width: 100%!important;\n    }\n  `};\n`;\n\nexport const Code = ({ language, children, code }) =>\n  children ? (\n    <CodeTag>{children}</CodeTag>\n  ) : (\n    <CodeBlock>\n      <SyntaxHighlighter language={language} style={codeThemeLarge}>\n        {code}\n      </SyntaxHighlighter>\n    </CodeBlock>\n  );\n\nexport const Ol = styled(Centered.withComponent('ol'))`\n  list-style-type: decimal;\n  padding-left: ${cols(2)};\n  max-width: ${cols(43)};\n  margin-bottom: 1.1rem;\n`;\n\nexport const Ul = styled(Centered.withComponent('ul'))`\n  list-style-type: disc;\n  padding-left: ${cols(2)};\n  max-width: ${cols(43)};\n  margin-bottom: 1.1rem;\n`;\n\nexport const Li = styled.li`\n  line-height: 1.7;\n  margin-bottom: 0.5rem;\n  ${fontSize(18)} ${media.medium`${fontSize(14)}`};\n`;\n\nexport const Hr = styled.hr`\n  border: none;\n  height: 1px;\n  background-color: ${LIGHT_GREY};\n  margin: ${cols(2)} 0;\n`;\n\nconst Button = styled.button`\n  background: ${GREEN};\n  border-radius: 0;\n  padding: ${cols(1)} ${cols(2)};\n  cursor: pointer;\n  margin: 0 auto;\n`;\n\nconst ButtonContent = styled.span`\n  color: ${WHITE};\n  ${fontBold} display: block;\n`;\n\nexport const ActionButton = ({ children, onClick }) => (\n  <Button type=\"button\" onClick={onClick}>\n    <ButtonContent>{children}</ButtonContent>\n  </Button>\n);\n\nexport const ArticleHeader = ({ children }) => (\n  <ArticleHeaderPrimitive>\n    <H1>{children}</H1>\n  </ArticleHeaderPrimitive>\n);\n\nexport const Video = ({ src, height = 320 }) => (\n  <Centered>\n    <video autoPlay height={height} controls muted>\n      <source src={src} type=\"video/mp4\" />\n    </video>\n  </Centered>\n);\n"
  },
  {
    "path": "packages/site/templates/global-new/ContentPage/index.js",
    "content": "import { Fragment } from 'react';\nimport Header from '../Header';\nimport Footer from '../Footer';\nimport { Container, ContentContainer } from '../styled';\n\nexport default ({ children, section }) => (\n  <Container>\n    <ContentContainer>\n      <Header section={section} />\n      {children}\n      <Footer />\n    </ContentContainer>\n  </Container>\n);\n"
  },
  {
    "path": "packages/site/templates/global-new/Footer/index.js",
    "content": "import PopmotionLogo from '~/components/icons/Logo';\nimport SocialLinks from '~/templates/global/SocialLinks';\nimport themes from '~/styles/themes';\nimport {\n  Container,\n  Section,\n  Header,\n  NavItem,\n  MadeIn,\n  Copyright\n} from './styled';\nimport Link from 'next/link';\n\nconst openSource = [\n  themes.pose,\n  themes.pure,\n  themes.popcorn,\n  themes.stylefire,\n  themes.framesync\n];\n\nexport default () => (\n  <Container>\n    <Section>\n      <Header>Site</Header>\n      <ul>\n        {themes.popmotion.headerNavLinks.map(({ href, label, isExternal }) => (\n          <NavItem key={href}>\n            <Link href={href}>\n              <a>{label}</a>\n            </Link>\n          </NavItem>\n        ))}\n      </ul>\n    </Section>\n    <Section>\n      <Header>Open source</Header>\n      <ul>\n        {openSource.map(({ url, name }) => (\n          <NavItem key={url}>\n            <Link href={url}>\n              <a>{name}</a>\n            </Link>\n          </NavItem>\n        ))}\n      </ul>\n    </Section>\n    <Section>\n      <Link href=\"/\">\n        <a>\n          <PopmotionLogo {...themes.popmotion.headerLogoSize} />\n        </a>\n      </Link>\n      <MadeIn>{`Made in London with 🌯`}</MadeIn>\n      <Copyright>{`© 2014-2019 Framer BV`}</Copyright>\n      <SocialLinks />\n    </Section>\n  </Container>\n);\n"
  },
  {
    "path": "packages/site/templates/global-new/Footer/styled.js",
    "content": "import styled from 'styled-components';\nimport Link from 'next/link';\nimport { color, font, media } from '~/styles/vars';\nimport { P } from '~/templates/global-new/styled';\n\nexport const Container = styled.div`\n  display: flex;\n  justify-content: flex-start;\n  padding-top: 75px;\n  width: 100%;\n  border-top: 1px solid ${color.lightGrey};\n\n  ${media.small`\n    flex-wrap: wrap;\n  `};\n`;\n\nexport const Section = styled.nav`\n  width: 200px;\n  flex: 200px 0 1;\n\n  &:last-child {\n    text-align: right;\n    margin-left: auto;\n  }\n\n  ${media.small`\n    flex: 100% 0 0;\n    width: 100%;\n    margin-bottom: 30px;\n\n    &:last-child {\n      text-align: left;\n    }\n  `};\n`;\n\nexport const Header = styled.h2`\n  ${font.bold};\n  font-size: 18px;\n  margin-bottom: 10px;\n`;\n\nexport const NavItem = styled.li`\n  margin-bottom: 7px;\n`;\n\nexport const MadeIn = styled(P)`\n  margin-top: 7px;\n`;\n\nexport const Copyright = styled(P)`\n  font-size: 14px;\n  margin-bottom: 10px;\n`;\n"
  },
  {
    "path": "packages/site/templates/global-new/Header/index.js",
    "content": "import { Fragment } from 'react';\nimport Nav from '../Nav';\n\nexport default props => <Nav {...props} />;\n"
  },
  {
    "path": "packages/site/templates/global-new/Nav/index.js",
    "content": "import Link from 'next/link';\nimport { Container, Links, NavItem } from './styled';\nimport { withTheme } from 'styled-components';\n\nconst Nav = ({ theme, isWhite, section }) => (\n  <Container isWhite={isWhite}>\n    <Link href={theme.url}>\n      <a>\n        <theme.Logo {...theme.headerLogoSize} />\n      </a>\n    </Link>\n    <Links>\n      {theme.headerNavLinks.map(({ href, isExternal, label, id }) => (\n        <NavItem isSelected={section === id} key={id}>\n          <Link href={href}>\n            <a>{label}</a>\n          </Link>\n        </NavItem>\n      ))}\n    </Links>\n  </Container>\n);\n\nexport default withTheme(Nav);\n"
  },
  {
    "path": "packages/site/templates/global-new/Nav/styled.js",
    "content": "import styled from 'styled-components';\nimport { color, font, media, cols } from '~/styles/vars';\n\nexport const Container = styled.nav`\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n\n  ${media.large`\n    margin: 0 20px;\n  `}\n\n  ${media.medium`\n    flex-wrap: wrap;\n\n    > a,\n    > ul {\n      flex: 0 0 100%;\n      display: flex;\n      justify-content: center;\n    }\n  `} ${({ isWhite }) =>\n  isWhite &&\n  `\n    path {\n      fill: ${color.white};\n    }\n\n    a,\n    a:hover {\n      color: ${color.white};\n      font-weight: bold;\n    }\n  `};\n\n  ${media.small`margin: 0;`}\n`;\n\nexport const Links = styled.ul`\n  display: flex;\n\n  ${media.medium`margin-top: 20px`};\n\n  li {\n    margin-left: 30px;\n\n    ${media.medium`margin-left: 20px`};\n\n    &:first-child {\n      margin-left: 0;\n    }\n  }\n`;\n\nexport const NavItem = styled.li`\n  ${({ isSelected, theme }) =>\n    isSelected &&\n    `\n    position: relative;\n\n    a {\n      color: ${theme.color.base};\n    }\n\n    &:after {\n      content: '';\n      display: block;\n      position: absolute;\n      height: 3px;\n      background-color: ${theme.color.base};\n      left: 0;\n      right: 0;\n      bottom: -5px;\n    }\n  `};\n`;\n"
  },
  {
    "path": "packages/site/templates/global-new/styled.js",
    "content": "import styled from 'styled-components';\nimport Link from 'next/link';\nimport { color, font, media } from '~/styles/vars';\n\nexport const Container = styled.div`\n  ${({ theme }) => `\n    background-color: ${theme.color.base};\n    background-image: radial-gradient(120% 600px at 50% 200px, ${theme.color.base}, ${theme.color.twist} 120%);\n    min-height: 100vh;\n  `};\n  padding: 10px;\n`;\n\nexport const ContentContainer = styled.div`\n  background: ${color.white};\n  padding: ${({ noHeader }) => (noHeader ? '75px' : '30px')} 30px;\n\n  ${media.small`padding: ${({ noHeader }) =>\n    noHeader ? '10px' : '30px'} 10px;`};\n  ${media.large`padding: ${({ noHeader }) =>\n    noHeader ? '30px' : '30px'} 10px;`};\n\n  a {\n    color: ${({ theme }) => theme.color.action};\n\n    &:hover {\n      color: ${({ theme }) => theme.color.actionHighlight};\n    }\n  }\n`;\n\nexport const Section = styled.section`\n  margin: 75px auto;\n  max-width: 650px;\n`;\n\nexport const PageHeader = styled.h1`\n  font-size: 36px;\n  color: ${color.black};\n  ${font.bold};\n  letter-spacing: -1.1px;\n  text-align: center;\n  margin-bottom: 40px;\n\n  ${media.medium`\n    font-size: 24px;\n    letter-spacing: -0.5px;\n  `};\n`;\n\nexport const P = styled.p`\n  font-size: 18px;\n  line-height: 24px;\n  letter-spacing: -0.2px;\n\n  em {\n    font-weight: bold;\n  }\n\n  ${media.medium`\n    font-size: 16px;\n    line-height: 22px;\n  `};\n`;\n\nexport const ActionButton = styled.button`\n  ${({ theme }) => `\n    background-image: linear-gradient(-180deg, ${theme.color.base} 0%, ${theme.color.twist} 100%);\n    box-shadow: 0 1px 0 0 ${theme.color.baseShadow}, 0 2px 3px 0 rgba(0,0,0,0.22);\n    text-shadow: 0 -1px 0 ${theme.color.baseShadow};\n\n    &:active {\n      box-shadow: 0 1px 1px 0 rgba(0,0,0,0.22);\n      transform: translateY(1px);\n    }\n  `};\n  border-radius: 300px;\n  color: ${color.white}!important;\n  font-size: 18px;\n  ${font.body};\n  ${font.bold};\n  letter-spacing: -0.2px;\n  cursor: pointer;\n  padding: 10px 30px;\n\n  ${({ white, theme }) =>\n    white &&\n    `\n    background-image: linear-gradient(-180deg, #fff 0%, #eee 100%);\n    color: ${color.black}!important;\n    text-shadow: none;\n  `};\n\n  ${({ cta }) =>\n    cta &&\n    `\n    font-size: 24px;\n    padding: 15px 30px;\n\n    ${media.medium`font-size: 18px;`}\n  `};\n`;\n\nconst ButtonAsLink = styled(ActionButton.withComponent('a'))`\n  display: inline-block;\n`;\n\nexport const ActionLink = ({ href, ...props }) => (\n  <Link href={href}>\n    <ButtonAsLink {...props} />\n  </Link>\n);\n"
  },
  {
    "path": "packages/site/templates/homepage/index.js",
    "content": "import styled from 'styled-components';\nimport { color, media } from '~/styles/vars';\nimport Nav from '~/templates/global-new/Nav';\nimport GlobalTemplate from '~/templates/global/Template';\nimport { Container, ContentContainer } from '~/templates/global-new/styled';\n\nconst HeaderContainer = styled.header`\n  padding: 30px;\n\n  ${media.large`padding: 20px;`};\n  ${media.small`padding: 10px;`};\n`;\n\nexport default ({ title, description, theme, Header, children }) => (\n  <GlobalTemplate title={title} description={description} theme={theme}>\n    <Container>\n      <HeaderContainer>\n        <Nav isWhite />\n        <Header />\n      </HeaderContainer>\n      <ContentContainer noHeader>{children}</ContentContainer>\n    </Container>\n  </GlobalTemplate>\n);\n"
  },
  {
    "path": "packages/site/utils/string.js",
    "content": "export function htmlUnencode(str) {\n  return str\n    .replace(/&quot;/g, '\"')\n    .replace(/&#39;/g, \"'\")\n    .replace(/&lt;/g, '<')\n    .replace(/&gt;/g, '>')\n    .replace(/&amp;/g, '&');\n}\n"
  },
  {
    "path": "packages/style-value-types/CHANGELOG.md",
    "content": "# Changelog\n\nStyle Value Types adheres to [Semantic Versioning](http://semver.org/).\n\n## [5.1.2] 2022-08-15\n\n### Update\n\n-   Updating `tslib` and `typescript`.\n\n## [5.1.1] 2022-08-10\n\n### Fixed\n\n-   Supporting `rgba` and `hsla` values without spaces around the alpha slash.\n\n### Update\n\n-   Adding `types` to `exports` field.\n\n## [5.1.0] 2021-11-24\n\n### Update\n\n-   Updating `tslib`.\n\n## [5.0.0] 2021-09-23\n\n### Fixed\n\n-   Fixing `exports` and `module` in `package.json`. This will break (unsupported) direct file imports.\n\n### [4.1.5] 2021-09-21\n\n### Fixed\n\n- Making complex value type gracefully accept numbers.\n\n### [4.1.4] 2021-03-19\n\n### Fixed\n\n- Fixing `main` entry point.\n\n### [4.1.3] 2021-03-19\n\n### Fixed\n\n- Fixing `main` entry point.\n\n### [4.1.2] 2021-03-19\n\n### Added\n\n- Adding `exports` to `package.json`.\n\n### Updated\n\n- `tslib` to latest.\n\n### [4.1.1] 2021-03-01\n\n### Fixed\n\n- Fixing es entry point.\n\n### [4.1.0] 2021-03-01\n\n### Fixed\n\n- Unbundling ES code to facilitate code-splitting in Webpack.\n\n## [4.0.3] 2020-02-22\n\n### Fixed\n\n- Fixing `hasOwnProperty` call on `null` for color test.\n\n## [4.0.1] 2020-01-08\n\n### Added\n\n- Restoring support for RGBA/HSLA objects in rgba.parse/hsla.parse.\n\n## [4.0.0] 2020-01-08\n\n### Added\n\n- Support for hex alpha.\n- `filter` type.\n- Improved handling of decimals with no preceding digit.\n\n### Removed\n\n- Support for RGBA/HSLA objects in rgba.parse/hsla.parse.\n\n## [3.2.0] 2020-12-18\n\n### Fixed\n\n- Including `tslib` as a separate dependency.\n\n## [3.1.9] 2020-07-23\n\n### Fixed\n\n- Fixed opacity with whitespace syntax colors.\n\n## [3.1.8] 2020-07-23\n\n### Fixed\n\n- Fixed whitespace syntax colors.\n- Fixed HSL(A) colors containing decimals.\n\n## [3.1.7] 2019-11-14\n\n### Fixed\n\n- Updating to Typescript 3.7.\n\n## [3.1.6] 2019-07-25\n\n### Fixed\n\n- Clamping color alpha to 0-1.\n\n## [3.1.4] 2019-05-01\n\n### Fixed\n\n- Rejecting `complex` values in `color` tests.\n\n## [3.1.3] 2019-04-29\n\n### Fixed\n\n- Dynamic type imports.\n\n## [3.1.2] 2019-04-29\n\n### Removed\n\n- Hard `ValueType` typing from `complex`.\n\n## [3.1.1] 2019-04-29\n\n### Added\n\n- `getAnimatableNone` to `complex` value type.\n\n## [3.1.0] 2019-03-12\n\n### Added\n\n- `progressPercentage` value type.\n\n## [3.0.7] 2018-08-30\n\n### Fixed\n\n- Preventing unit types from matching anything that contains that string ie px matching to `blur(20px)`.\n\n## [3.0.6] 2018-08-16\n\n### Fixed\n\n- Detecting exponential values in complex.createTransformer. [#423](https://github.com/Popmotion/popmotion/issues/423)\n\n## [3.0.5] 2018-08-14\n\n### Fixed\n\n- Preventing `complex` from matching `number`.\n\n## [3.0.4] 2018-08-13\n\n### Fixed\n\n- Fixed a bug in the complex value type where single function-like values, like `grayscale(0%)` aren't recognised as complex value types.\n\n## [3.0.3] 2018-06-28\n\n### Fixed\n\n- Fixing error in `tsconfig.json` that leaves code untranspiled.\n\n## [3.0.2] 2018-06-27\n\n### Fixed\n\n- Improving color regex to pick 6-letter hex codes first.\n\n## [3.0.1] 2018-06-27\n\n### Fixed\n\n- Fixing template algo.\n\n## [3.0.0] 2018-06-22\n\n### Removed\n\n- Removed new `combo` in favour of a single unified `complex` value type that can handle mixed number and color strings.\n\n## [2.0.1] 2018-06-21\n\n### Fixed\n\n- Now finding colors containing spaces within combo values.\n\n## [2.0.0] 2018-06-20\n\n### Added\n\n- New units: `vh`, `vw`\n- New space-delimited combo type\n- Strengthened unit type tests\n- Color types can accept already-parsed numbers\n"
  },
  {
    "path": "packages/style-value-types/LICENSE.md",
    "content": "The MIT License (MIT)\nCopyright (c) 2018 Popmotion\n\nPermission 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:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE 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."
  },
  {
    "path": "packages/style-value-types/README.md",
    "content": "# Style Value Types\nParsers, transformers and tests for common style value types, eg: %, hex codes etc.\n\nTo help convert numerical values into commonly-used special value types, like `px` or `hex`, we provide an optional module called `style-value-types`:\n\n```bash\nnpm install style-value-types --save \n```\n\nEach value type has three functions:\n\n- `test`: Returns `true` if the provided value is of that type.\n- `parse`: Returns the value in a format suitable for animation. Either a `number` or `{ [key: string]: number }`.\n\nAnd one of:\n- `transform`: The reverse of `parse`. Accepts a `number` or map of named numbers and converts that into the value type.\n- `createTransformer`: Accepts a value and returns a `transform` based on that specific value.\n\n## Import\n\n```javascript\nimport { color } from 'style-value-types';\n```\n\n## Example\n\n```javascript\n// Test\ncolor.test('#fff'); // true\ncolor.test(0); // false\n\n// Parse\ncolor.parse('rgba(255, 255, 255, 0)');\n// { red: 255, green: 255, blue: 255, alpha: 0 }\n\n// Transform\ncolor.transform({ hue: 200, saturation: 100, lightness: 50, alpha: 0.5 });\n// 'hsla(200, 100%, 50%, 0.5)'\n```\n\n## Included value types\n\n- `alpha`: `Number` between `0` and `1`\n- `complex`: Handles space and comma delimited values, like CSS box-shadow: `'10px 10px inset #f00, 5px 5px 30px #fff'`, gradient or a path definition.\n- `color`: `String` of either `hex`, `hsla` or `rgba` type\n- `degrees`: `String` ending in `deg`\n- `hex`: `String` beginning with `#` and followed by 3 or 6-digit hex code\n- `hsla`: `String` with valid `hsla` property\n- `percent`: `String` ending in `%`\n- `px`: `String` ending in `px`\n- `scale`: `Number` with a `default` of `1` instead of `0`\n- `rgbUnit`: Integer between `1` and `255`\n- `rgba`: String in `rgba(rgbUnit, rgbUnit, rgbUnit, alpha)` format\n\n## complex\n\nThe `complex` value type is slightly different to the others. Instead of a `transform` method, it has a `createTransformer` method which returns the `transform` method:\n\n```javascript\nconst svgPath = 'M150 0 L75 200';\nconst transform = complex.createTransformer(svgPath);\n```\n\nThe returned `transform` function is unique to the string given to it. When this function is provided an object of the same format as returned by `complex.parse()` (in this example `complex.parse(svgPath)`), it will use the original string as a template.\n"
  },
  {
    "path": "packages/style-value-types/package.json",
    "content": "{\n  \"name\": \"style-value-types\",\n  \"version\": \"5.1.2\",\n  \"description\": \"Parsers, transformers and tests for special value types, eg: %, hex codes etc.\",\n  \"main\": \"dist/valueTypes.cjs.js\",\n  \"types\": \"lib/index.d.ts\",\n  \"module\": \"dist/es/index.mjs\",\n  \"jsnext:main\": \"dist/es/index.mjs\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./lib/index.d.ts\",\n      \"import\": \"./dist/es/index.mjs\",\n      \"require\": \"./dist/valueTypes.cjs.js\",\n      \"default\": \"./dist/valueTypes.cjs.js\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"files\": [\n    \"lib\",\n    \"dist\"\n  ],\n  \"sideEffects\": false,\n  \"scripts\": {\n    \"build\": \"tsc -p . && rollup -c && yarn measure\",\n    \"watch\": \"rollup -c -w\",\n    \"lint\": \"tslint -c tslint.json 'src/**/*.{ts}'\",\n    \"test\": \"jest --maxWorkers=2\",\n    \"measure\": \"gzip -c dist/style-value-types.min.js | wc -c\",\n    \"prepublishOnly\": \"npm run test && npm run build\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/Popmotion/popmotion/tree/master/packages/style-value-types\"\n  },\n  \"keywords\": [\n    \"css\",\n    \"svg\",\n    \"hex\",\n    \"rgba\",\n    \"hsla\"\n  ],\n  \"author\": \"Matt Perry\",\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/Popmotion/popmotion/issues\"\n  },\n  \"homepage\": \"https://popmotion.io\",\n  \"devDependencies\": {\n    \"@types/jest\": \"^23.1.1\",\n    \"webpack\": \"^3.12.0\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"ts\",\n      \"js\"\n    ],\n    \"transform\": {\n      \"\\\\.(ts)$\": \"../../../node_modules/ts-jest/preprocessor.js\"\n    },\n    \"testRegex\": \"/_tests/.*\\\\.(ts|tsx|js)$\",\n    \"rootDir\": \"src\",\n    \"testURL\": \"http://localhost/\"\n  },\n  \"unpkg\": \"./dist/style-value-types.min.js\",\n  \"prettier\": {\n    \"parser\": \"typescript\",\n    \"singleQuote\": true\n  },\n  \"dependencies\": {\n    \"hey-listen\": \"^1.0.8\",\n    \"tslib\": \"2.4.0\"\n  }\n}\n"
  },
  {
    "path": "packages/style-value-types/rollup.config.js",
    "content": "import generateConfig from '../../rollup-generate-config';\nimport pkg from './package.json';\n\nexport default generateConfig(pkg, 'valueTypes');\n"
  },
  {
    "path": "packages/style-value-types/src/_tests/index.test.ts",
    "content": "import {\n  alpha,\n  hex,\n  rgba,\n  rgbUnit,\n  hsla,\n  color,\n  px,\n  degrees,\n  percent,\n  progressPercentage,\n  complex,\n  filter,\n} from '../';\nimport { singleColorRegex, colorRegex, floatRegex } from '../utils';\n\nconst PATH = 'M150 0 L75 200 L225 200 Z';\nconst GREYSCALE = 'greyscale(100%)';\nconst PATH_VALUES = [150, 0, 75, 200, 225, 200];\nconst MIXED = '0px 0px 0px rgba(161, 0, 246, 0)';\n\ndescribe('regex', () => {\n  it('should correctly identify values', () => {\n    expect(singleColorRegex.test('#fff000')).toBe(true);\n    expect(singleColorRegex.test('#fff000aa')).toBe(true);\n    expect(singleColorRegex.test('rgba(161, 0, 246, 0)')).toBe(true);\n    expect(singleColorRegex.test('rgba(161 0 246 / 0)')).toBe(true);\n    expect(singleColorRegex.test('rgba(161 0 246/0)')).toBe(true);\n    expect(\n      singleColorRegex.test('rgba(161 0 246 / 0) rgba(161 0 246 / 0)')\n    ).toBe(false);\n    expect(singleColorRegex.test('#fff000 #fff000')).toBe(false);\n    expect(colorRegex.test('#fff000 #fff000aa')).toBe(true);\n    expect(colorRegex.test('rgba(161 0 246 / 0) rgba(161 0 246 / 0)')).toBe(\n      true\n    );\n\n    expect(\n      'rgba(161 0 246 / 0) rgba(161 0 246 / 0)'.match(colorRegex)?.length\n    ).toEqual(2);\n\n    expect(colorRegex.test('rgba(161 0 246/0) rgba(161 0 246/0)')).toBe(true);\n\n    expect(\n      'rgba(161 0 246/0) rgba(161 0 246/0)'.match(colorRegex)?.length\n    ).toEqual(2);\n\n    expect(\n      'a0.9b 1 2 -3 -4.0 -.5 -0.6 a.7b 800 10.0009'.match(floatRegex)\n    ).toEqual([\n      '0.9',\n      '1',\n      '2',\n      '-3',\n      '-4.0',\n      '-.5',\n      '-0.6',\n      '.7',\n      '800',\n      '10.0009',\n    ]);\n    expect('hsla(177, 37.4978%, 76.66804%, 1)'.match(floatRegex)).toEqual([\n      '177',\n      '37.4978',\n      '76.66804',\n      '1',\n    ]);\n  });\n});\n\ndescribe('complex value type', () => {\n  it('test returns correctly', () => {\n    expect(complex.test(GREYSCALE)).toBe(true);\n    expect(complex.test(PATH)).toBe(true);\n    expect(complex.test(3)).toBe(false);\n    expect(complex.test('3')).toBe(false);\n    expect(complex.test('3px')).toBe(true);\n    expect(complex.test(MIXED)).toBe(true);\n  });\n\n  it('parse converts string to array', () => {\n    expect(complex.parse(PATH)).toEqual(PATH_VALUES);\n    expect(complex.parse(GREYSCALE)).toEqual([100]);\n    expect(complex.parse(MIXED)).toEqual([\n      { red: 161, green: 0, blue: 246, alpha: 0 },\n      0,\n      0,\n      0,\n    ]);\n    expect(complex.parse('0px 0px 0px rgba(161 0 246 / 0.5)')).toEqual([\n      { red: 161, green: 0, blue: 246, alpha: 0.5 },\n      0,\n      0,\n      0,\n    ]);\n  });\n\n  it('createTransformer returns a transformer function that correctly inserts values', () => {\n    const transform = complex.createTransformer(PATH);\n    expect(transform(PATH_VALUES)).toBe(PATH);\n\n    const transformMixedExpo = complex.createTransformer(\n      '0px 0px 0px rgba(161, 0, 246, 0)'\n    );\n    expect(\n      transformMixedExpo([\n        {\n          red: 161,\n          green: 0,\n          blue: 246,\n          alpha: 6.399999974426862e-10,\n        },\n        0,\n        1.5999999547489097e-8,\n        3.199999909497819e-8,\n      ])\n    ).toBe('0px 0px 0px rgba(161, 0, 246, 0)');\n\n    const transformSingleFunction = complex.createTransformer(GREYSCALE);\n    expect(transformSingleFunction([100])).toBe(GREYSCALE);\n\n    const transformSingleNumber = complex.createTransformer(2);\n    expect(transformSingleNumber([100])).toBe('100');\n  });\n\n  it('can create an animatable \"none\"', () => {\n    expect(complex.getAnimatableNone('100% 0px #fff')).toBe(\n      '0% 0px rgba(255, 255, 255, 1)'\n    );\n  });\n});\n\nconst red = {\n  red: 255,\n  green: 0,\n  blue: 0,\n  alpha: 1,\n};\n\nconst redOutOfRange = {\n  red: 300,\n  green: 0,\n  blue: 0,\n  alpha: 2,\n};\n\nconst hslaTestColor = {\n  hue: 170,\n  saturation: 50,\n  lightness: 45,\n  alpha: 1,\n};\n\nconst hslaOutOfRange = {\n  hue: 170,\n  saturation: 50,\n  lightness: 45,\n  alpha: 2,\n};\n\ndescribe('hex()', () => {\n  it('should correctly test for colors', () => {\n    expect(hex.test('#f00')).toEqual(true);\n    expect(hex.test('#f00a')).toEqual(true);\n    expect(hex.test('#f000aa')).toEqual(true);\n    expect(hex.test('#f000aa00')).toEqual(true);\n    expect(hex.test('#f00 0px')).toEqual(false);\n    expect(hex.test(red)).toEqual(false);\n  });\n\n  it('should split a hex value into the correct params', () => {\n    expect(hex.parse('#f00')).toEqual(red);\n    expect(hex.parse('#ff0000')).toEqual(red);\n    expect(hex.parse('#ffff00')).not.toEqual(red);\n    expect(hex.parse('#ff0000ff')).toEqual(red);\n    expect(hex.parse('#ff000000')).not.toEqual(red);\n    expect(hex.parse('#f00f')).toEqual(red);\n    expect(hex.parse('#f000')).not.toEqual(red);\n  });\n\n  it('should correctly combine a hex value', () => {\n    expect(hex.transform(red)).toBe('rgba(255, 0, 0, 1)');\n  });\n});\n\ndescribe('rgba()', () => {\n  it('should correctly test for colors', () => {\n    expect(rgba.test('rgba(255, 0, 0, 0.5)')).toEqual(true);\n    expect(rgba.test('rgba(255 0 0 / 0.5)')).toEqual(true);\n    expect(rgba.test('rgba(255, 0, 0, 0.5) 0px')).toEqual(false);\n    expect(rgba.test({ red: 255 })).toEqual(true);\n    expect(rgba.test({ hue: 255 })).toEqual(false);\n  });\n\n  it('should split an rgba value into the correct params', () => {\n    expect(rgba.parse('rgba(255, 0, 0, 0.5)')).toEqual({ ...red, alpha: 0.5 });\n    expect(rgba.parse('rgb(255,0,0)')).toEqual(red);\n    expect(rgba.parse('rgb(255,250,1)')).toEqual({\n      red: 255,\n      green: 250,\n      blue: 1,\n      alpha: 1,\n    });\n    expect(rgba.parse('rgb(255 0 0)')).toEqual(red);\n    expect(rgba.parse('rgba(161 0 246 / 0)')).toEqual({\n      red: 161,\n      green: 0,\n      blue: 246,\n      alpha: 0,\n    });\n    expect(rgba.parse(red)).toEqual(red);\n  });\n\n  it('should correctly combine rgba value', () => {\n    expect(rgba.transform(red)).toEqual('rgba(255, 0, 0, 1)');\n    expect(rgba.transform(redOutOfRange)).toEqual('rgba(255, 0, 0, 1)');\n  });\n});\n\ndescribe('hsla()', () => {\n  it('should correctly test for colors', () => {\n    expect(hsla.test('hsla(170, 50%, 45%, 1)')).toEqual(true);\n    expect(hsla.test('hsla(177, 37.4978%, 76.66804%, 1)')).toEqual(true);\n    expect(hsla.test('hsla(170 50% 45% / 1)')).toEqual(true);\n    expect(hsla.test('hsla(170 50% 45%/1)')).toEqual(true);\n    expect(hsla.test('hsla(177 37.4978% 76.66804% / 1)')).toEqual(true);\n    expect(hsla.test('hsla(170, 50%, 45%, 1) 0px')).toEqual(false);\n  });\n\n  it('should split an hsl value into the correct params', () => {\n    expect(hsla.parse('hsla(170, 50%, 45%, 1)')).toEqual(hslaTestColor);\n    expect(hsla.parse('hsl(170, 50%, 45%)')).toEqual(hslaTestColor);\n    expect(hsla.parse('hsla(170 50% 45% 1)')).toEqual(hslaTestColor);\n    expect(hsla.parse('hsl(170 50% 45%)')).toEqual(hslaTestColor);\n    expect(hsla.parse('hsla(177, 37.4978%, 76.66804%, 1)')).toEqual({\n      hue: 177,\n      saturation: 37.4978,\n      lightness: 76.66804,\n      alpha: 1,\n    });\n    expect(hsla.parse('hsla(177 37.4978% 76.66804% / 1)')).toEqual({\n      hue: 177,\n      saturation: 37.4978,\n      lightness: 76.66804,\n      alpha: 1,\n    });\n    expect(hsla.parse('hsla(177 37.4978% 76.66804% / 0.5)')).toEqual({\n      hue: 177,\n      saturation: 37.4978,\n      lightness: 76.66804,\n      alpha: 0.5,\n    });\n    expect(hsla.parse('hsla(177 37.4978% 76.66804%/0.5)')).toEqual({\n      hue: 177,\n      saturation: 37.4978,\n      lightness: 76.66804,\n      alpha: 0.5,\n    });\n    expect(hsla.parse(hslaTestColor)).toEqual(hslaTestColor);\n  });\n\n  it('should correctly combine hsla value', () => {\n    expect(hsla.transform(hslaTestColor)).toEqual('hsla(170, 50%, 45%, 1)');\n    expect(hsla.transform(hslaOutOfRange)).toEqual('hsla(170, 50%, 45%, 1)');\n    expect(\n      hsla.transform({\n        hue: 177,\n        saturation: 37.4978,\n        lightness: 76.66804,\n        alpha: 1,\n      })\n    ).toEqual('hsla(177, 37.4978%, 76.66804%, 1)');\n  });\n});\n\ndescribe('color()', () => {\n  it('should split the color with the appropriate parser', () => {\n    expect(color.parse('rgba(255, 0, 0, 1)')).toEqual(red);\n    expect(color.parse('rgba(255, 0, 0, 0.8)')).toEqual({ ...red, alpha: 0.8 });\n    expect(color.parse('rgba(255, 0, 0, .8)')).toEqual({ ...red, alpha: 0.8 });\n    expect(color.parse('rgba(255, 0, 0,.8)')).toEqual({ ...red, alpha: 0.8 });\n    expect(color.parse('#f00')).toEqual(red);\n    expect(color.parse('#f00f')).toEqual(red);\n    expect(color.parse('hsla(170, 50%, 45%, 1)')).toEqual(hslaTestColor);\n  });\n\n  it('should correctly combine color value', () => {\n    expect(color.transform(red)).toEqual('rgba(255, 0, 0, 1)');\n    expect(color.transform('rgba(255, 0, 0, 1)')).toEqual('rgba(255, 0, 0, 1)');\n    expect(color.transform(hslaTestColor)).toEqual('hsla(170, 50%, 45%, 1)');\n  });\n\n  it('should correctly identify color', () => {\n    expect(color.test('#e66465')).toBe(true);\n    expect(color.test('#fff')).toBe(true);\n    expect(color.test('#fff000')).toBe(true);\n    expect(color.test('#fff000aa')).toBe(true);\n    expect(color.test('#fff 0px')).toBe(false);\n    expect(color.test('#f0f0f0')).toBe(true);\n    expect(color.test('rgb(233, 233, 1)')).toBe(true);\n    expect(color.test('rgb(0, 0, 0) 5px 5px 50px 0px')).toBe(false);\n    expect(color.test('rgba(255, 255, 0, 1)')).toBe(true);\n    expect(color.test('rgba(255,255,0,1)')).toBe(true);\n    expect(color.test('rgba(255,255, 0,1)')).toBe(true);\n    expect(color.test('hsl(0, 0%, 0%)')).toBe(true);\n    expect(color.test('hsl(0, 0%,0%)')).toBe(true);\n    expect(color.test('hsla(180, 360%, 360%, 0.5)')).toBe(true);\n    expect(color.test('hsla(180, 360%, 360%, 0.5) 0px')).toBe(false);\n    expect(color.test('greensock')).toBe(false);\n    expect(color.test('filter(190deg)')).toBe(false);\n  });\n});\n\ndescribe('unit transformers', () => {\n  it('should correctly identify units', () => {\n    expect(px.test(10)).toBe(false);\n    expect(px.test('10px')).toBe(true);\n    expect(px.test('blur(10px)')).toBe(false);\n    expect(percent.test('10px')).toBe(false);\n    expect(percent.test('10%')).toBe(true);\n    expect(percent.test('blur(10%)')).toBe(false);\n  });\n\n  it('should append the correct units', () => {\n    expect(px.transform(10)).toBe('10px');\n    expect(degrees.transform(360)).toBe('360deg');\n    expect(percent.transform(100)).toBe('100%');\n    expect(rgbUnit.transform(256)).toBe(255);\n    expect(rgbUnit.transform(24.5)).toBe(25);\n    expect(\n      rgba.transform({\n        red: 256,\n        green: 24.5,\n        blue: 0,\n      })\n    ).toBe('rgba(255, 25, 0, 1)');\n    expect(\n      hsla.transform({\n        hue: 100,\n        saturation: 50,\n        lightness: 50,\n        alpha: 1,\n      })\n    ).toBe('hsla(100, 50%, 50%, 1)');\n    expect(alpha.transform(2)).toBe(1);\n    expect(\n      color.transform({\n        red: 256,\n        green: 24.5,\n        blue: 0,\n      })\n    ).toBe('rgba(255, 25, 0, 1)');\n    expect(\n      color.transform({\n        hue: 100,\n        saturation: 50,\n        lightness: 50,\n        alpha: 1,\n      })\n    ).toBe('hsla(100, 50%, 50%, 1)');\n  });\n});\n\ndescribe('combination values', () => {\n  it('should test correctly', () => {\n    expect(complex.test('20px 20px 10px inset #fff')).toEqual(true);\n    expect(\n      complex.test('20px 20px 10px inset rgba(255, 255, 255, 1), 20px')\n    ).toEqual(true);\n    expect(\n      complex.test('linear-gradient(0.25turn, #3f87a6, #ebf8e1, #f69d3c')\n    ).toEqual(true);\n  });\n\n  it('should parse into an array', () => {\n    expect(complex.parse('0px 10px #fff')).toEqual([\n      { red: 255, green: 255, blue: 255, alpha: 1 },\n      0,\n      10,\n    ]);\n    expect(complex.parse('20px 20px 10px inset #fff')).toEqual([\n      { red: 255, green: 255, blue: 255, alpha: 1 },\n      20,\n      20,\n      10,\n    ]);\n    expect(\n      complex.parse('20px 20px 10px inset rgba(255, 255, 255, 1)')\n    ).toEqual([{ red: 255, green: 255, blue: 255, alpha: 1 }, 20, 20, 10]);\n    expect(\n      complex.parse(\n        '20px 20px 10px inset #fff, 20px 20px 10px inset rgba(255, 255, 255, 1)'\n      )\n    ).toEqual([\n      { red: 255, green: 255, blue: 255, alpha: 1 },\n      { red: 255, green: 255, blue: 255, alpha: 1 },\n      20,\n      20,\n      10,\n      20,\n      20,\n      10,\n    ]);\n    expect(complex.parse('linear-gradient(0.25turn, #fff)')).toEqual([\n      {\n        red: 255,\n        green: 255,\n        blue: 255,\n        alpha: 1,\n      },\n      0.25,\n    ]);\n    expect(\n      complex.parse('linear-gradient(1deg, rgba(255, 255, 255, 1))')\n    ).toEqual([\n      {\n        red: 255,\n        green: 255,\n        blue: 255,\n        alpha: 1,\n      },\n      1,\n    ]);\n\n    expect(\n      complex.parse(\n        'linear-gradient(217deg, rgba(255,0,0,.8), rgba(255,0,0,0) 70.71%)'\n      )\n    ).toEqual([\n      {\n        red: 255,\n        green: 0,\n        blue: 0,\n        alpha: 0.8,\n      },\n      {\n        red: 255,\n        green: 0,\n        blue: 0,\n        alpha: 0,\n      },\n      217,\n      70.71,\n    ]);\n\n    expect(\n      complex.parse('radial-gradient(circle at 50% 25%, #e66465, #9198e5)')\n    ).toEqual([\n      { alpha: 1, blue: 101, green: 100, red: 230 },\n      { alpha: 1, blue: 229, green: 152, red: 145 },\n      50,\n      25,\n    ]);\n  });\n\n  it('should create a transformer', () => {\n    const animatable = complex.parse(\n      '20px 20px 10px inset rgba(255, 255, 255, 1), 20px 20px 10px inset #fff'\n    );\n    const transformer = complex.createTransformer(\n      '20px 20px 10px inset #fff, 20px 20px 10px inset rgba(255, 255, 255, 1)'\n    );\n\n    expect(transformer(animatable)).toBe(\n      '20px 20px 10px inset rgba(255, 255, 255, 1), 20px 20px 10px inset rgba(255, 255, 255, 1)'\n    );\n\n    const gradient = complex.parse(\n      'linear-gradient(217deg, rgba(255,0,0,.8), rgba(255,0,0,0) 70.71%)'\n    );\n    const gradientTransformer = complex.createTransformer(\n      'linear-gradient(217deg, rgba(255,0,0,.8), rgba(255,0,0,0) 70.71%)'\n    );\n    expect(gradientTransformer(gradient)).toBe(\n      'linear-gradient(217deg, rgba(255, 0, 0, 0.8), rgba(255, 0, 0, 0) 70.71%)'\n    );\n  });\n});\n\ndescribe('progress value type', () => {\n  it('should test correctly', () => {\n    expect(progressPercentage.test('100%')).toBe(true);\n    expect(progressPercentage.test('100px')).toBe(false);\n  });\n  it('should parse correctly', () => {\n    expect(progressPercentage.parse('50%')).toBe(0.5);\n    expect(progressPercentage.parse('0%')).toBe(0);\n    expect(progressPercentage.parse('-200%')).toBe(-2);\n  });\n  it('should transform correctly', () => {\n    expect(progressPercentage.transform(0.1)).toBe('10%');\n    expect(progressPercentage.transform(1.5)).toBe('150%');\n  });\n});\n\ndescribe('filter', () => {\n  it('should create an animatableNone with correct default values', () => {\n    expect(\n      filter.getAnimatableNone(\n        'blur(10.5px) brightness(50.5%) contrast(50.5%) drop-shadow(10px 10px #fff) grayscale(50.5%) hue-rotate(90deg) invert(50%) opacity(0.5) saturate(50.5%) sepia(50.5%)'\n      )\n    ).toEqual(\n      'blur(0px) brightness(100%) contrast(100%) drop-shadow(10px 10px #fff) grayscale(0%) hue-rotate(0deg) invert(0%) opacity(1) saturate(100%) sepia(0%)'\n    );\n    expect(\n      filter.getAnimatableNone(\n        'blur(5rem) brightness(0.5) contrast(0.5) drop-shadow(10px 10px #fff) grayscale(0.5) hue-rotate(1.75turn) invert(0.5) opacity(0.5) saturate(0.5) sepia(0.5)'\n      )\n    ).toEqual(\n      'blur(0rem) brightness(1) contrast(1) drop-shadow(10px 10px #fff) grayscale(0) hue-rotate(0turn) invert(0) opacity(1) saturate(1) sepia(0)'\n    );\n  });\n});\n"
  },
  {
    "path": "packages/style-value-types/src/color/hex.ts",
    "content": "import { RGBA, ValueType } from '../types';\nimport { rgba } from './rgba';\nimport { isColorString } from './utils';\n\nfunction parseHex(v: string): RGBA {\n  let r = '';\n  let g = '';\n  let b = '';\n  let a = '';\n\n  // If we have 6 characters, ie #FF0000\n  if (v.length > 5) {\n    r = v.substr(1, 2);\n    g = v.substr(3, 2);\n    b = v.substr(5, 2);\n    a = v.substr(7, 2);\n\n    // Or we have 3 characters, ie #F00\n  } else {\n    r = v.substr(1, 1);\n    g = v.substr(2, 1);\n    b = v.substr(3, 1);\n    a = v.substr(4, 1);\n    r += r;\n    g += g;\n    b += b;\n    a += a;\n  }\n\n  return {\n    red: parseInt(r, 16),\n    green: parseInt(g, 16),\n    blue: parseInt(b, 16),\n    alpha: a ? parseInt(a, 16) / 255 : 1,\n  };\n}\n\nexport const hex: ValueType = {\n  test: isColorString('#'),\n  parse: parseHex,\n  transform: rgba.transform,\n};\n"
  },
  {
    "path": "packages/style-value-types/src/color/hsla.ts",
    "content": "import { alpha as alphaType } from '../numbers';\nimport { percent } from '../numbers/units';\nimport { HSLA, ValueType } from '../types';\nimport { sanitize } from '../utils';\nimport { isColorString, splitColor } from './utils';\n\nexport const hsla: ValueType = {\n  test: isColorString('hsl', 'hue'),\n  parse: splitColor('hue', 'saturation', 'lightness'),\n  transform: ({ hue, saturation, lightness, alpha = 1 }: HSLA) => {\n    return (\n      'hsla(' +\n      Math.round(hue) +\n      ', ' +\n      percent.transform(sanitize(saturation)) +\n      ', ' +\n      percent.transform(sanitize(lightness)) +\n      ', ' +\n      sanitize(alphaType.transform(alpha)) +\n      ')'\n    );\n  },\n};\n"
  },
  {
    "path": "packages/style-value-types/src/color/index.ts",
    "content": "import { HSLA, RGBA, ValueType } from '../types';\nimport { isString } from '../utils';\nimport { hex } from './hex';\nimport { hsla } from './hsla';\nimport { rgba } from './rgba';\n\nexport const color: ValueType = {\n  test: (v: any) => rgba.test(v) || hex.test(v) || hsla.test(v),\n  parse: (v: any) => {\n    if (rgba.test(v)) {\n      return rgba.parse(v);\n    } else if (hsla.test(v)) {\n      return hsla.parse(v);\n    } else {\n      return hex.parse(v);\n    }\n  },\n  transform: (v: HSLA | RGBA | string) => {\n    return isString(v)\n      ? v\n      : v.hasOwnProperty('red')\n      ? rgba.transform(v)\n      : hsla.transform(v);\n  },\n};\n"
  },
  {
    "path": "packages/style-value-types/src/color/rgba.ts",
    "content": "import { alpha as alphaType, number } from '../numbers';\nimport { RGBA, ValueType } from '../types';\nimport { clamp, sanitize } from '../utils';\nimport { isColorString, splitColor } from './utils';\n\nconst clampRgbUnit = clamp(0, 255);\nexport const rgbUnit: ValueType = {\n  ...number,\n  transform: (v: number) => Math.round(clampRgbUnit(v)),\n};\n\nexport const rgba: ValueType = {\n  test: isColorString('rgb', 'red'),\n  parse: splitColor('red', 'green', 'blue'),\n  transform: ({ red, green, blue, alpha = 1 }: RGBA) =>\n    'rgba(' +\n    rgbUnit.transform(red) +\n    ', ' +\n    rgbUnit.transform(green) +\n    ', ' +\n    rgbUnit.transform(blue) +\n    ', ' +\n    sanitize(alphaType.transform(alpha)) +\n    ')',\n};\n"
  },
  {
    "path": "packages/style-value-types/src/color/utils.ts",
    "content": "import { Color } from '../types';\nimport { floatRegex, isString, singleColorRegex } from '../utils';\n\n/**\n * Returns true if the provided string is a color, ie rgba(0,0,0,0) or #000,\n * but false if a number or multiple colors\n */\nexport const isColorString = (type: string, testProp?: string) => (v: any) => {\n  return Boolean(\n    (isString(v) && singleColorRegex.test(v) && v.startsWith(type)) ||\n      (testProp && Object.prototype.hasOwnProperty.call(v, testProp))\n  );\n};\n\nexport const splitColor = (aName: string, bName: string, cName: string) => (\n  v: string | Color\n) => {\n  if (!isString(v)) return v;\n\n  const [a, b, c, alpha] = v.match(floatRegex);\n\n  return {\n    [aName]: parseFloat(a),\n    [bName]: parseFloat(b),\n    [cName]: parseFloat(c),\n    alpha: alpha !== undefined ? parseFloat(alpha) : 1,\n  };\n};\n"
  },
  {
    "path": "packages/style-value-types/src/complex/filter.ts",
    "content": "import { complex } from '.';\nimport { floatRegex } from '../utils';\n\n/**\n * Properties that should default to 1 or 100%\n */\nconst maxDefaults = new Set(['brightness', 'contrast', 'saturate', 'opacity']);\n\nfunction applyDefaultFilter(v: string) {\n  let [name, value] = v.slice(0, -1).split('(');\n\n  if (name === 'drop-shadow') return v;\n\n  const [number] = value.match(floatRegex) || [];\n  if (!number) return v;\n\n  const unit = value.replace(number, '');\n  let defaultValue = maxDefaults.has(name) ? 1 : 0;\n  if (number !== value) defaultValue *= 100;\n\n  return name + '(' + defaultValue + unit + ')';\n}\n\nconst functionRegex = /([a-z-]*)\\(.*?\\)/g;\n\nexport const filter = {\n  ...complex,\n  getAnimatableNone: (v: string) => {\n    const functions = v.match(functionRegex);\n    return functions ? functions.map(applyDefaultFilter).join(' ') : v;\n  },\n};\n"
  },
  {
    "path": "packages/style-value-types/src/complex/index.ts",
    "content": "import { color } from '../color';\nimport { number } from '../numbers';\nimport { Color } from '../types';\nimport { colorRegex, floatRegex, isString, sanitize } from '../utils';\n\nconst colorToken = '${c}';\nconst numberToken = '${n}';\n\nfunction test(v: any) {\n  return (\n    isNaN(v) &&\n    isString(v) &&\n    (v.match(floatRegex)?.length ?? 0) + (v.match(colorRegex)?.length ?? 0) > 0\n  );\n}\n\nfunction analyse(v: string | number) {\n  if (typeof v === 'number') v = `${v}`;\n\n  const values: Array<Color | number> = [];\n  let numColors = 0;\n\n  const colors = v.match(colorRegex);\n  if (colors) {\n    numColors = colors.length;\n    // Strip colors from input so they're not picked up by number regex.\n    // There's a better way to combine these regex searches, but its beyond my regex skills\n    v = v.replace(colorRegex, colorToken);\n    values.push(...colors.map(color.parse));\n  }\n\n  const numbers = v.match(floatRegex);\n  if (numbers) {\n    v = v.replace(floatRegex, numberToken);\n    values.push(...numbers.map(number.parse));\n  }\n\n  return { values, numColors, tokenised: v };\n}\n\nfunction parse(v: string | number) {\n  return analyse(v).values;\n}\n\nfunction createTransformer(v: string | number) {\n  const { values, numColors, tokenised } = analyse(v);\n  const numValues = values.length;\n\n  return (v: Array<Color | number | string>) => {\n    let output = tokenised;\n\n    for (let i = 0; i < numValues; i++) {\n      output = output.replace(\n        i < numColors ? colorToken : numberToken,\n        i < numColors ? color.transform(v[i]) : sanitize(v[i] as number)\n      );\n    }\n\n    return output;\n  };\n}\n\nconst convertNumbersToZero = (v: number | Color) =>\n  typeof v === 'number' ? 0 : v;\n\nfunction getAnimatableNone(v: string | number) {\n  const parsed = parse(v);\n  const transformer = createTransformer(v);\n  return transformer(parsed.map(convertNumbersToZero));\n}\n\nexport const complex = { test, parse, createTransformer, getAnimatableNone };\n"
  },
  {
    "path": "packages/style-value-types/src/index.ts",
    "content": "export * from './types';\nexport { number, scale, alpha } from './numbers';\nexport {\n  degrees,\n  percent,\n  progressPercentage,\n  px,\n  vw,\n  vh,\n} from './numbers/units';\nexport { hsla } from './color/hsla';\nexport { rgba, rgbUnit } from './color/rgba';\nexport { hex } from './color/hex';\nexport { color } from './color';\nexport { complex } from './complex';\nexport { filter } from './complex/filter';\n"
  },
  {
    "path": "packages/style-value-types/src/numbers/index.ts",
    "content": "import { clamp } from '../utils';\nimport { ValueType } from '../types';\n\nexport const number: ValueType = {\n  test: (v) => typeof v === 'number',\n  parse: parseFloat,\n  transform: (v: number) => v,\n};\n\nexport const alpha: ValueType = {\n  ...number,\n  transform: clamp(0, 1),\n};\n\nexport const scale: ValueType = {\n  ...number,\n  default: 1,\n};\n"
  },
  {
    "path": "packages/style-value-types/src/numbers/units.ts",
    "content": "import { ValueType } from '../types';\nimport { isString } from '../utils';\n\nconst createUnitType = (unit: string): ValueType => ({\n  test: (v: string) =>\n    isString(v) && v.endsWith(unit) && v.split(' ').length === 1,\n  parse: parseFloat,\n  transform: (v: number | string) => `${v}${unit}`,\n});\n\nexport const degrees = createUnitType('deg');\nexport const percent = createUnitType('%');\nexport const px = createUnitType('px');\nexport const vh = createUnitType('vh');\nexport const vw = createUnitType('vw');\n\nexport const progressPercentage: ValueType = {\n  ...percent,\n  parse: (v: string) => percent.parse(v) / 100,\n  transform: (v: number) => percent.transform(v * 100),\n};\n"
  },
  {
    "path": "packages/style-value-types/src/types.ts",
    "content": "export type Transformer = (v: any) => any;\n\nexport type ValueType = {\n  test: (v: any) => boolean;\n  parse: (v: any) => any;\n  transform?: Transformer;\n  createTransformer?: (template: string) => Transformer;\n  default?: any;\n  getAnimatableNone?: (v: any) => any;\n};\n\nexport type NumberMap = {\n  [key: string]: number;\n};\n\nexport type RGBA = {\n  red: number;\n  green: number;\n  blue: number;\n  alpha?: number;\n};\n\nexport type HSLA = {\n  hue: number;\n  saturation: number;\n  lightness: number;\n  alpha?: number;\n};\n\nexport type Color = HSLA | RGBA;\n"
  },
  {
    "path": "packages/style-value-types/src/utils.ts",
    "content": "export const clamp = (min: number, max: number) => (v: number) =>\n  Math.max(Math.min(v, max), min);\n\n// If this number is a decimal, make it just five decimal places\n// to avoid exponents\nexport const sanitize = (v: number) => (v % 1 ? Number(v.toFixed(5)) : v);\n\nexport const floatRegex = /(-)?([\\d]*\\.?[\\d])+/g;\nexport const colorRegex = /(#[0-9a-f]{6}|#[0-9a-f]{3}|#(?:[0-9a-f]{2}){2,4}|(rgb|hsl)a?\\((-?[\\d\\.]+%?[,\\s]+){2}(-?[\\d\\.]+%?)\\s*[\\,\\/]?\\s*[\\d\\.]*%?\\))/gi;\nexport const singleColorRegex = /^(#[0-9a-f]{3}|#(?:[0-9a-f]{2}){2,4}|(rgb|hsl)a?\\((-?[\\d\\.]+%?[,\\s]+){2}(-?[\\d\\.]+%?)\\s*[\\,\\/]?\\s*[\\d\\.]*%?\\))$/i;\n\nexport function isString(v: any): v is string {\n  return typeof v === 'string';\n}\n"
  },
  {
    "path": "packages/style-value-types/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"rootDir\": \"src\",\n    \"outDir\": \"lib\",\n    \"declarationDir\": \"lib\",\n  },\n  \"include\": [\"src/**/*\"]\n}"
  },
  {
    "path": "packages/style-value-types/tslint.json",
    "content": "{\n  \"defaultSeverity\": \"error\",\n  \"extends\": [\n      \"tslint:recommended\"\n  ],\n  \"jsRules\": {},\n  \"rules\": {\n      \"ban-types\": [false, [\"Function\"]],\n      \"quotemark\": [true, \"single\", \"avoid-escape\", \"avoid-template\"],\n      \"trailing-comma\": [false],\n      \"no-unused-variable\": true,\n      \"interface-name\": false,\n      \"interface-over-type-literal\": false,\n      \"max-line-length\":false,\n      \"curly\": false,\n      \"prefer-for-of\": false,\n      \"member-access\": false,\n    \"object-literal-sort-keys\": false,\n    \"ordered-imports\": false,\n    \"variable-name\": false\n  },\n  \"rulesDirectory\": []\n}"
  },
  {
    "path": "playground/animate.js",
    "content": "import * as React from 'react';\nimport { useEffect, useRef, useState } from 'react';\nimport styled from 'styled-components';\nimport { animate } from 'popmotion';\n\nconst Box = styled.div`\n  width: 100px;\n  height: 100px;\n  background-color: #09f;\n  border-radius: 10px;\n`;\n\nexport function Keyframes() {\n  const ref = useRef();\n  const [opacity, setOpacity] = useState(0);\n\n  useEffect(() => {\n    const controls = animate({\n      type: 'spring',\n      from: 0,\n      to: 400,\n      duration: 300,\n      mass: 1,\n      velocity: 20,\n      dampingRatio: 1,\n      onUpdate: (v) => {\n        ref.current.style.transform = `translateX(${v}px) translateZ(0)`;\n        // if (v > 20) controls.stop();\n      },\n    });\n\n    return () => controls.stop();\n    // animate({\n    //   from: 0,\n    //   to: 300,\n    //   type: 'spring',\n    //   repeat: Infinity,\n    //   repeatType: 'mirror',\n    //   onUpdate: v => {\n    //     ref.current.style.transform = `translateX(${v}px)`;\n    //   }\n    // });\n  }, [opacity]);\n\n  return <Box ref={ref} onClick={() => setOpacity(opacity ? 0 : 1)} />;\n}\n"
  },
  {
    "path": "playground/index.js",
    "content": "import React from 'react';\nimport { storiesOf } from '@storybook/react';\nimport * as Animate from './animate';\n// import * as Worklet from './worklet';\n\n// storiesOf('worklet', module).add('tween', () => <Worklet.Tween />);\n\nstoriesOf('animate', module).add('keyframes', () => <Animate.Keyframes />);\n// .add('decay', () => <Animate.Decay />)\n// .add('spring', () => <Animate.Spring />);\n"
  },
  {
    "path": "playground/worklet.js",
    "content": "import * as React from 'react';\nimport { useEffect, useRef } from 'react';\nimport styled from 'styled-components';\nimport { animate, workletReady } from 'popmotion';\n\nCSS.animationWorklet.addModule('popmotion-worklet.js').then(workletReady);\n\nconst Box = styled.div`\n  width: 100px;\n  height: 100px;\n  background-color: #09f;\n  border-radius: 10px;\n`;\n\nexport function Tween() {\n  const ref = useRef();\n\n  useEffect(() => {\n    animate(ref.current, { x: 100 }, { duration: 3000 });\n  }, []);\n\n  return <Box ref={ref} />;\n}\n"
  },
  {
    "path": "rollup-generate-config.js",
    "content": "import resolve from '@rollup/plugin-node-resolve';\nimport replace from '@rollup/plugin-replace';\nimport { terser } from 'rollup-plugin-terser';\n\nconst makeExternalPredicate = (externalArr) => {\n  if (externalArr.length === 0) {\n    return () => false;\n  }\n  const pattern = new RegExp(`^(${externalArr.join('|')})($|/)`);\n  return (id) => pattern.test(id);\n};\n\nexport default function (pkg, name = pkg.name) {\n  const deps = Object.keys(pkg.dependencies || {});\n  const peerDeps = Object.keys(pkg.peerDependencies || {});\n\n  const config = {\n    input: 'lib/index.js',\n    external: makeExternalPredicate(deps.concat(peerDeps)),\n  };\n\n  const umd = {\n    ...config,\n    output: {\n      file: `dist/${name}.js`,\n      format: 'umd',\n      name,\n      exports: 'named',\n      globals: {\n        tslib: 'tslib',\n        'hey-listen': 'heyListen',\n        'style-value-types': 'valueTypes',\n        framesync: 'framesync',\n        popmotion: 'popmotion',\n        'pose-core': 'poseCore',\n        '@popmotion/easing': 'easing',\n        '@popmotion/popcorn': 'popcorn',\n      },\n    },\n    external: makeExternalPredicate(peerDeps),\n    plugins: [\n      resolve(),\n      replace({\n        'process.env.NODE_ENV': JSON.stringify('development'),\n      }),\n    ],\n  };\n\n  const umdProd = {\n    ...umd,\n    output: {\n      ...umd.output,\n      file: pkg.unpkg || `dist/${name}.min.js`,\n    },\n    plugins: [\n      resolve(),\n      replace({\n        'process.env.NODE_ENV': JSON.stringify('production'),\n      }),\n      terser({ output: { comments: false } }),\n    ],\n  };\n\n  const es = {\n    ...config,\n    output: {\n      entryFileNames: '[name].mjs',\n      format: 'es',\n      preserveModules: true,\n      dir: 'dist/es',\n    },\n    plugins: [resolve()],\n  };\n\n  const cjs = {\n    ...config,\n    output: {\n      file: `dist/${name}.cjs.js`,\n      format: 'cjs',\n      exports: 'named',\n    },\n    plugins: [resolve()],\n  };\n\n  return [umd, umdProd, es, cjs];\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"es6\",\n    \"moduleResolution\": \"node\",\n    \"noImplicitAny\": true,\n    \"removeComments\": true,\n    \"preserveConstEnums\": true,\n    \"sourceMap\": true,\n    \"noUnusedLocals\": true,\n    \"target\": \"ES6\",\n    \"watch\": false,\n    \"baseUrl\": \"./packages\",\n    \"importHelpers\": true,\n    \"paths\": {\n      \"framesync\": [\n        \"./framesync/lib\"\n      ],\n      \"popmotion\": [\n        \"./popmotion/lib\"\n      ],\n      \"style-value-types\": [\n        \"./style-value-types/lib\"\n      ]\n    },\n    \"alwaysStrict\": true,\n    \"declaration\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"lib\": [\n      \"es5\",\n      \"es6\",\n      \"dom\"\n    ],\n    \"skipLibCheck\": true\n  },\n  \"exclude\": [\n    \"**/*.test.ts\"\n  ]\n}"
  },
  {
    "path": "tslint.json",
    "content": "{\n  \"defaultSeverity\": \"error\",\n  \"extends\": [\n    \"tslint:latest\",\n    \"tslint-react\",\n    \"tslint-config-prettier\",\n    \"tslint-circular-dependencies\"\n  ],\n  \"jsRules\": {},\n  \"rules\": {\n    \"ban-types\": [\n      false,\n      [\n        \"Function\"\n      ]\n    ],\n    \"quotemark\": [\n      true,\n      \"single\",\n      \"avoid-escape\",\n      \"avoid-template\"\n    ],\n    \"trailing-comma\": [\n      false\n    ],\n    \"forin\": false,\n    \"interface-name\": false,\n    \"interface-over-type-literal\": false,\n    \"max-line-length\": false,\n    \"curly\": false,\n    \"prefer-for-of\": false,\n    \"member-access\": false,\n    \"ordered-imports\": false,\n    \"object-literal-sort-keys\": false,\n    \"imports-after-export\": false,\n    \"no-instanceof-operator\": false,\n    \"initialize-statics-after-imports\": false\n  },\n  \"rulesDirectory\": []\n}"
  },
  {
    "path": "types/animations/decay.d.ts",
    "content": "import { Animator, DecayOptions } from './types';\nexport declare class DecayAnimator implements Animator<DecayOptions, number> {\n  options: DecayOptions;\n  amplitude: number;\n  target: number;\n  static needsInterpolation: boolean;\n  isComplete: boolean;\n  constructor(options: DecayOptions);\n  update(t: number): number;\n  updateOptions({\n    velocity,\n    from,\n    power,\n    timeConstant,\n    restDelta,\n    modifyTarget\n  }?: DecayOptions): void;\n  static uniqueOptionKeys: Set<\n    | 'velocity'\n    | 'to'\n    | 'restDelta'\n    | 'from'\n    | 'timeConstant'\n    | 'power'\n    | 'modifyTarget'\n  >;\n}\n"
  },
  {
    "path": "types/animations/index.d.ts",
    "content": "import { Animatable, AnimationOptions, PlaybackControls } from './types';\nexport declare function animate<V extends Animatable>({\n  from,\n  to,\n  autoplay,\n  driver,\n  elapsed,\n  repeat: repeatMax,\n  repeatType,\n  repeatDelay,\n  onPlay,\n  onComplete,\n  onRepeat,\n  onUpdate,\n  ...options\n}: AnimationOptions<V>): PlaybackControls;\n"
  },
  {
    "path": "types/animations/inertia.d.ts",
    "content": ""
  },
  {
    "path": "types/animations/keyframes.d.ts",
    "content": "import { KeyframeOptions, Animator } from './types';\nimport { Easing } from '../easing/types';\nexport declare function defaultEasing(values: any[], easing?: Easing): Easing[];\nexport declare function defaultOffset(values: any[]): number[];\nexport declare function convertOffsetToTimes(\n  offset: number[],\n  duration: number\n): number[];\nexport declare class KeyframesAnimator\n  implements Animator<KeyframeOptions, any> {\n  options: KeyframeOptions;\n  isComplete: boolean;\n  static needsInterpolation: boolean;\n  interpolator: (t: number) => any;\n  constructor(options: KeyframeOptions);\n  update(t: number): any;\n  updateOptions({ from, to, ease, offset, duration }: KeyframeOptions): void;\n  static uniqueOptionKeys: Set<'to' | 'from' | 'ease' | 'duration' | 'offset'>;\n}\n"
  },
  {
    "path": "types/animations/spring.d.ts",
    "content": "import { SpringOptions, Animator } from './types';\nexport declare class SpringAnimator implements Animator<SpringOptions, number> {\n  options: SpringOptions;\n  isComplete: boolean;\n  resolveSpring: (t: number) => number;\n  static needsInterpolation: boolean;\n  constructor(options: SpringOptions);\n  update(t: number): number | undefined;\n  updateOptions({\n    from,\n    to,\n    velocity,\n    stiffness,\n    damping,\n    mass,\n    restSpeed,\n    restDelta\n  }: SpringOptions): void;\n  static uniqueOptionKeys: Set<\n    | 'velocity'\n    | 'restSpeed'\n    | 'to'\n    | 'restDelta'\n    | 'from'\n    | 'damping'\n    | 'stiffness'\n    | 'mass'\n  >;\n}\n"
  },
  {
    "path": "types/animations/types.d.ts",
    "content": "import { Easing } from '../easing/types';\n/**\n * The kinds of values that can currently be animated.\n */\nexport declare type Animatable = string | number;\n/**\n * Animators that can be resolved for time\n */\nexport interface Animator<O, V> {\n  options: O;\n  update(t: number): V;\n  updateOptions(options: O): void;\n  isComplete: boolean;\n}\nexport interface PlaybackControls {\n  play: () => void;\n  pause: () => void;\n  resume: () => void;\n  reverse: () => void;\n  seek: () => void;\n  stop: () => void;\n}\n/**\n * An update function. It accepts a timestamp used to advance the animation.\n */\ndeclare type Update = (timestamp: number) => void;\n/**\n * Drivers accept a update function and call it at an interval. This interval\n * could be a synchronous loop, a setInterval, or tied to the device's framerate.\n */\nexport declare type Driver = (update: Update) => () => void;\n/**\n * Playback options common to all animations.\n */\nexport interface PlaybackOptions<V extends Animatable> {\n  /**\n   * Whether to autoplay the animation when animate is called. If\n   * set to false, the animation must be started manually via the returned\n   * play method.\n   */\n  autoplay?: boolean;\n  driver?: Driver;\n  elapsed?: number;\n  from?: V;\n  repeat?: number;\n  repeatType?: 'loop' | 'reverse';\n  repeatDelay?: number;\n  onUpdate?: (latest: V) => void;\n  onPlay?: () => void;\n  onComplete?: () => void;\n  onRepeat?: () => void;\n}\nexport interface KeyframeOptions<V extends Animatable = number> {\n  to: V | V[];\n  from?: V;\n  duration?: number;\n  ease?: Easing | Easing[];\n  offset?: number[];\n}\nexport interface DecayOptions<T extends Animatable = number> {\n  from?: T;\n  to?: T;\n  velocity?: number;\n  power?: number;\n  timeConstant?: number;\n  modifyTarget?: (target: number) => number;\n  restDelta?: number;\n}\nexport interface SpringOptions<T extends Animatable = number> {\n  from?: T;\n  to?: T;\n  velocity?: number;\n  stiffness?: number;\n  damping?: number;\n  mass?: number;\n  restSpeed?: number;\n  restDelta?: number;\n}\nexport declare type AnimationOptions<V extends Animatable> = PlaybackOptions<\n  V\n> &\n  (DecayOptions<V> | KeyframeOptions<V> | SpringOptions<V>);\nexport {};\n"
  },
  {
    "path": "types/animations/utils/detect-animation-from-options.d.ts",
    "content": "import { SpringAnimator } from '../spring';\nimport { KeyframesAnimator } from '../keyframes';\nimport { DecayAnimator } from '../decay';\ninterface Options {}\nexport declare function detectAnimationFromOptions<T extends Options>(\n  config: T\n):\n  | typeof SpringAnimator\n  | typeof KeyframesAnimator\n  | typeof DecayAnimator\n  | undefined;\nexport {};\n"
  },
  {
    "path": "types/easing/cubic-bezier.d.ts",
    "content": "export declare function cubicBezier(\n  mX1: number,\n  mY1: number,\n  mX2: number,\n  mY2: number\n): import('./types').Easing;\n"
  },
  {
    "path": "types/easing/index.d.ts",
    "content": "import { Easing } from './types';\nexport declare const linear: Easing;\nexport declare const easeIn: Easing;\nexport declare const easeOut: Easing;\nexport declare const easeInOut: Easing;\nexport declare const circIn: Easing;\nexport declare const circOut: Easing;\nexport declare const circInOut: Easing;\nexport declare const backIn: Easing;\nexport declare const backOut: Easing;\nexport declare const backInOut: Easing;\nexport declare const anticipate: Easing;\nexport declare const bounceOut: (p: number) => number;\nexport declare const bounceIn: (p: number) => number;\nexport declare const bounceInOut: (p: number) => number;\n"
  },
  {
    "path": "types/easing/steps.d.ts",
    "content": "import { Easing } from './types';\nexport declare type Direction = 'start' | 'end';\nexport declare const steps: (steps: number, direction?: Direction) => Easing;\n"
  },
  {
    "path": "types/easing/types.d.ts",
    "content": "export declare type Easing = (v: number) => number;\nexport declare type EasingModifier = (easing: Easing) => Easing;\n"
  },
  {
    "path": "types/easing/utils.d.ts",
    "content": "import { Easing, EasingModifier } from './types';\nexport declare const reverseEasing: EasingModifier;\nexport declare const mirrorEasing: EasingModifier;\nexport declare const createExpoIn: (power: number) => Easing;\nexport declare const createBackIn: (power: number) => Easing;\nexport declare const createAnticipate: (power: number) => Easing;\n"
  },
  {
    "path": "types/global.d.ts",
    "content": "export {};\n"
  },
  {
    "path": "types/index.d.ts",
    "content": "export { animate } from './animations';\nexport { DecayAnimator } from './animations/decay';\nexport { SpringAnimator } from './animations/spring';\nexport { KeyframesAnimator } from './animations/keyframes';\nexport { angle } from './utils/angle';\nexport { applyOffset } from './utils/apply-offset';\nexport { attract, attractLinear, attractExpo } from './utils/attract';\nexport { clamp } from './utils/clamp';\nexport { degreesToRadians } from './utils/degrees-to-radians';\nexport { distance } from './utils/distance';\nexport { interpolate } from './utils/interpolate';\nexport { isPoint3D } from './utils/is-point-3d';\nexport { isPoint } from './utils/is-point';\nexport { mixColor } from './utils/mix-color';\nexport { mixComplex } from './utils/mix-complex';\nexport { mix } from './utils/mix';\nexport { pipe } from './utils/pipe';\nexport { pointFromVector } from './utils/point-from-vector';\nexport { progress } from './utils/progress';\nexport { radiansToDegrees } from './utils/radians-to-degrees';\nexport { smoothFrame } from './utils/smooth-frame';\nexport { smooth } from './utils/smooth';\nexport { snap } from './utils/snap';\nexport { toDecimal } from './utils/to-decimal';\nexport { velocityPerFrame } from './utils/velocity-per-frame';\nexport { velocityPerSecond } from './utils/velocity-per-second';\nexport { wrap } from './utils/wrap';\nexport {\n  linear,\n  easeIn,\n  easeInOut,\n  easeOut,\n  circIn,\n  circInOut,\n  circOut,\n  backIn,\n  backInOut,\n  backOut,\n  anticipate,\n  bounceIn,\n  bounceInOut,\n  bounceOut\n} from './easing';\nexport { cubicBezier } from './easing/cubic-bezier';\nexport { steps } from './easing/steps';\nexport {\n  mirrorEasing,\n  reverseEasing,\n  createExpoIn,\n  createBackIn,\n  createAnticipate\n} from './easing/utils';\n"
  },
  {
    "path": "types/types.d.ts",
    "content": "export declare type Point2D = {\n  x: number;\n  y: number;\n};\nexport declare type Point3D = Point2D & {\n  z: number;\n};\nexport declare type Point = Point2D | Point3D;\n"
  },
  {
    "path": "types/utils/angle.d.ts",
    "content": "import { Point } from '../types';\nexport declare const angle: (a: Point, b?: Point) => number;\n"
  },
  {
    "path": "types/utils/apply-offset.d.ts",
    "content": "/**\n * Apply offset\n * A function that, given a value, will get the offset from `from`\n * and apply it to `to`\n * @param  {number} from\n * @param  {number} to\n * @return {function}\n */\nexport declare const applyOffset: (\n  from: number,\n  to?: number | undefined\n) => (v: number) => number | undefined;\n"
  },
  {
    "path": "types/utils/attract.d.ts",
    "content": "export declare const attract: (\n  alterDisplacement?: Function\n) => (constant: number, origin: number, v: number) => number;\nexport declare const attractLinear: (\n  constant: number,\n  origin: number,\n  v: number\n) => number;\nexport declare const attractExpo: (\n  constant: number,\n  origin: number,\n  v: number\n) => number;\n"
  },
  {
    "path": "types/utils/clamp.d.ts",
    "content": "export declare const clamp: (min: number, max: number, v: number) => number;\n"
  },
  {
    "path": "types/utils/degrees-to-radians.d.ts",
    "content": "export declare const degreesToRadians: (degrees: number) => number;\n"
  },
  {
    "path": "types/utils/distance.d.ts",
    "content": "import { Point } from '../types';\ndeclare type _Point = Point | number;\nexport declare const distance: (a: _Point, b?: _Point) => number;\nexport {};\n"
  },
  {
    "path": "types/utils/inc.d.ts",
    "content": "import { Point } from '../types';\nexport declare const zeroPoint: Point;\nexport declare const isNum: (v: any) => v is number;\n"
  },
  {
    "path": "types/utils/interpolate.d.ts",
    "content": "import { Easing } from '../easing/types';\ndeclare type MixEasing = Easing | Easing[];\ndeclare type InterpolateOptions<T> = {\n  clamp?: boolean;\n  ease?: MixEasing;\n  mixer?: MixerFactory<T>;\n};\ndeclare type Mix<T> = (v: number) => T;\nexport declare type MixerFactory<T> = (from: T, to: T) => Mix<T>;\n/**\n * Create a function that maps from a numerical input array to a generic output array.\n *\n * Accepts:\n *   - Numbers\n *   - Colors (hex, hsl, hsla, rgb, rgba)\n *   - Complex (combinations of one or more numbers or strings)\n *\n * ```jsx\n * const mixColor = interpolate([0, 1], ['#fff', '#000'])\n *\n * mixColor(0.5) // 'rgba(128, 128, 128, 1)'\n * ```\n *\n * @public\n */\nexport declare function interpolate<T>(\n  input: number[],\n  output: T[],\n  { clamp: isClamp, ease, mixer }?: InterpolateOptions<T>\n): (v: number) => T;\nexport {};\n"
  },
  {
    "path": "types/utils/is-point-3d.d.ts",
    "content": "import { Point, Point3D } from '../types';\nexport declare const isPoint3D: (point: Point) => point is Point3D;\n"
  },
  {
    "path": "types/utils/is-point.d.ts",
    "content": "import { Point } from '../types';\nexport declare const isPoint: (point: Object) => point is Point;\n"
  },
  {
    "path": "types/utils/mix-color.d.ts",
    "content": "export declare const mixLinearColor: (\n  from: number,\n  to: number,\n  v: number\n) => number;\nexport declare const mixColor: (\n  from:\n    | string\n    | import('../../../style-value-types/lib').HSLA\n    | import('../../../style-value-types/lib').RGBA,\n  to:\n    | string\n    | import('../../../style-value-types/lib').HSLA\n    | import('../../../style-value-types/lib').RGBA\n) => (v: number) => any;\n"
  },
  {
    "path": "types/utils/mix-complex.d.ts",
    "content": "import { RGBA, HSLA } from 'style-value-types';\ndeclare type MixComplex = (p: number) => string;\ndeclare type BlendableObject = {\n  [key: string]: string | number | RGBA | HSLA;\n};\nexport declare const mixArray: (\n  from: (string | number | HSLA | RGBA)[],\n  to: (string | number | HSLA | RGBA)[]\n) => (v: number) => (string | number | HSLA | RGBA)[];\nexport declare const mixObject: (\n  origin: BlendableObject,\n  target: BlendableObject\n) => (\n  v: number\n) => {\n  [x: string]: string | number | HSLA | RGBA;\n};\nexport declare const mixComplex: (origin: string, target: string) => MixComplex;\nexport {};\n"
  },
  {
    "path": "types/utils/mix.d.ts",
    "content": "export declare const mix: (\n  from: number,\n  to: number,\n  progress: number\n) => number;\n"
  },
  {
    "path": "types/utils/pipe.d.ts",
    "content": "export declare const pipe: (...transformers: Function[]) => Function;\n"
  },
  {
    "path": "types/utils/point-from-vector.d.ts",
    "content": "import { Point2D } from '../types';\nexport declare const pointFromVector: (\n  origin: Point2D,\n  angle: number,\n  distance: number\n) => {\n  x: number;\n  y: number;\n};\n"
  },
  {
    "path": "types/utils/progress.d.ts",
    "content": "export declare const progress: (\n  from: number,\n  to: number,\n  value: number\n) => number;\n"
  },
  {
    "path": "types/utils/radians-to-degrees.d.ts",
    "content": "export declare const radiansToDegrees: (radians: number) => number;\n"
  },
  {
    "path": "types/utils/smooth-frame.d.ts",
    "content": "export declare const smoothFrame: (\n  prevValue: number,\n  nextValue: number,\n  duration: number,\n  smoothing?: number\n) => number;\n"
  },
  {
    "path": "types/utils/smooth.d.ts",
    "content": "export declare const smooth: (strength?: number) => (v: number) => number;\n"
  },
  {
    "path": "types/utils/snap.d.ts",
    "content": "export declare const snap: (\n  points: number | number[]\n) => (v: number) => number | undefined;\n"
  },
  {
    "path": "types/utils/to-decimal.d.ts",
    "content": "export declare const toDecimal: (num: number, precision?: number) => number;\n"
  },
  {
    "path": "types/utils/velocity-per-frame.d.ts",
    "content": "export declare const velocityPerFrame: (\n  xps: number,\n  frameDuration: number\n) => number;\n"
  },
  {
    "path": "types/utils/velocity-per-second.d.ts",
    "content": "export declare const velocityPerSecond: (\n  velocity: number,\n  frameDuration: number\n) => number;\n"
  },
  {
    "path": "types/utils/wrap.d.ts",
    "content": "export declare const wrap: (min: number, max: number, v: number) => number;\n"
  },
  {
    "path": "types/worklet/custom-properties.d.ts",
    "content": "export declare function namespace(name: string): string;\nexport declare function registerCustomProperties(): void;\n"
  },
  {
    "path": "types/worklet/load-worklet.d.ts",
    "content": "export declare function whenWorkletReady(): Promise<unknown>;\nexport declare function workletReady(): void;\n"
  }
]