@quenty/camera 14.22.1 → 14.22.2-canary.675e877.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,24 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [14.22.2-canary.675e877.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/camera@14.22.1...@quenty/camera@14.22.2-canary.675e877.0) (2025-08-07)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * Fix formatting ([41ceadb](https://github.com/Quenty/NevermoreEngine/commit/41ceadbc674b7860d8593019b5dc5d4cbe539deb))
12
+ * Setting RobloxCFrame also assigns the override CFrame ([1014f69](https://github.com/Quenty/NevermoreEngine/commit/1014f69cce67eda8cde99f7cb7b4243a83ec9fba))
13
+
14
+
15
+ ### Features
16
+
17
+ * Add CameraSubjectUtils ([5e32c47](https://github.com/Quenty/NevermoreEngine/commit/5e32c47a1cec33ca903c9f558463fffbc8f2daf4))
18
+ * Add epsilon ([9f61ef3](https://github.com/Quenty/NevermoreEngine/commit/9f61ef3c7fdfc8b7ffc65c592873fd960a5ef126))
19
+
20
+
21
+
22
+
23
+
6
24
  ## [14.22.1](https://github.com/Quenty/NevermoreEngine/compare/@quenty/camera@14.22.0...@quenty/camera@14.22.1) (2025-07-14)
7
25
 
8
26
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quenty/camera",
3
- "version": "14.22.1",
3
+ "version": "14.22.2-canary.675e877.0",
4
4
  "description": "Quenty's camera system for Roblox",
5
5
  "keywords": [
6
6
  "Roblox",
@@ -25,27 +25,27 @@
25
25
  "Quenty"
26
26
  ],
27
27
  "dependencies": {
28
- "@quenty/acceltween": "^2.5.3",
29
- "@quenty/baseobject": "^10.9.0",
30
- "@quenty/cframeutils": "^5.5.3",
31
- "@quenty/cubicspline": "^10.9.0",
32
- "@quenty/ducktype": "^5.9.0",
33
- "@quenty/inputobjectutils": "^4.19.0",
34
- "@quenty/loader": "^10.9.0",
35
- "@quenty/maid": "^3.5.0",
36
- "@quenty/math": "^2.7.3",
37
- "@quenty/qframe": "^10.11.0",
38
- "@quenty/rx": "^13.18.0",
39
- "@quenty/servicebag": "^11.13.0",
40
- "@quenty/spring": "^10.9.0",
41
- "@quenty/valueobject": "^13.18.0",
42
- "@quenty/vector3utils": "^10.9.0"
28
+ "@quenty/acceltween": "2.5.3",
29
+ "@quenty/baseobject": "10.9.0",
30
+ "@quenty/cframeutils": "5.5.3",
31
+ "@quenty/cubicspline": "10.9.0",
32
+ "@quenty/ducktype": "5.9.0",
33
+ "@quenty/inputobjectutils": "4.19.0",
34
+ "@quenty/loader": "10.9.0",
35
+ "@quenty/maid": "3.5.0",
36
+ "@quenty/math": "2.7.3",
37
+ "@quenty/qframe": "10.11.0",
38
+ "@quenty/rx": "13.18.0",
39
+ "@quenty/servicebag": "11.13.0",
40
+ "@quenty/spring": "10.9.0",
41
+ "@quenty/valueobject": "13.18.0",
42
+ "@quenty/vector3utils": "10.9.0"
43
43
  },
44
44
  "devDependencies": {
45
- "@quenty/camerastoryutils": "^10.11.0"
45
+ "@quenty/camerastoryutils": "10.11.0"
46
46
  },
47
47
  "publishConfig": {
48
48
  "access": "public"
49
49
  },
50
- "gitHead": "b37dbb03d406fe0bce6d4f9c2fd99f1be2e459e5"
50
+ "gitHead": "675e87759fbcf0f346c264580e679725819353e3"
51
51
  }
@@ -91,6 +91,10 @@ DefaultCamera.OverrideCameraState = DefaultCamera.SetRobloxCameraState
91
91
  ]=]
92
92
  function DefaultCamera.SetRobloxCFrame(self: DefaultCamera, cframe: CFrame)
93
93
  self._cameraState.CFrame = cframe
94
+
95
+ if self._lastCameraFrame then
96
+ self._lastCameraFrame.CFrame = cframe
97
+ end
94
98
  end
95
99
 
96
100
  --[=[
@@ -30,6 +30,7 @@ export type FadeBetweenCamera3 = typeof(setmetatable(
30
30
  Speed: number,
31
31
  Velocity: number,
32
32
  Target: number,
33
+ Epsilon: number?,
33
34
  },
34
35
  {} :: typeof({ __index = FadeBetweenCamera3 })
35
36
  )) & CameraEffectUtils.CameraEffect
@@ -73,7 +74,7 @@ function FadeBetweenCamera3:__newindex(index, value)
73
74
  self._spring.Target = value
74
75
  elseif index == "Velocity" then
75
76
  self._spring.Velocity = value
76
- elseif index == "CameraA" or index == "CameraB" then
77
+ elseif index == "CameraA" or index == "CameraB" or index == "Epsilon" then
77
78
  rawset(self, index, value)
78
79
  else
79
80
  error(string.format("%q is not a valid member of FadeBetweenCamera3", tostring(index)))
@@ -88,7 +89,7 @@ end
88
89
  ]=]
89
90
  function FadeBetweenCamera3:__index(index)
90
91
  if index == "CameraState" then
91
- local _, t = SpringUtils.animating(self._spring)
92
+ local _, t = SpringUtils.animating(self._spring, rawget(self, "Epsilon"))
92
93
  if t == 0 then
93
94
  return self.CameraStateA
94
95
  elseif t == 1 then
@@ -146,24 +147,26 @@ function FadeBetweenCamera3:__index(index)
146
147
  elseif index == "Damper" then
147
148
  return self._spring.Damper
148
149
  elseif index == "Value" then
149
- local _, t = SpringUtils.animating(self._spring)
150
+ local _, t = SpringUtils.animating(self._spring, rawget(self, "Epsilon"))
150
151
  return t
151
152
  elseif index == "Speed" then
152
153
  return self._spring.Speed
153
154
  elseif index == "Target" then
154
155
  return self._spring.Target
155
156
  elseif index == "Velocity" then
156
- local animating = SpringUtils.animating(self._spring)
157
+ local animating = SpringUtils.animating(self._spring, rawget(self, "Epsilon"))
157
158
  if animating then
158
159
  return self._spring.Velocity
159
160
  else
160
161
  return 0
161
162
  end
162
163
  elseif index == "HasReachedTarget" then
163
- local animating = SpringUtils.animating(self._spring)
164
+ local animating = SpringUtils.animating(self._spring, rawget(self, "Epsilon"))
164
165
  return not animating
165
166
  elseif index == "Spring" then
166
167
  return self._spring
168
+ elseif index == "Epsilon" then
169
+ return rawget(self, "Epsilon")
167
170
  elseif FadeBetweenCamera3[index] then
168
171
  return FadeBetweenCamera3[index]
169
172
  else
@@ -156,6 +156,10 @@ function CameraStateTweener.GetCameraBelow(self: CameraStateTweener): CameraEffe
156
156
  return self._cameraBelow
157
157
  end
158
158
 
159
+ function CameraStateTweener:SetEpsilon(epsilon: number?)
160
+ self._fadeBetween.Epsilon = epsilon
161
+ end
162
+
159
163
  --[=[
160
164
  Sets the percent visible target
161
165
  @param target number
@@ -0,0 +1,68 @@
1
+ --[=[
2
+ @class CameraSubjectUtils
3
+ ]=]
4
+
5
+ local CameraSubjectUtils = {}
6
+
7
+ local HEAD_OFFSET = Vector3.new(0, 1.5, 0)
8
+ local R15_HEAD_OFFSET = Vector3.new(0, 1.5, 0)
9
+ local R15_HEAD_OFFSET_NO_SCALING = Vector3.new(0, 2, 0)
10
+ local HUMANOID_ROOT_PART_SIZE = Vector3.new(2, 2, 1)
11
+
12
+ --[=[
13
+ Follows the same logic as Roblox's default camera
14
+ ]=]
15
+ function CameraSubjectUtils.getRobloxCameraSubjectCFrame(cameraSubject: Instance): CFrame?
16
+ if cameraSubject:IsA("Humanoid") then
17
+ local humanoid = cameraSubject
18
+ local humanoidIsDead = humanoid:GetState() == Enum.HumanoidStateType.Dead
19
+
20
+ local cameraOffset = humanoid.CameraOffset
21
+ local bodyPartToFollow: BasePart? = humanoid.RootPart
22
+
23
+ -- If the humanoid is dead, prefer their head part as a follow target, if it exists
24
+ if humanoidIsDead then
25
+ if humanoid.Parent and humanoid.Parent:IsA("Model") then
26
+ bodyPartToFollow = (humanoid.Parent:FindFirstChild("Head") :: BasePart) or bodyPartToFollow
27
+ end
28
+ end
29
+
30
+ if bodyPartToFollow and bodyPartToFollow:IsA("BasePart") then
31
+ local heightOffset
32
+ if humanoid.RigType == Enum.HumanoidRigType.R15 then
33
+ if humanoid.AutomaticScalingEnabled then
34
+ heightOffset = R15_HEAD_OFFSET
35
+
36
+ local rootPart = humanoid.RootPart
37
+ if bodyPartToFollow == rootPart then
38
+ local rootPartSizeOffset = (rootPart.Size.Y - HUMANOID_ROOT_PART_SIZE.Y) / 2
39
+ heightOffset = heightOffset + Vector3.new(0, rootPartSizeOffset, 0)
40
+ end
41
+ else
42
+ heightOffset = R15_HEAD_OFFSET_NO_SCALING
43
+ end
44
+ else
45
+ heightOffset = HEAD_OFFSET
46
+ end
47
+
48
+ if humanoidIsDead then
49
+ heightOffset = Vector3.zero
50
+ end
51
+
52
+ return bodyPartToFollow.CFrame * CFrame.new(heightOffset + cameraOffset)
53
+ end
54
+ elseif cameraSubject:IsA("BasePart") then
55
+ return cameraSubject.CFrame
56
+ elseif cameraSubject:IsA("Model") then
57
+ -- Model subjects are expected to have a PrimaryPart to determine orientation
58
+ if cameraSubject.PrimaryPart then
59
+ return (cameraSubject :: any):GetPrimaryPartCFrame()
60
+ else
61
+ return nil
62
+ end
63
+ end
64
+
65
+ return nil
66
+ end
67
+
68
+ return CameraSubjectUtils