{"id":"coffilhg/easysmoothdamp","name":"easysmoothdamp","scope":"coffilhg","platform":"roblox","description":"Easier way to use TweenService:SmoothDamp() - keeps the required variables in a metatable!","version":"1.0.3","latest":"1.0.3","versions":["1.0.0","1.0.1","1.0.2","1.0.3"],"license":"MPL-2.0","licenseRating":"caution","licenseCaveats":["File-level copyleft: if you modify this package's own source files, those modified files must be made available under MPL-2.0. Using it unmodified in a closed-source game is fine."],"licenseVerified":false,"dependencies":{},"integrity":"9277962879c06bb02ebe6919623498017e3924b74a80dfd2a74c353133ff296c","likes":0,"downloads":0,"install":"forest install coffilhg/easysmoothdamp","url":"https://forest.dev/p/roblox/coffilhg/easysmoothdamp","files":"https://api.forest.dev/ai/package/roblox/coffilhg/easysmoothdamp/files","readme":"# EasySmoothDamp\r\nEasier way to use TweenService:SmoothDamp() - keeps the required variables in a metatable!\r\n\r\n---\r\n\r\n## Available Here!\r\n- **[This repository](src/init.luau) ~ [src/init.luau](src/init.luau)**\r\n- **[Wally](<https://wally.run/package/coffilhg/easysmoothdamp>)**\r\n\r\n    ```toml\r\n    EasySmoothDamp = \"coffilhg/easysmoothdamp@1.0.3\"\r\n    ```\r\n- **Rotriever**\r\n\r\n    ```toml\r\n    EasySmoothDamp = \"github.com/Coffilhg/Useful-Modules@EasySmoothDamp/1.0.3\"\r\n    ```\r\n<!--- **[Creator Store](<https://create.roblox.com/store/category/gameplay?creatorName=coffilhg>)** ~ **[EasySmoothDamp](<https://create.roblox.com/store/asset/114136223178149/CoffeeBaseValue>)**-->\r\n\r\n---\r\n\r\n## Features\r\n\r\n- TweenService:SmoothDamp() made simpler, just for faster typing!\r\n- When to and Why use **SmoothDamp**? Watch this tutorial by Roblox: **\"[How to use SmoothDamp for smooth UX on Roblox](<https://www.youtube.com/watch?v=RYzj4TjiMyE>)\"**\r\n- Why use **EasySmoothDamp**? Keeps the Feedback values for SmoothDamp internally!\r\n\r\n---\r\n\r\n## Installation\r\n\r\nUse the \"*Available Here!*\" section to obtain the Module\r\n\r\nRequire the Module:\r\n```lua\r\nlocal EasySmoothDamp = require(PathToModule)\r\n```\r\n\r\n---\r\n\r\n## Roblox Example VS Roblox Example + EasySmoothDamp\r\n\r\n**Roblox Example from \"[How to use SmoothDamp for smooth UX on Roblox](<https://www.youtube.com/watch?v=RYzj4TjiMyE>)\" - 50 Lines and multiple Feedback values for SmoothDamp**\r\n```lua\r\nlocal RunService = game:GetService(\"RunService\")\r\nlocal TweenService = game:GetService(\"TweenService\")\r\nlocal UserInputService = game:GetService(\"UserInputService\")\r\n\r\nlocal head = script.Parent:WaitForChild(\"Head\") :: BasePart\r\n\r\nlocal cloud = script.Cloud\r\ncloud.Parent = script.Parent -- Put cloud into the character model\r\n\r\n-- Offset from the head\r\nlocal offset = Vector3.new(0, 5, 0)\r\n\r\n-- Feedback values for SmoothDamp:\r\nlocal currentCFrame = head.CFrame + offset\r\nlocal currentVelocity = Vector3.zero\r\n\r\nlocal smoothTime = 0.5\r\nlocal maxSpeed = nil\r\n\r\nlocal function impulse()\r\n\tcurrentVelocity += Vector3.new(0, 10, 0)\r\nend\r\n\r\nlocal function onUpdate(dt: number)\r\n\tlocal targetCFrame = head.CFrame + offset\r\n\t\r\n\tcurrentCFrame, currentVelocity = TweenService:SmoothDamp(\r\n\t\tcurrentCFrame,\r\n\t\ttargetCFrame,\r\n\t\tcurrentVelocity,\r\n\t\tsmoothTime,\r\n\t\tmaxSpeed,\r\n\t\tdt\r\n\t)\r\n\t\r\n\tcloud:PivotTo(currentCFrame)\r\nend\r\n\r\nlocal function onInputBegan(input: InputObject, processed: boolean)\r\n\tif processed then return end\r\n\t\r\n\tif input.UserInputType == Enum.UserInputType.Keyboard then\r\n\t\tif input.KeyCode == Enum.KeyCode.C then\r\n\t\t\timpulse()\r\n\t\tend\r\n\tend\r\nend\r\n\r\nRunService.PreRender:Connect(onUpdate)\r\nUserInputService.InputBegan:Connect(onInputBegan)\r\n```\r\n\r\n**Same as Roblox Example, but using EasySmoothDamp - 54 Lines (with more comments) and Feedback values for SmoothDamp are just hidden behind a metatable!**\r\n```lua\r\nlocal RunService = game:GetService(\"RunService\")\r\nlocal UserInputService = game:GetService(\"UserInputService\")\r\n\r\nlocal EasySmoothDamp = require(game.ReplicatedStorage.EasySmoothDamp)\r\n\r\nlocal head = script.Parent:WaitForChild(\"Head\") :: BasePart\r\n\r\nlocal cloud = script.Cloud\r\ncloud.Parent = script.Parent -- Put cloud into the character model\r\n\r\n-- Offset from the head\r\nlocal offset = Vector3.new(0, 5, 0)\r\n\r\n-- Feedback values for SmoothDamp:\r\nlocal CloudSmoothDamper = EasySmoothDamp.new(\r\n\thead.CFrame + offset, -- currentCFrame\r\n\thead.CFrame + offset, -- targetCFrame\r\n\tVector3.zero, -- currentVelocity\r\n\t0.5, -- smoothTime\r\n\tnil -- maxSpeed\r\n)\r\n-- When this is set to false\r\nCloudSmoothDamper.IsReturnIsFinishedStateOnUpdateEnabled = false\r\n-- SmoothDamper:Update(dt) -> returns only the currentValue (named \r\n-- currentCFrame for this example); This can be passed as argument\r\n-- e.g. cloud:PivotTo(CloudSmoothDamper:Update(dt))\r\n\r\nlocal function impulse()\r\n\t--currentVelocity += Vector3.new(0, 10, 0)\r\n\tCloudSmoothDamper.CurrentSpeed += Vector3.new(0, 10, 0)\r\nend\r\n\r\nlocal function onUpdate(dt: number)\r\n\t--local targetCFrame = head.CFrame + offset\r\n\tCloudSmoothDamper.CurrentGoal = head.CFrame + offset\r\n\r\n\t--currentCFrame, ... = TweenService:SmoothDamp(...)\r\n\tlocal currentCFrame = CloudSmoothDamper:Update(dt)\r\n\r\n\tcloud:PivotTo(currentCFrame)\r\nend\r\n\r\nlocal function onInputBegan(input: InputObject, processed: boolean)\r\n\tif processed then return end\r\n\r\n\tif input.UserInputType == Enum.UserInputType.Keyboard then\r\n\t\tif input.KeyCode == Enum.KeyCode.C then\r\n\t\t\timpulse()\r\n\t\tend\r\n\tend\r\nend\r\n\r\nRunService.PreRender:Connect(onUpdate)\r\nUserInputService.InputBegan:Connect(onInputBegan)\r\n```\r\n\r\n---\r\n\r\n## Basic Usage\r\n\r\n- **Creating a SmoothDamper - EasySmoothDamp.new(...)**\r\n```lua\r\n-- Make a number go from 0 to 100\r\n\r\nlocal SmoothDamper = EasySmoothDamp.new(\r\n\t-- EasySmoothDamp naming (Documentation naming) [isRequired?] {Defaults}\r\n\t0, -- CurrentValue (current) [✅] {none}\r\n\t100, -- CurrentGoal (target) [✅] {none}\r\n\t0, -- CurrentSpeed (velocity) {0, Vector2.zero, Vector3.zero, CFrame.identity}\r\n\t0.1, -- SmoothTime (smoothTime) {0.3}\r\n\t100 -- MaxSpeed (maxSpeed) {100}\r\n)\r\n-- type of SmoothDamper -> in this case EasySmoothDamp.SmoothDamper<number>\r\n```\r\n\r\n- **SmoothDamper:Update(deltaTime: number?)**\r\n```lua\r\nlocal RunService = game:GetService(\"RunService\")\r\nlocal conn = nil\r\n\r\n-- Update the value after given DeltaTime\r\nconn = RunService.PreRender:Connect(function(dt: number)\r\n\tlocal currentValue, isFinished = SmoothDamper:Update(dt)\r\n\r\n    print(`Current Value = {currentValue}`)\r\n\r\n    if isFinished then\r\n        conn:Disconnect()\r\n        -- the Value will be near 100, but not exactly!\r\n        -- It'd be somewhere in between 100-EPSILON to 100\r\n        print(`Done! Finished with Value = {currentValue}`)\r\n    end\r\nend)\r\n```\r\n\r\n- **Setting custom EPSILON - EasySmoothDamp.SetEPSILON(newEPSILONValue : number?)**\r\n\r\n```lua\r\n-- Default EPSILON is 1e-3 (0.001)\r\n\r\nEasySmoothDamp.SetEPSILON() -- sets EPSILON back to 1e-3 (0.001)\r\nEasySmoothDamp.SetEPSILON(0.123) -- sets EPSILON to your number (e.g. 0.123)\r\n```\r\n\r\n- **Don't want to use RunService, but need auto deltaTime? - Here's an example!**\r\n```lua\r\n-- be careful automatic deltaTime is calculated since the creation time of the SmoothDamper!\r\n-- if you had something like a huge wait between creation of the SmoothDamper and\r\n-- its :Update() without a specified deltaTime, don't forget to reset!\r\n\r\n-- SmoothDamper created using EasySmoothDamp.new(...)\r\n-- Something took multiple seconds to load, before the update loop starts (we'll simulate it)\r\ntask.wait(3)\r\nSmoothDamper:ResetInternalTime()\r\n\r\n-- Warning! Do NOT run this in Command Bar, EasySmoothDamp uses time(), which is\r\n-- always zero for whenever you aren't in test mode.\r\n\r\nwhile task.wait() do\r\n    local currentValue, isFinished = SmoothDamper:Update() -- don't set deltaTime\r\n    -- so it calculates automatically\r\n\r\n    print(`Current Value = {currentValue}`)\r\n\r\n    if isFinished then\r\n        -- the Value will be near 100, but not exactly!\r\n        -- It'd be somewhere in between 100-EPSILON to 100\r\n        print(`Done! Finished with Value = {currentValue}`)\r\n        break\r\n    end\r\nend\r\n```\r\n\r\n- **Want to only receive *currentValue*, but not the isFinished when using :Update?**\r\n```lua\r\n-- simply turn it off!\r\nSmoothDamper.IsReturnIsFinishedStateOnUpdateEnabled = false\r\n-- (or turn it back on by setting it back to true)\r\n```\r\n\r\n- **SmoothDamper:IsFinished(): boolean**\r\n```lua\r\n-- If you've disabled the receival of isFinished argument, you might want to\r\n-- check it sometimes, do it using :IsFinished()\r\n\r\nprint(SmoothDamper:IsFinished()) -- false\r\n\r\nSmoothDamper.CurrentValue = SmoothDamper.CurrentGoal\r\n\r\nprint(SmoothDamper:IsFinished()) -- true\r\n```\r\n\r\n---\r\n\r\n## API\r\n\r\n**EasySmoothDamp**\r\n- `.new(CurrentValue : T, CurrentGoal : T, CurrentSpeed : (T)?, SmoothTime : number?, MaxSpeed : number?): SmoothDamper<T>`\r\n> T is one of the SmoothDampSupported types - number | Vector2 | Vector3 | CFrame\r\n\r\n> CurrentValue and CurrentGoal must be the same type\r\n\r\n> CurrentSpeed will be automatically set to the type of CurrentValue, even if a wrong CurrentSpeed type is given (doesn't throw errors)\r\n\r\n> CurrentValue, CurrentGoal and CurrentSpeed can only be reassigned to the same initial type T later.\r\n- `.SetEPSILON(newEPSILONValue : number?)`\r\n> Default EPSILON is 1e-3 (0.001); Given no newEPSILONValue applies the default.\r\n\r\n**SmoothDamper**\r\n- `:Update(deltaTime: number?): (T, boolean?)`\r\n> Calls TweenService:SmoothDamp with the given deltaTime or calculates the deltaTime automatically (time since creation via .new or last :Update call)\r\n\r\n> returns CurrentValue, and if self.IsReturnIsFinishedStateOnUpdateEnabled is true, also returns the result of :IsFinished()\r\n- `:IsFinished(): boolean`\r\n> Checks whether the difference between CurrentValue and CurrentGoal is less than EPSILON\r\n- `:ResetInternalTime()`\r\n> Resets last :Update() call time to current time()\r\n\r\n---\r\n\r\n## NOTES\r\n\r\nEverytime you use `SmoothDamper:Update()`, it also does `SmoothDamper:IsFinished()` to return isFinished boolean, unless disabled by setting `SmoothDamper.IsReturnIsFinishedStateOnUpdateEnabled = false`\r\n\r\n---\r\n\r\n## License & Attribution\r\n\r\nThis module is licensed under the **Mozilla Public License 2.0 (MPL 2.0)**.\r\n\r\n#### What this means for Roblox Developers:\r\n* **Use & Modify:** You can freely use this module in any public, private, or commercial Roblox game.\r\n* **File-Level Copyleft:** If you modify the source code of this module itself, you must make your modified version of the module publicly available under the MPL 2.0.\r\n* **No Viral Code Leakage:** Including this module in your game does **not** force you to open-source your other game scripts, UI layouts, or proprietary codebase. \r\n\r\nSee the full terms in the [LICENSE](LICENSE) file.\r\n\r\nAttribution to all dependencies is included in [Notice](NOTICE)\r\n\r\nCopyright © 2026 @Coffilhg (Roblox UserId 517222346)","readmeTruncated":false}