{"id":22454325,"url":"https://github.com/littensy/ripple","last_synced_at":"2025-04-06T08:15:22.331Z","repository":{"id":184747780,"uuid":"672411669","full_name":"littensy/ripple","owner":"littensy","description":"🎨 An elegant motion library for Roblox","archived":false,"fork":false,"pushed_at":"2025-01-21T19:24:14.000Z","size":117,"stargazers_count":36,"open_issues_count":3,"forks_count":13,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-30T03:08:37.988Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Luau","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/littensy.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":"2023-07-30T01:55:48.000Z","updated_at":"2025-02-12T00:13:44.000Z","dependencies_parsed_at":"2023-12-31T02:42:25.505Z","dependency_job_id":"16f57775-b570-45cb-a479-18d6c5401051","html_url":"https://github.com/littensy/ripple","commit_stats":null,"previous_names":["littensy/ripple","littensy/motion"],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/littensy%2Fripple","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/littensy%2Fripple/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/littensy%2Fripple/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/littensy%2Fripple/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/littensy","download_url":"https://codeload.github.com/littensy/ripple/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247451667,"owners_count":20940944,"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":[],"created_at":"2024-12-06T07:07:31.110Z","updated_at":"2025-04-06T08:15:22.293Z","avatar_url":"https://github.com/littensy.png","language":"Luau","readme":"# 🎨 Ripple\n\n**Ripple** is a simple, lightweight, and easy-to-use Roblox library for creating simple transitions and animations. It is inspired by [roact-spring](https://github.com/chriscerie/roact-spring) and is primarily intended to be a general-use alternative to [Flipper](https://github.com/Reselim/Flipper) for [Roblox-TS](https://roblox-ts.com).\n\nYou may use Ripple with or without Roact. Currently, there is no package for using Ripple with Roact.\n\n## 📦 Installation\n\nRipple is available on [NPM](https://www.npmjs.com/package/@rbxts/ripple) and can be installed with the following commands:\n\n```bash\nnpm install @rbxts/ripple\nyarn add @rbxts/ripple\npnpm add @rbxts/ripple\n```\n\n```toml\n# Wally\nRipple = \"littensy/ripple@version\"\n```\n\n## 📚 Documentation\n\nTo see Ripple in action, check out the [example repository](https://github.com/littensy/rbxts-react-example).\n\n### ⚡ Quick Start\n\nCall `createMotion` to create an animation.\n\nUse the `spring`, `linear`, `immediate`, and `tween` methods to set the goal of your animation.\n\n```typescript\nimport { Motion, MotionGoal, config, createMotion } from \"@rbxts/ripple\";\n\nconst motion = createMotion(Vector3.zero, { start: true });\n\nmotion.spring(Vector3.one, config.spring.stiff);\n\nmotion.onStep((value, deltaTime) =\u003e {\n\tprint(value, deltaTime);\n});\n\nprint(motion.get());\n```\n\nYou can also apply different goal types to specific properties using the `to` method:\n\n```typescript\nconst motion = createMotion({ x: 0, y: 0 });\n\nmotion.to({\n\tx: spring(100, config.spring.stiff),\n\ty: linear(100),\n});\n```\n\n### ⚛️ Usage with React\n\n#### `useMotion(initialValue)`\n\nCreates a memoized Motion object set to the given initial value.\n\nReturns a binding that updates with the Motion, along with the Motion object.\n\n```typescript\nfunction MyComponent() {\n\tconst [binding, motion] = useMotion(0);\n\t// ...\n}\n```\n\n```typescript\nexport function useMotion(initialValue: number): LuaTuple\u003c[Binding\u003cnumber\u003e, Motion]\u003e;\n\nexport function useMotion\u003cT extends MotionGoal\u003e(initialValue: T): LuaTuple\u003c[Binding\u003cT\u003e, Motion\u003cT\u003e]\u003e;\n\nexport function useMotion\u003cT extends MotionGoal\u003e(initialValue: T) {\n\tconst motion = useMemo(() =\u003e {\n\t\treturn createMotion(initialValue);\n\t}, []);\n\n\tconst [binding, setValue] = useBinding(initialValue);\n\n\tuseEventListener(RunService.Heartbeat, (delta) =\u003e {\n\t\tconst value = motion.step(delta);\n\n\t\tif (value !== binding.getValue()) {\n\t\t\tsetValue(value);\n\t\t}\n\t});\n\n\treturn $tuple(binding, motion);\n}\n```\n\n#### `useSpring(value, springConfig?)`\n\nApplies spring animations to the given value, and updates the goal with the latest value on every re-render.\n\nReturns a binding that updates with the Motion.\n\n```typescript\nfunction MyComponent({ someValue }: Props) {\n\tconst binding = useSpring(someValue);\n\t// ...\n}\n```\n\n```typescript\nexport function useSpring(goal: number | Binding\u003cnumber\u003e, options?: SpringOptions): Binding\u003cnumber\u003e;\n\nexport function useSpring\u003cT extends MotionGoal\u003e(goal: T | Binding\u003cT\u003e, options?: SpringOptions): Binding\u003cT\u003e;\n\nexport function useSpring(goal: MotionGoal | Binding\u003cMotionGoal\u003e, options?: SpringOptions) {\n\tconst [binding, motion] = useMotion(getBindingValue(goal));\n\tconst previousValue = useRef(getBindingValue(goal));\n\n\tuseEventListener(RunService.Heartbeat, () =\u003e {\n\t\tconst currentValue = getBindingValue(goal);\n\n\t\tif (currentValue !== previousValue.current) {\n\t\t\tpreviousValue.current = currentValue;\n\t\t\tmotion.spring(currentValue, options);\n\t\t}\n\t});\n\n\treturn binding;\n}\n```\n\n### 📝 License\n\nRipple is licensed under the MIT License.\n","funding_links":[],"categories":["Motion"],"sub_categories":["Ripple \u003cimg src=\"luau.svg\" width=\"18px\" /\u003e\u003cimg src=\"roblox-ts.svg\" width=\"18px\" /\u003e"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flittensy%2Fripple","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flittensy%2Fripple","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flittensy%2Fripple/lists"}