diff --git a/.cursor/plans/remove_plugin_animations_f4a43647.plan.md b/.cursor/plans/remove_plugin_animations_f4a43647.plan.md new file mode 100644 index 00000000..f42eb850 --- /dev/null +++ b/.cursor/plans/remove_plugin_animations_f4a43647.plan.md @@ -0,0 +1,101 @@ +--- +name: Remove Plugin Animations +overview: Replace every `Flipper.Spring.new(...)` with `Flipper.Instant.new(...)` across all plugin components to make all UI transitions instant, and remove the 0.3s double-click delay in DomLabel expand/collapse. +todos: + - id: domlabel + content: "DomLabel.lua: Replace 2 Spring goals with Instant, remove task.delay(0.3) wrapper from expand logic" + status: completed + - id: page + content: "Page.lua: Replace Spring goal with Instant" + status: completed + - id: touchripple + content: "TouchRipple.lua: Replace 3 Spring goals with Instant, remove EXPAND_SPRING constant" + status: completed + - id: textbutton + content: "TextButton.lua: Replace 3 Spring goals with Instant, remove SPRING_PROPS constant" + status: completed + - id: textinput + content: "TextInput.lua: Replace 3 Spring goals with Instant, remove SPRING_PROPS constant" + status: completed + - id: notification + content: "Notification.lua: Replace 2 Spring goals with Instant" + status: completed + - id: dropdown + content: "Dropdown.lua: Replace Spring goal with Instant" + status: completed + - id: iconbutton + content: "IconButton.lua: Replace 2 Spring goals with Instant, remove HOVER_SPRING_PROPS constant" + status: completed + - id: checkbox + content: "Checkbox.lua: Replace Spring goal with Instant" + status: completed +isProject: false +--- + +# Remove All Animations From Plugin + +## Strategy + +Every animation in the plugin uses Flipper motors with `Flipper.Spring.new(value, { frequency, dampingRatio })` goals. The Flipper library already has `Flipper.Instant.new(value)` which sets the motor value immediately with no interpolation. The fix is a mechanical replacement of every `Flipper.Spring.new(...)` with `Flipper.Instant.new(...)`. + +This preserves the binding/motor infrastructure (no structural refactoring needed) while making every transition instant. + +Additionally, the DomLabel expand/collapse has a `task.delay(0.3)` that waits to distinguish single-click from double-click before expanding. This delay should be removed so expansion is immediate on click. + +## Files to Change (10 files, ~20 replacements) + +### 1. [DomLabel.lua](plugin/src/App/Components/PatchVisualizer/DomLabel.lua) -- Expand/collapse + +- Line 436: `Flipper.Spring.new(24, {...})` -> `Flipper.Instant.new(24)` +- Line 602: `Flipper.Spring.new(goalHeight, {...})` -> `Flipper.Instant.new(goalHeight)` +- Lines 545-608: Remove the `task.delay(0.3)` wrapper so expansion logic runs immediately on single click (keep double-click detection, just don't delay the expand) + +### 2. [Page.lua](plugin/src/App/Page.lua) -- Page transitions + +- Line 65: `Flipper.Spring.new(...)` -> `Flipper.Instant.new(...)` + +### 3. [TouchRipple.lua](plugin/src/App/Components/TouchRipple.lua) -- Click ripple effect + +- Line 84: `Flipper.Spring.new(1, EXPAND_SPRING)` -> `Flipper.Instant.new(1)` +- Line 85: `Flipper.Spring.new(1, EXPAND_SPRING)` -> `Flipper.Instant.new(1)` +- Line 93: `Flipper.Spring.new(0, {...})` -> `Flipper.Instant.new(0)` +- Remove unused `EXPAND_SPRING` constant + +### 4. [TextButton.lua](plugin/src/App/Components/TextButton.lua) -- Hover/enabled + +- Line 36: `Flipper.Spring.new(...)` -> `Flipper.Instant.new(...)` +- Line 64: `Flipper.Spring.new(1, SPRING_PROPS)` -> `Flipper.Instant.new(1)` +- Line 70: `Flipper.Spring.new(0, SPRING_PROPS)` -> `Flipper.Instant.new(0)` +- Remove unused `SPRING_PROPS` constant + +### 5. [TextInput.lua](plugin/src/App/Components/TextInput.lua) -- Hover/enabled + +- Line 34: `Flipper.Spring.new(...)` -> `Flipper.Instant.new(...)` +- Line 101: `Flipper.Spring.new(1, SPRING_PROPS)` -> `Flipper.Instant.new(1)` +- Line 107: `Flipper.Spring.new(0, SPRING_PROPS)` -> `Flipper.Instant.new(0)` +- Remove unused `SPRING_PROPS` constant + +### 6. [Notification.lua](plugin/src/App/Components/Notifications/Notification.lua) -- Appear/dismiss + +- Line 43: `Flipper.Spring.new(0, {...})` -> `Flipper.Instant.new(0)` +- Line 50: `Flipper.Spring.new(1, {...})` -> `Flipper.Instant.new(1)` + +### 7. [Dropdown.lua](plugin/src/App/Components/Dropdown.lua) -- Open/close + +- Line 39: `Flipper.Spring.new(...)` -> `Flipper.Instant.new(...)` + +### 8. [IconButton.lua](plugin/src/App/Components/IconButton.lua) -- Hover circle + +- Line 41: `Flipper.Spring.new(1, HOVER_SPRING_PROPS)` -> `Flipper.Instant.new(1)` +- Line 45: `Flipper.Spring.new(0, HOVER_SPRING_PROPS)` -> `Flipper.Instant.new(0)` +- Remove unused `HOVER_SPRING_PROPS` constant + +### 9. [Checkbox.lua](plugin/src/App/Components/Checkbox.lua) -- Active state + +- Line 26: `Flipper.Spring.new(...)` -> `Flipper.Instant.new(...)` + +## Not Touched + +- **Spinner.lua** -- Uses `RenderStepped` rotation, not Flipper springs. This is a loading indicator, not a decorative animation. Keeping it. +- **bindingUtil.lua** -- `mapLerp`, `blendAlpha`, `fromMotor` are utility functions still needed by the instant-value bindings. No changes needed. +- **Flipper package** -- Vendored, not modified. diff --git a/plugin/src/App/Components/Checkbox.lua b/plugin/src/App/Components/Checkbox.lua index 98cbf8c0..c2bfd134 100644 --- a/plugin/src/App/Components/Checkbox.lua +++ b/plugin/src/App/Components/Checkbox.lua @@ -23,10 +23,7 @@ end function Checkbox:didUpdate(lastProps) if lastProps.active ~= self.props.active then - self.motor:setGoal(Flipper.Spring.new(self.props.active and 1 or 0, { - frequency = 6, - dampingRatio = 1.1, - })) + self.motor:setGoal(Flipper.Instant.new(self.props.active and 1 or 0)) end end diff --git a/plugin/src/App/Components/Dropdown.lua b/plugin/src/App/Components/Dropdown.lua index 486a614c..a697135f 100644 --- a/plugin/src/App/Components/Dropdown.lua +++ b/plugin/src/App/Components/Dropdown.lua @@ -36,10 +36,7 @@ function Dropdown:didUpdate(prevProps) }) end - self.openMotor:setGoal(Flipper.Spring.new(self.state.open and 1 or 0, { - frequency = 6, - dampingRatio = 1.1, - })) + self.openMotor:setGoal(Flipper.Instant.new(self.state.open and 1 or 0)) end function Dropdown:render() diff --git a/plugin/src/App/Components/IconButton.lua b/plugin/src/App/Components/IconButton.lua index dc451b0d..1b74d835 100644 --- a/plugin/src/App/Components/IconButton.lua +++ b/plugin/src/App/Components/IconButton.lua @@ -8,11 +8,6 @@ local Flipper = require(Packages.Flipper) local Assets = require(Plugin.Assets) local bindingUtil = require(Plugin.App.bindingUtil) -local HOVER_SPRING_PROPS = { - frequency = 5, - dampingRatio = 1.1, -} - local e = Roact.createElement local IconButton = Roact.Component:extend("IconButton") @@ -38,11 +33,11 @@ function IconButton:render() [Roact.Event.Activated] = self.props.onClick, [Roact.Event.MouseEnter] = function() - self.motor:setGoal(Flipper.Spring.new(1, HOVER_SPRING_PROPS)) + self.motor:setGoal(Flipper.Instant.new(1)) end, [Roact.Event.MouseLeave] = function() - self.motor:setGoal(Flipper.Spring.new(0, HOVER_SPRING_PROPS)) + self.motor:setGoal(Flipper.Instant.new(0)) end, }, { Icon = e("ImageLabel", { diff --git a/plugin/src/App/Components/Notifications/Notification.lua b/plugin/src/App/Components/Notifications/Notification.lua index 1d9464c9..bdb288f5 100644 --- a/plugin/src/App/Components/Notifications/Notification.lua +++ b/plugin/src/App/Components/Notifications/Notification.lua @@ -40,17 +40,11 @@ function Notification:dismiss() end self.dismissed = true - self.motor:setGoal(Flipper.Spring.new(0, { - frequency = 5, - dampingRatio = 1, - })) + self.motor:setGoal(Flipper.Instant.new(0)) end function Notification:didMount() - self.motor:setGoal(Flipper.Spring.new(1, { - frequency = 3, - dampingRatio = 1, - })) + self.motor:setGoal(Flipper.Instant.new(1)) self.props.soundPlayer:play(Assets.Sounds.Notification) diff --git a/plugin/src/App/Components/PatchVisualizer/DomLabel.lua b/plugin/src/App/Components/PatchVisualizer/DomLabel.lua index 212aed0e..f8e4872a 100644 --- a/plugin/src/App/Components/PatchVisualizer/DomLabel.lua +++ b/plugin/src/App/Components/PatchVisualizer/DomLabel.lua @@ -433,10 +433,7 @@ function DomLabel:didUpdate(prevProps) then -- Close the expansion when the domlabel is changed to a different thing self.expanded = false - self.motor:setGoal(Flipper.Spring.new(24, { - frequency = 5, - dampingRatio = 1, - })) + self.motor:setGoal(Flipper.Instant.new(24)) end end @@ -541,71 +538,50 @@ function DomLabel:render() SelectionService:Set({ props.instance }) end else - -- Single click expands the changes (after a delay to check for double click) - task.delay(0.3, function() - -- Guard against unmounted component or stale click - if not self.isMounted then + -- Removed script: show diff of old source vs empty + if + props.patchType == "Remove" + and props.instance + and props.changeInfo + and props.changeInfo.linesRemoved + and props.showStringDiff + then + local ok, source = pcall(function() + return (props.instance :: any).Source + end) + if ok and type(source) == "string" then + props.showStringDiff(source, "", props.instancePath) return end + end - if os.clock() - (self.lastDoubleClickTime or 0) <= 0.35 then - -- This was a double click, so don't expand - return - end - - -- Use self.props to get current props, not stale closure - local p = self.props - - -- Removed script: show diff of old source vs empty - if - p.patchType == "Remove" - and p.instance - and p.changeInfo - and p.changeInfo.linesRemoved - and p.showStringDiff - then - local ok, source = pcall(function() - return (p.instance :: any).Source - end) - if ok and type(source) == "string" then - p.showStringDiff(source, "", p.instancePath) + -- Added script: find Source in changeList and show diff of empty vs new source + if + props.patchType == "Add" + and props.changeList + and props.changeInfo + and props.changeInfo.linesAdded + and props.showStringDiff + then + for _, entry in props.changeList do + if entry[1] == "Source" and type(entry[3]) == "string" then + props.showStringDiff("", tostring(entry[3]), props.instancePath) return end end + end - -- Added script: find Source in changeList and show diff of empty vs new source - if - p.patchType == "Add" - and p.changeList - and p.changeInfo - and p.changeInfo.linesAdded - and p.showStringDiff - then - for _, entry in p.changeList do - if entry[1] == "Source" and type(entry[3]) == "string" then - p.showStringDiff("", tostring(entry[3]), p.instancePath) - return - end - end + if props.changeList then + local cl = props.changeList + if #cl == 2 and cl[2][1] == "Source" and props.showStringDiff then + props.showStringDiff(tostring(cl[2][2]), tostring(cl[2][3]), props.instancePath) + else + self.expanded = not self.expanded + local goalHeight = 24 + + (if self.expanded then math.clamp(#props.changeList * 24, 24, 24 * 6) else 0) + self.motor:setGoal(Flipper.Instant.new(goalHeight)) end - - if p.changeList then - -- If the only change is Source, open the diff viewer directly - -- changeList[1] is the header, changeList[2+] are entries - local cl = p.changeList - if #cl == 2 and cl[2][1] == "Source" and p.showStringDiff then - p.showStringDiff(tostring(cl[2][2]), tostring(cl[2][3]), p.instancePath) - else - self.expanded = not self.expanded - local goalHeight = 24 - + (if self.expanded then math.clamp(#p.changeList * 24, 24, 24 * 6) else 0) - self.motor:setGoal(Flipper.Spring.new(goalHeight, { - frequency = 5, - dampingRatio = 1, - })) - end - end - end) + end end end, }), diff --git a/plugin/src/App/Components/TextButton.lua b/plugin/src/App/Components/TextButton.lua index 1fe871fd..1978fb0f 100644 --- a/plugin/src/App/Components/TextButton.lua +++ b/plugin/src/App/Components/TextButton.lua @@ -13,11 +13,6 @@ local getTextBoundsAsync = require(Plugin.App.getTextBoundsAsync) local SlicedImage = require(script.Parent.SlicedImage) local TouchRipple = require(script.Parent.TouchRipple) -local SPRING_PROPS = { - frequency = 5, - dampingRatio = 1, -} - local e = Roact.createElement local TextButton = Roact.Component:extend("TextButton") @@ -33,7 +28,7 @@ end function TextButton:didUpdate(lastProps) if lastProps.enabled ~= self.props.enabled then self.motor:setGoal({ - enabled = Flipper.Spring.new(self.props.enabled and 1 or 0), + enabled = Flipper.Instant.new(self.props.enabled and 1 or 0), }) end end @@ -61,13 +56,13 @@ function TextButton:render() [Roact.Event.MouseEnter] = function() self.motor:setGoal({ - hover = Flipper.Spring.new(1, SPRING_PROPS), + hover = Flipper.Instant.new(1), }) end, [Roact.Event.MouseLeave] = function() self.motor:setGoal({ - hover = Flipper.Spring.new(0, SPRING_PROPS), + hover = Flipper.Instant.new(0), }) end, }, { diff --git a/plugin/src/App/Components/TextInput.lua b/plugin/src/App/Components/TextInput.lua index 5cf83f3f..f15a7c39 100644 --- a/plugin/src/App/Components/TextInput.lua +++ b/plugin/src/App/Components/TextInput.lua @@ -11,11 +11,6 @@ local bindingUtil = require(Plugin.App.bindingUtil) local SlicedImage = require(script.Parent.SlicedImage) -local SPRING_PROPS = { - frequency = 5, - dampingRatio = 1, -} - local e = Roact.createElement local TextInput = Roact.Component:extend("TextInput") @@ -31,7 +26,7 @@ end function TextInput:didUpdate(lastProps) if lastProps.enabled ~= self.props.enabled then self.motor:setGoal({ - enabled = Flipper.Spring.new(self.props.enabled and 1 or 0), + enabled = Flipper.Instant.new(self.props.enabled and 1 or 0), }) end end @@ -98,13 +93,13 @@ function TextInput:render() [Roact.Event.MouseEnter] = function() self.motor:setGoal({ - hover = Flipper.Spring.new(1, SPRING_PROPS), + hover = Flipper.Instant.new(1), }) end, [Roact.Event.MouseLeave] = function() self.motor:setGoal({ - hover = Flipper.Spring.new(0, SPRING_PROPS), + hover = Flipper.Instant.new(0), }) end, diff --git a/plugin/src/App/Components/TouchRipple.lua b/plugin/src/App/Components/TouchRipple.lua index 1ea4c27d..a5d047a1 100644 --- a/plugin/src/App/Components/TouchRipple.lua +++ b/plugin/src/App/Components/TouchRipple.lua @@ -8,11 +8,6 @@ local Flipper = require(Packages.Flipper) local Assets = require(Plugin.Assets) local bindingUtil = require(Plugin.App.bindingUtil) -local EXPAND_SPRING = { - frequency = 7, - dampingRatio = 2, -} - local TouchRipple = Roact.Component:extend("TouchRipple") function TouchRipple:init() @@ -81,8 +76,8 @@ function TouchRipple:render() self.setPosition(relativePosition) self.motor:setGoal({ - scale = Flipper.Spring.new(1, EXPAND_SPRING), - opacity = Flipper.Spring.new(1, EXPAND_SPRING), + scale = Flipper.Instant.new(1), + opacity = Flipper.Instant.new(1), }) input:GetPropertyChangedSignal("UserInputState"):Connect(function() @@ -90,10 +85,7 @@ function TouchRipple:render() if userInputState == Enum.UserInputState.Cancel or userInputState == Enum.UserInputState.End then self.motor:setGoal({ - opacity = Flipper.Spring.new(0, { - frequency = 5, - dampingRatio = 1, - }), + opacity = Flipper.Instant.new(0), }) end end) diff --git a/plugin/src/App/Page.lua b/plugin/src/App/Page.lua index 42bc68b2..30e76220 100644 --- a/plugin/src/App/Page.lua +++ b/plugin/src/App/Page.lua @@ -62,10 +62,7 @@ end function Page:didUpdate(lastProps) if self.props.active ~= lastProps.active then - self.motor:setGoal(Flipper.Spring.new(self.props.active and 1 or 0, { - frequency = 6, - dampingRatio = 1, - })) + self.motor:setGoal(Flipper.Instant.new(self.props.active and 1 or 0)) end end