{"id":19805346,"url":"https://github.com/cirolee/tiny-motion","last_synced_at":"2025-05-01T06:31:09.768Z","repository":{"id":246145092,"uuid":"820229367","full_name":"CiroLee/tiny-motion","owner":"CiroLee","description":"The high-performance extension of  Web Animation API for React Hooks","archived":false,"fork":false,"pushed_at":"2024-12-22T14:56:49.000Z","size":996,"stargazers_count":10,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-22T10:53:43.815Z","etag":null,"topics":["animation","hooks","motion","react","tiny-motion","web-animation-api"],"latest_commit_sha":null,"homepage":"https://tiny-motion.vercel.app","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CiroLee.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-06-26T04:15:05.000Z","updated_at":"2024-12-22T14:54:02.000Z","dependencies_parsed_at":"2024-06-26T05:33:20.140Z","dependency_job_id":"f9ba7cdc-e163-41bf-b106-12ae8eb3d47f","html_url":"https://github.com/CiroLee/tiny-motion","commit_stats":null,"previous_names":["cirolee/animate-motion","cirolee/ease-motion","cirolee/tiny-motion"],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CiroLee%2Ftiny-motion","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CiroLee%2Ftiny-motion/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CiroLee%2Ftiny-motion/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CiroLee%2Ftiny-motion/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CiroLee","download_url":"https://codeload.github.com/CiroLee/tiny-motion/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251835526,"owners_count":21651667,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["animation","hooks","motion","react","tiny-motion","web-animation-api"],"created_at":"2024-11-12T09:03:30.648Z","updated_at":"2025-05-01T06:31:09.337Z","avatar_url":"https://github.com/CiroLee.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"images/tiny-motion-logo.svg\" width=\"256\" height=\"256\" alt=\"logo\"\u003e\n  \u003ch1 style=\"margin-top:20px\"\u003e@cirolee/tiny-motion\u003c/h1\u003e\n\u003c/div\u003e\n\nThe high-performance extension of Web Animation API for React Hooks\n\n![NPM Unpacked Size](https://img.shields.io/npm/unpacked-size/%40cirolee%2Ftiny-motion) ![NPM Version](https://img.shields.io/npm/v/@cirolee/tiny-motion) ![NPM License](https://img.shields.io/npm/l/%40cirolee%2Ftiny-motion)\n\n# Install\n\n```bash\nnpm install @cirolee/tiny-motion\n```\n\n# Usage\n\n## useMotion\n\nthe preset motions\n\n```ts\n// App.tsx\nimport { useMotion } from '@cirolee/tiny-motion';\n\nexport default function App() {\n  const [ ref, motion ] = useMotion\u003cHTMLDivElement\u003e()\n\n  return (\n    \u003cdiv\u003e\n      \u003cdiv ref={ref} className=\"text-3xl\"\u003e@cirolee/tiny-motion\u003c/div\u003e\n      \u003cbutton onClick={() =\u003e motion('swing')}\u003eplay\u003c/button\u003e\n    \u003c/div\u003e\n  )\n}\n```\n\n## useAnimate\n\nbasic wrap of [Web Animation API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API)\n\n```ts\nimport { useAnimate} from '@cirolee/tiny-motion;'\nexport default function App() {\n  const [ ref, animate ] = useAnimate\u003cHTMLDivElement\u003e();\n  return (\n    \u003cdiv className=\"relative mb-3 flex h-[240px] overflow-hidden rounded-md border items-center justify-center\"\u003e\n      \u003cdiv ref={ref} className=\"size-[120px] rounded-lg bg-blue-500\"\u003e\u003c/div\u003e\n      \u003cbutton\n        className=\"absolute bottom-2 right-2\"\n        onClick={() =\u003e {\n          animate(\n            {\n              transform: ['translateX(0)', 'translateX(100px)'],\n              borderRadius: ['8px', '50%'],\n              backgroundColor: ['rgb(59 130 246)', 'rgb(246 154 59)']\n            },\n            {\n              duration: 800,\n              easing: 'ease-in-out',\n              fill: 'forwards'\n            }\n          );\n        }}\u003e\n        play\n      \u003c/button\u003e\n    \u003c/div\u003e\n  )\n}\n```\n\n## useGroup\n\nuseGroup is used to control multiple elements to animate with the same parameters\n\n```ts\nimport { useGroup, EASING_FUNCTIONS } from '@cirolee/tiny-motion';\n\nexport default function App() {\n  const ballRef1 = useRef\u003cHTMLDivElement\u003e(null);\n  const ballRef2 = useRef\u003cHTMLDivElement\u003e(null);\n  const ballRef3 = useRef\u003cHTMLDivElement\u003e(null);\n\n  const controller = useGroup(\n    {\n      refs: [ballRef1, ballRef2, ballRef3],\n      keyframes: {\n        transform: ['translateX(0) rotate(0)', 'translateX(500px) rotate(2turn)']\n      },\n      options: {\n        duration: 3000,\n        fill: 'forwards',\n        easing: EASING_FUNCTIONS.easeOutInBack\n      },\n      onStart: () =\u003e {\n        console.log('start animate');\n      },\n      onPause: () =\u003e {\n        console.log('pause animate');\n      },\n      onResume: () =\u003e {\n        console.log('resume animate');\n      },\n      onComplete: () =\u003e {\n        console.log('complete animate');\n      }\n    },\n    []\n  );\n\n  return (\n    \u003cdiv className=\"flex flex-col justify-center gap-2 px-8\"\u003e\n      \u003cdiv ref={ballRef1} className=\"size-[40px] bg-blue-500\"\u003e\u003c/div\u003e\n      \u003cdiv ref={ballRef2} className=\"size-[40px] bg-blue-500\"\u003e\u003c/div\u003e\n      \u003cdiv ref={ballRef3} className=\"size-[40px] bg-blue-500\"\u003e\u003c/div\u003e\n      \u003cdiv className=\"absolute bottom-2 right-2 space-x-2\"\u003e\n        \u003cbutton onClick={() =\u003e controller.play()}\u003e\n          play\n        \u003c/button\u003e\n        \u003cbutton onClick={() =\u003e controller.reverse()}\u003e\n          reverse\n        \u003c/button\u003e\n        \u003cbutton onClick={() =\u003e controller.pause()}\u003e\n          pause\n        \u003c/button\u003e\n        \u003cbutton onClick={() =\u003e controller.resume()}\u003e\n          resume\n        \u003c/button\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n  )\n}\n```\n\n## useMultiple\n\nuseMultiple is used to control the animation of multiple elements using independent animation parameters\n\n```ts\nimport { useRef } from 'react';\nimport { useMultiple } from '@cirolee/tiny-motion';\n\nexport default function App() {\n  const ballRef1 = useRef\u003cHTMLDivElement\u003e(null);\n  const ballRef2 = useRef\u003cHTMLDivElement\u003e(null);\n  const ballRef3 = useRef\u003cHTMLDivElement\u003e(null);\n\n  const controller = useMultiple(\n    {\n      baseOptions: {\n        duration: 1000,\n        fill: 'forwards'\n      },\n      config: [\n        {\n          ref: ballRef1,\n          keyframes: [\n            { transform: 'translateX(0) scale(1)', borderRadius: '0' },\n            { transform: 'translateX(100px) scale(1)', borderRadius: '50%', offset: 0.2 },\n            { transform: 'translateX(100px) scale(1)', borderRadius: '50%', offset: 0.6 },\n            {\n              transform: 'translateX(160px) scale(1.6, 1)',\n              borderRadius: '50%'\n            },\n            {\n              transform: 'translateX(360px) scale(1, 1)',\n              borderRadius: '50%'\n            }\n          ]\n        },\n        {\n          ref: ballRef2,\n          keyframes: {\n            transform: ['translateX(200px) rotate(2turn)'],\n            borderRadius: ['4px']\n          },\n          options: {\n            duration: 500\n          }\n        },\n        {\n          ref: ballRef3,\n          keyframes: {\n            transform: ['translateX(0)', 'translateX(300px)'],\n            easing: 'steps(4)'\n          }\n        }\n      ]\n    },\n    []\n  );\n\n  return (\n    \u003cdiv className=\"mb-4 flex flex-col justify-center gap-2 px-8\"\u003e\n      \u003cdiv ref={ballRef1} className=\"size-[40px] bg-blue-500\"\u003e\u003c/div\u003e\n      \u003cdiv ref={ballRef2} className=\"size-[40px] bg-blue-500\"\u003e\u003c/div\u003e\n      \u003cdiv ref={ballRef3} className=\"size-[40px] bg-blue-500\"\u003e\u003c/div\u003e\n      \u003cbutton className=\"absolute bottom-3 right-3\" onClick={() =\u003e controller.play()}\u003e\n        play\n      \u003c/button\u003e\n    \u003c/div\u003e\n  )\n}\n```\n\n## useLineDraw\n\nused to make svg elements(such as path, circle) to have a line animation effect\n\n```ts\nimport { useRef } from 'react';\nimport { useLineDraw } from '@cirolee/tiny-motion';\n\nexport default function App() {\n  const path1Ref = useRef\u003cSVGPathElement\u003e(null);\n  const path2Ref = useRef\u003cSVGPathElement\u003e(null);\n  const controller = useLineDraw(\n    {\n      refs: [path1Ref, path2Ref],\n      drawType: 'appear',\n      options: {\n        duration: 1500,\n        fill: 'forwards',\n        easing: 'ease-in-out'\n      }\n    },\n    []\n  );\n  return (\n    \u003cdiv className=\"mb-4 flex flex-col px-8 flex-center\"\u003e\n      \u003csvg\n        xmlns=\"http://www.w3.org/2000/svg\"\n        width=\"100\"\n        height=\"100\"\n        viewBox=\"0 0 24 24\"\n        fill=\"none\"\n        stroke=\"currentColor\"\n        stroke-width=\"2\"\n        stroke-linecap=\"round\"\n        stroke-linejoin=\"round\"\u003e\n        \u003cpath ref={path1Ref} d=\"M5 21c.5 -4.5 2.5 -8 7 -10\" /\u003e\n        \u003cpath ref={path2Ref} d=\"M9 18c6.218 0 10.5 -3.288 11 -12v-2h-4.014c-9 0 -11.986 4 -12 9c0 1 0 3 2 5h3z\" /\u003e\n      \u003c/svg\u003e\n      \u003cbutton size=\"sm\" className=\"absolute bottom-3 right-3\" onClick={() =\u003e controller.play()}\u003e\n        play\n      \u003c/button\u003e\n    \u003c/div\u003e\n  )\n}\n```\n\n## useValue\n\nuseValue is used to animate numbers\n\n```ts\nimport { useValue } from '@cirolee/tiny-motion';\n\nexport default function App() {\n  const [value, controller] = useValue(0, 100 {\n    duration: 5000,\n    autoPlay: false,\n    easing: 'easeOutCubic'\n  });\n\n  return (\n    \u003cdiv className=\"flex h-[260px] flex-col items-center\"\u003e\n      \u003cdiv className=\"my-4 flex size-[120px] rounded-xl border bg-white text-3xl font-bold flex-center\"\u003e{value}\u003c/div\u003e\n      \u003cp\u003eisPlaying: {controller.isPlaying.toString()}\u003c/p\u003e\n      \u003cdiv className=\"mt-4 space-x-2\"\u003e\n        \u003cbutton onClick={() =\u003e controller.play()}\u003e\n          play\n        \u003c/button\u003e\n        \u003cbutton onClick={() =\u003e controller.pause()}\u003e\n          pause\n        \u003c/button\u003e\n        \u003cbutton onClick={() =\u003e controller.resume()}\u003e\n          resume\n        \u003c/button\u003e\n        \u003cbutton onClick={() =\u003e controller.cancel()}\u003e\n          cancel\n        \u003c/button\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n  )\n}\n```\n\n## useSpring\n\nused to simulate the real physical spring motion effect\n\n```ts\nimport { useSpring } from '@cirolee/tiny-motion';\n\nexport default function App() {\n  const [y, controller] = useSpring({ from: 0, to: 240, autoPlay: false });\n\n  return (\n    \u003cdiv className=\"h-[440px] px-8\"\u003e\n      \u003cdiv className=\"relative top-3 ml-[33%] size-16 rounded-full bg-blue-500\"\n      style={{ transform: `translateY(${y}px)`}}\u003e\u003c/div\u003e\n      \u003cbutton disabled={controller.isPlaying} onClick={controller.play}\u003e\n        {controller.isPlaying ? 'playing...' : 'start'}\n      \u003c/button\u003e\n    \u003c/div\u003e\n  )\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcirolee%2Ftiny-motion","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcirolee%2Ftiny-motion","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcirolee%2Ftiny-motion/lists"}