Epoxyish, a modern spring solution

It will be uploaded to Wally in the next couple of days

what about roblox ts? When will it be uploaded to that?

That uses Wally to my knowledge.

roblox ts doesnā€™t use wally, it uses npm.

Oop, just checked, I think youā€™re correct.

In that case, no, Iā€™m not uploading to roblox-ts.

Update number one is here!

  • Added Spring.Active :: boolean
  • Added Spring.Completed :: Signal<nil>
  • Added Spring.DisconnectLatch :: () -> nil

You can see what these changes entail in the post! It has been updated to let ya know.

These resources take time and effort to make! Please support me for just $1 a month on my Patreon.

So it just exists for the purpose of recreating what RunService has already done and makes your code shorter? Interesting.

Iā€™d probably stick with RunService, but who knows, maybe Iā€™ll find a good use-case for it in the near future.

Yes, but a bit more; there are two built-in functionalities as well.

If your instance is destroyed, Latch will automatically un-queue it from the spring scheduler and clean up everything.

There is also a new DisconnectLatch method of the Spring itself, so calling it cleans up the connection without you having to keep track of your own Run Service connection.

2 Likes

Wow, thats something that roblox developers really needed. Thank you so much for this! Also it would be really cool if you made a desmos formula to help the developers visualise their spring.

1 Like

The URL Seems Misleading, It says ā€œWallyā€ even though it takes you to the github repository, but itā€™s great :slight_smile: and this is the real Epoxyish Wally link and are you ā€œMiaGobbleā€ on GitHub or did someone reuploaded it to github?

1 Like

I am MiaGobble, so the upload is mine.

1 Like

Not sure if I just downloaded an old version of Iā€™m missing something, but your :Impulse() doesnā€™t really work for all types?

function Spring:Impulse(Force : any)
	self.Velocity += Force
end

Youā€™re not really checking for other types. If I used a CFrame for the force, it would break.

I havenā€™t really dived into the code that deeply, but shouldnā€™t it be this instead?

function Spring:Impulse(Force : any)
	self.Add(self.Velocity, Force)
end

Yeah, that was definitely an oversight, Iā€™ll publish a new version soon. Thanks for pointing that out!

1 Like

Hi, Iā€™m trying to use the module to spring the CFrame of a modelā€™s primary part & a hitbox part at the same time.
Both have their own Values, Springs & Latchā€™s, yet it seems that they donā€™t spring to their new set CFrame when it changesā€¦
RobloxStudioBeta_LFxEaciplq

Could you show some code snippets?

2 Likes

Hereā€™s snippets of the code. The Completed function never fires (I never see the prints) either.

-- initialization (only ran once)
local spring_values = {}
local spring_springs = {}

spring_values[ClientStatus.ObjClone] = mod_epoxyish.Value(CFrame.new())
spring_values[ClientStatus.ObjHitbox] = mod_epoxyish.Value(CFrame.new())
		
spring_springs[ClientStatus.ObjClone] = mod_epoxyish.Spring{
	Target = spring_values[ClientStatus.ObjClone],
			
	Speed = 10,
	Dampening = 5,
	Mass = 8,
	Force = 30,
}
spring_springs[ClientStatus.ObjHitbox] = mod_epoxyish.Spring{
	Target = spring_values[ClientStatus.ObjHitbox],

	Speed = 10,
	Dampening = 5,
	Mass = 8,
	Force = 30,
}
		
spring_springs[ClientStatus.ObjClone].Completed:Connect(function()
	print("spring model completed")
end)
spring_springs[ClientStatus.ObjHitbox].Completed:Connect(function()
	print("spring hitbox completed")
end)
		
mod_epoxyish.Latch(ClientStatus.ObjClone.PrimaryPart){CFrame = spring_values[ClientStatus.ObjClone]}
mod_epoxyish.Latch(ClientStatus.ObjHitbox){CFrame = spring_values[ClientStatus.ObjHitbox]}

-- updated every frame (if cframes have changed)
spring_values[ClientStatus.ObjClone]:Set(cf_obj)
spring_values[ClientStatus.ObjHitbox]:Set(cf_hit)

You are making them target each other, it seems like.

1 Like

This resource sounds great, but there is a lot of boilerplate code which Iā€™m afraid will clutter up my codebase.

For instance, suppose I want to animate the ImageColor property and Position property of an ImageLabel, with a tool like spr, this will just amount to:

spr.target(DAMPING_RATIO, FREQUENCY, {
    ImageColor = Color3.new(1, 0, 0),
    Position = UDim2.fromScale(0.5, 0.5)
})

but with Epoxyish, on top of the existing boilerplate code, Iā€™d still have to create an entirely new spring for each property I want to animate.

local ImageLabel = ...

local Value = Epoxyish.Value
local Latch = Epoxyish.Latch
local Spring = Epoxyish.Spring

local imageColorValue = Value(Color3.new(0, 0, 0))
local imageColorSpring = Spring {
    Target = imageColorValue,

    Speed = 5,
    Dampening = 3
}

local positionValue = Value(UDim2.fromScale(-0.5, 0))
local positionSpring = Spring {
    Target = positionValue ,

    Speed = 5,
    Dampening = 3
}

Latch(ImageLabel) {
    Position = positionSpring,
    ImageColor = imageColorSpring
}

The difference between both approaches are clearly visible. While the first one is easier to understand, read and modify, the latter looks more complicated, confusing, and wellā€¦ ugly (yes you heard me right).

All in all, this is a great module whose API design might sound good on paper but in practice is a horrible one.

Rather than using variables, I recommend making the springs in-line for the latch construction.

Springs are separate since Latch might not always be something that a developer would want to use. Having the two be separate is important for that!

Here is an example of your code modified to this type of structure:

local ImageLabel = ...

local Value = Epoxyish.Value
local Latch = Epoxyish.Latch
local Spring = Epoxyish.Spring

local imageColorValue = Value(Color3.new(0, 0, 0))
local positionValue = Value(UDim2.fromScale(-0.5, 0))

Latch(ImageLabel) {
    Position = Spring {
		Target = positionValue ,
	
		Speed = 5,
		Dampening = 3
	},

    ImageColor = Spring {
		Target = imageColorValue,
	
		Speed = 5,
		Dampening = 3
	}
}

Could you clarify here?

1 Like

Omg, I have been wanting and asking for a standalone Fusion style spring since the very moment Iā€™ve used it. This is awesome, tysm!

But I am having an issue with the wally version, the signal module seems to be missing from the ā€œSpringā€ modulescript, causing an error on runtime.

Also checked the github to make sure that my wally install isnā€™t doing weird stuff, and it verifies that the signal module is actually missing.