So I’m wondering if there is a Spring Modules but with CFrame. I’m trying to do some spring stuff with my viewmodel and it uses Vector3 which can cause problems.

There is TweenService and `:Lerp`

but if you are looking for a spring module there’s Flipper. It’s based around Motors and goals.

I would honestly recommend just doing the first two options.

Although a vector3 usually represents the displacement of a spring, for a swaying viewmodel I believe you can make the vector3 represent the **angular displacement** of the view model rotation, in a similar manner to this:

I’ll see if I can work a solution to this seems interesting.

Here made something, cool to spring up your FPS view model:

It’s a local script which uses Quenty’s spring module to add a spring effect to the otherwise static view model.

Before spring:

After Spring:

Code, insert into your starterCharacter scripts as a local script and test it out. Values for the spring will need adjusting of course.

–Edit: Here’s a better working version with the dampening actually working, messed up the previous CFrame calculation. Still have no idea how to limit the rotation with the spring forces following in suite. Also the video I posted is old and doesn’t contained the fixed changes but am too lazy to reupload so try it out yourself.

Edit 2: Updated it with viewmodel clamping and removed the nan error:

## Old code

```
local part = Instance.new("Part")
part.Size = Vector3.new(0.5,0.5,2)
part.Anchored = true
part.CanCollide = false
part.Parent = workspace
local cameraOffset = CFrame.new(0.8, -0.6, -2.2)
local camera = workspace.CurrentCamera
local RunService = game:GetService("RunService")
local Spring = require(script:WaitForChild("Spring"))
local ZEROVECTOR =Vector3.new()
local viewmodelSpring = Spring.new(ZEROVECTOR)
viewmodelSpring.Speed = 5
viewmodelSpring.Damper = 0.25 --1 is perfect dampening
local function clampMagnitude(vector, maxMagnitude)
return (vector.Magnitude > maxMagnitude and (vector.Unit * maxMagnitude) or vector)
end
function angleBetween(vector1, vector2)
return math.acos(math.clamp(vector1.Unit:Dot(vector2.Unit), -1, 1))
end
local deltaSensitivity = -2 -- increases force from mouse delta
--if negative force goes in opposite direction, viewmodel is lagging behind
local maxAngle = 30 --degrees
local previousGoalCFrame = CFrame.new()
RunService.RenderStepped:Connect(function(step)
local goalCFrame = camera.CFrame*cameraOffset
part.CFrame = goalCFrame
--Spring stuff
local differenceCF = previousGoalCFrame:ToObjectSpace(goalCFrame)
local axis, angle = differenceCF:ToAxisAngle()
local angularDisplacement = axis*angle
previousGoalCFrame = goalCFrame
local springForce = angularDisplacement*deltaSensitivity
viewmodelSpring:Impulse(springForce)
local partSpringOffset = viewmodelSpring.Position
local axis = partSpringOffset.Unit
local angle = partSpringOffset.Magnitude
--clamp the angle don't want it to speen 360 degrees unless you want it to
--velocity goes wild though
angle = math.deg(angle)
if angle > maxAngle then
--print("Clamped")
--local maxAngularDisplacement = axis*angle
local currentViewModelVelocity = viewmodelSpring.Velocity
local collision = math.sign(currentViewModelVelocity:Dot(axis))
--1 is colliding, -1 is going away from colliding wall normal
if collision > 0 then
local reactionAngle = angleBetween(currentViewModelVelocity.Unit,axis)
local resolve = math.cos(reactionAngle)
local reactionForce = -axis*currentViewModelVelocity.Magnitude*resolve
viewmodelSpring:Impulse(reactionForce)
end
end
angle = math.clamp(angle,0,maxAngle)
angle = math.rad(angle)
if angle > 0.001 then--Nan check checking if there is no spring caused rotation
part.CFrame *= CFrame.fromAxisAngle(axis,angle)
end
end)
```

Edit 3: I have gotten the time to be reinterested in this problem as it popped up again in #help-and-feedback:scripting-support so here is the video of it after the CFrames are applied to a viewmodel Humanoid root part, with a gun welded to it which changes the center of rotation instead of rotating through the center of the gun. Also the speed is increased so it follows the camera faster and doesn’t lag too far behind.

You can replace psuedoHRP with your own view model “Camera”, apply some offsets and do whatever.

After After After spring improvements

I recommend playing around with these variables:

```
viewmodelSpring.Speed = 10 --changes how fast it accelerates.
viewmodelSpring.Damper = 0.95 --1 is perfect dampening, 0 is no dampening
local deltaSensitivity = -2 -- increases force from mouse delta
--if negative force goes in opposite direction, viewmodel is lagging behind,
--Ex, camera turn right, model turns left if negative.
local maxAngle = 30 --degrees, will prevent the gun from being used as a fidget spinner
```

## New improved viewmodel spring code example

```
local gunPart = Instance.new("Part")
gunPart.Size = Vector3.new(0.5,0.5,2)
gunPart.Anchored = false
gunPart.CanCollide = false
gunPart.Parent = workspace
local psuedoHRP = Instance.new("Part")
psuedoHRP.Name = "ViewmodelHRP"
psuedoHRP.Size = Vector3.new(0.5,0.5,2)
psuedoHRP.Anchored = true
psuedoHRP.CanCollide = false
psuedoHRP.Parent = workspace
psuedoHRP.Transparency = 0.5
local weld = Instance.new("Weld")
weld.C0 = CFrame.new(1, -0.4, -1.4)
weld.Part0 = psuedoHRP
weld.Part1 = gunPart
weld.Parent = gunPart
local camera = workspace.CurrentCamera
local RunService = game:GetService("RunService")
local Spring = require(script:WaitForChild("Spring"))
local ZEROVECTOR =Vector3.new()
local viewmodelSpring = Spring.new(ZEROVECTOR)
viewmodelSpring.Speed = 10
viewmodelSpring.Damper = 0.95 --1 is perfect dampening
local function clampMagnitude(vector, maxMagnitude)
return (vector.Magnitude > maxMagnitude and (vector.Unit * maxMagnitude) or vector)
end
function angleBetween(vector1, vector2)
return math.acos(math.clamp(vector1.Unit:Dot(vector2.Unit), -1, 1))
end
local deltaSensitivity = -2 -- increases force from mouse delta
--if negative force goes in opposite direction, viewmodel is lagging behind
local maxAngle = 30 --degrees
local previousGoalCFrame = CFrame.new()
RunService.RenderStepped:Connect(function(step)
local goalCFrame = camera.CFrame
psuedoHRP.CFrame = goalCFrame
--Spring stuff
local differenceCF = previousGoalCFrame:ToObjectSpace(goalCFrame)
local axis, angle = differenceCF:ToAxisAngle()
local angularDisplacement = axis*angle
previousGoalCFrame = goalCFrame
local springForce = angularDisplacement*deltaSensitivity
viewmodelSpring:Impulse(springForce)
local partSpringOffset = viewmodelSpring.Position
local axis = partSpringOffset.Unit
local angle = partSpringOffset.Magnitude
--clamp the angle don't want it to speen 360 degrees unless you want it to
--velocity goes wild though
angle = math.deg(angle)
if angle > maxAngle then
--print("Clamped")
--local maxAngularDisplacement = axis*angle
local currentViewModelVelocity = viewmodelSpring.Velocity
local collision = math.sign(currentViewModelVelocity:Dot(axis))
--1 is colliding, -1 is going away from colliding wall normal
if collision > 0 then
local reactionAngle = angleBetween(currentViewModelVelocity.Unit,axis)
local resolve = math.cos(reactionAngle)
local reactionForce = -axis*currentViewModelVelocity.Magnitude*resolve
viewmodelSpring:Impulse(reactionForce)
end
end
angle = math.clamp(angle,0,maxAngle)
angle = math.rad(angle)
if angle > 0.001 then--Nan check checking if there is no spring caused rotation
psuedoHRP.CFrame *= CFrame.fromAxisAngle(axis,angle)
end
end)
```

Woah, what an awesome module! Kinda disappointed I haven’t heard about this module earlier but glad I knew about it today!

Yeah I like the module because it uses os.clock() and cool metatable stuff.

I think an easier way of doing this is to use the mouse delta to get the shoving force direction and magnitude instead of my overly complicated CFrame approach from this really neat FPS tutorial which I should have looked at earlier .

```
-- Let's get some mouse movement!
local mouseDelta = game:GetService("UserInputService"):GetMouseDelta()
self.springs.sway:shove(Vector3.new(mouseDelta.x / 200,mouseDelta.y / 200)) --not sure if this needs deltaTime filtering
--vs my wut CFrame approach
local differenceCF = previousGoalCFrame:ToObjectSpace(goalCFrame)
local axis, angle = differenceCF:ToAxisAngle()
local angularDisplacement = axis*angle
previousGoalCFrame = goalCFrame
local springForce = angularDisplacement*deltaSensitivity
viewmodelSpring:Impulse(springForce)
```

And to convert the spring force into bobbing you can just use CFrame.Angles instead of CFrame.fromAxisAngles, I believe the CFrame Angles approach gets rid of the rolling rotation as well if thats what you are looking for:

```
--tutorial sway method:
local sway = self.springs.sway:update(deltaTime)
self.viewmodel.rootPart.CFrame *= CFrame.Angles(0,-sway.x,sway.y)
--my CFrame from axis angle method:
local partSpringOffset = viewmodelSpring.Position
local axis = partSpringOffset.Unit
local angle = partSpringOffset.Magnitude
part.CFrame *= CFrame.fromAxisAngle(axis,angle)
```

Edit: I do like axis angles a lot.

you literallty just saved me 1000 hours of coding thank you

Is there a way to achieve the same thing but without the spring effect (same effect as perfect dampening)? I tried removing the spring part of the script and it came out really rough.

For the bobing part it throws an error, part.CFrame *= CFrame.Angles(axis,angle), " 18:25:12.420 Argument 3 missing or nil - Studio"