roblox-opencode 1.0.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.
Files changed (248) hide show
  1. package/README.md +122 -0
  2. package/commands/setup-game.md +108 -0
  3. package/commands/sync-check.md +53 -0
  4. package/core/roblox-core.md +93 -0
  5. package/dist/server.js +167 -0
  6. package/package.json +35 -0
  7. package/skills/roblox-analytics/SKILL.md +277 -0
  8. package/skills/roblox-analytics/references/event-batcher.luau +75 -0
  9. package/skills/roblox-animation-vfx/SKILL.md +1325 -0
  10. package/skills/roblox-architecture/SKILL.md +863 -0
  11. package/skills/roblox-architecture/references/combat-systems.md +1381 -0
  12. package/skills/roblox-code-review/SKILL.md +687 -0
  13. package/skills/roblox-data/SKILL.md +889 -0
  14. package/skills/roblox-data/references/inventory-systems.md +1729 -0
  15. package/skills/roblox-debug/SKILL.md +99 -0
  16. package/skills/roblox-gui/SKILL.md +1103 -0
  17. package/skills/roblox-gui-fusion/SKILL.md +150 -0
  18. package/skills/roblox-gui-fusion/references/inventory.luau +427 -0
  19. package/skills/roblox-gui-fusion/references/settings-menu.luau +579 -0
  20. package/skills/roblox-gui-fusion/references/shop.luau +411 -0
  21. package/skills/roblox-luau-mastery/SKILL.md +1519 -0
  22. package/skills/roblox-monetization/SKILL.md +1084 -0
  23. package/skills/roblox-monetization/references/process-receipt.luau +131 -0
  24. package/skills/roblox-networking/SKILL.md +669 -0
  25. package/skills/roblox-networking/references/remote-validator.luau +193 -0
  26. package/skills/roblox-publish-checklist/SKILL.md +128 -0
  27. package/skills/roblox-runtime/SKILL.md +753 -0
  28. package/skills/roblox-sharp-edges/SKILL.md +295 -0
  29. package/skills/roblox-sync/SKILL.md +126 -0
  30. package/skills/roblox-testing/SKILL.md +943 -0
  31. package/skills/roblox-tooling/SKILL.md +150 -0
  32. package/vendor/LICENSES/ProfileStore-LICENSE +201 -0
  33. package/vendor/LICENSES/RbxUtil-LICENSE +7 -0
  34. package/vendor/LICENSES/promise-LICENSE +21 -0
  35. package/vendor/LICENSES/t-LICENSE +21 -0
  36. package/vendor/LICENSES/testez-LICENSE +201 -0
  37. package/vendor/README.md +84 -0
  38. package/vendor/fusion/Animation/ExternalTime.luau +84 -0
  39. package/vendor/fusion/Animation/Spring.luau +322 -0
  40. package/vendor/fusion/Animation/Stopwatch.luau +128 -0
  41. package/vendor/fusion/Animation/Tween.luau +187 -0
  42. package/vendor/fusion/Animation/getTweenDuration.luau +27 -0
  43. package/vendor/fusion/Animation/getTweenRatio.luau +47 -0
  44. package/vendor/fusion/Animation/lerpType.luau +164 -0
  45. package/vendor/fusion/Animation/packType.luau +100 -0
  46. package/vendor/fusion/Animation/springCoefficients.luau +80 -0
  47. package/vendor/fusion/Animation/unpackType.luau +103 -0
  48. package/vendor/fusion/Colour/Oklab.luau +70 -0
  49. package/vendor/fusion/Colour/sRGB.luau +55 -0
  50. package/vendor/fusion/External.luau +168 -0
  51. package/vendor/fusion/ExternalDebug.luau +70 -0
  52. package/vendor/fusion/Graph/Observer.luau +114 -0
  53. package/vendor/fusion/Graph/castToGraph.luau +29 -0
  54. package/vendor/fusion/Graph/change.luau +81 -0
  55. package/vendor/fusion/Graph/depend.luau +33 -0
  56. package/vendor/fusion/Graph/evaluate.luau +56 -0
  57. package/vendor/fusion/Instances/Attribute.luau +58 -0
  58. package/vendor/fusion/Instances/AttributeChange.luau +47 -0
  59. package/vendor/fusion/Instances/AttributeOut.luau +63 -0
  60. package/vendor/fusion/Instances/Child.luau +21 -0
  61. package/vendor/fusion/Instances/Children.luau +148 -0
  62. package/vendor/fusion/Instances/Hydrate.luau +33 -0
  63. package/vendor/fusion/Instances/New.luau +53 -0
  64. package/vendor/fusion/Instances/OnChange.luau +50 -0
  65. package/vendor/fusion/Instances/OnEvent.luau +54 -0
  66. package/vendor/fusion/Instances/Out.luau +69 -0
  67. package/vendor/fusion/Instances/applyInstanceProps.luau +149 -0
  68. package/vendor/fusion/Instances/defaultProps.luau +194 -0
  69. package/vendor/fusion/LICENSE +21 -0
  70. package/vendor/fusion/Logging/formatError.luau +49 -0
  71. package/vendor/fusion/Logging/messages.luau +52 -0
  72. package/vendor/fusion/Logging/parseError.luau +25 -0
  73. package/vendor/fusion/Memory/checkLifetime.luau +134 -0
  74. package/vendor/fusion/Memory/deriveScope.luau +24 -0
  75. package/vendor/fusion/Memory/deriveScopeImpl.luau +45 -0
  76. package/vendor/fusion/Memory/doCleanup.luau +79 -0
  77. package/vendor/fusion/Memory/innerScope.luau +34 -0
  78. package/vendor/fusion/Memory/legacyCleanup.luau +18 -0
  79. package/vendor/fusion/Memory/needsDestruction.luau +17 -0
  80. package/vendor/fusion/Memory/poisonScope.luau +34 -0
  81. package/vendor/fusion/Memory/scopePool.luau +55 -0
  82. package/vendor/fusion/Memory/scoped.luau +27 -0
  83. package/vendor/fusion/Memory/whichLivesLonger.luau +75 -0
  84. package/vendor/fusion/RobloxExternal.luau +98 -0
  85. package/vendor/fusion/State/Computed.luau +139 -0
  86. package/vendor/fusion/State/For/Disassembly.luau +211 -0
  87. package/vendor/fusion/State/For/ForTypes.luau +30 -0
  88. package/vendor/fusion/State/For/init.luau +110 -0
  89. package/vendor/fusion/State/ForKeys.luau +94 -0
  90. package/vendor/fusion/State/ForPairs.luau +97 -0
  91. package/vendor/fusion/State/ForValues.luau +94 -0
  92. package/vendor/fusion/State/Value.luau +88 -0
  93. package/vendor/fusion/State/castToState.luau +26 -0
  94. package/vendor/fusion/State/peek.luau +31 -0
  95. package/vendor/fusion/State/updateAll.luau +1 -0
  96. package/vendor/fusion/Types.luau +314 -0
  97. package/vendor/fusion/Utility/Contextual.luau +91 -0
  98. package/vendor/fusion/Utility/Safe.luau +23 -0
  99. package/vendor/fusion/Utility/isSimilar.luau +29 -0
  100. package/vendor/fusion/Utility/merge.luau +35 -0
  101. package/vendor/fusion/Utility/nameOf.luau +35 -0
  102. package/vendor/fusion/Utility/never.luau +14 -0
  103. package/vendor/fusion/Utility/nicknames.luau +11 -0
  104. package/vendor/fusion/Utility/xtypeof.luau +27 -0
  105. package/vendor/fusion/init.luau +82 -0
  106. package/vendor/profilestore/init.luau +2243 -0
  107. package/vendor/promise/init.luau +1982 -0
  108. package/vendor/rbxutil/buffer-util/Buffer.test.luau +25 -0
  109. package/vendor/rbxutil/buffer-util/BufferReader.luau +228 -0
  110. package/vendor/rbxutil/buffer-util/BufferWriter.luau +269 -0
  111. package/vendor/rbxutil/buffer-util/DataTypeBuffer.luau +223 -0
  112. package/vendor/rbxutil/buffer-util/Types.luau +60 -0
  113. package/vendor/rbxutil/buffer-util/index.d.ts +153 -0
  114. package/vendor/rbxutil/buffer-util/init.luau +41 -0
  115. package/vendor/rbxutil/buffer-util/package.json +16 -0
  116. package/vendor/rbxutil/buffer-util/wally.toml +9 -0
  117. package/vendor/rbxutil/comm/Client/ClientComm.luau +232 -0
  118. package/vendor/rbxutil/comm/Client/ClientRemoteProperty.luau +156 -0
  119. package/vendor/rbxutil/comm/Client/ClientRemoteSignal.luau +109 -0
  120. package/vendor/rbxutil/comm/Client/init.luau +135 -0
  121. package/vendor/rbxutil/comm/Server/RemoteProperty.luau +295 -0
  122. package/vendor/rbxutil/comm/Server/RemoteSignal.luau +211 -0
  123. package/vendor/rbxutil/comm/Server/ServerComm.luau +211 -0
  124. package/vendor/rbxutil/comm/Server/init.luau +140 -0
  125. package/vendor/rbxutil/comm/Types.luau +18 -0
  126. package/vendor/rbxutil/comm/Util.luau +27 -0
  127. package/vendor/rbxutil/comm/init.luau +35 -0
  128. package/vendor/rbxutil/comm/wally.toml +13 -0
  129. package/vendor/rbxutil/component/init.luau +759 -0
  130. package/vendor/rbxutil/component/init.test.luau +311 -0
  131. package/vendor/rbxutil/component/wally.toml +14 -0
  132. package/vendor/rbxutil/concur/init.luau +542 -0
  133. package/vendor/rbxutil/concur/init.test.luau +364 -0
  134. package/vendor/rbxutil/concur/wally.toml +8 -0
  135. package/vendor/rbxutil/enum-list/init.luau +101 -0
  136. package/vendor/rbxutil/enum-list/init.test.luau +91 -0
  137. package/vendor/rbxutil/enum-list/wally.toml +8 -0
  138. package/vendor/rbxutil/find/index.d.ts +20 -0
  139. package/vendor/rbxutil/find/init.luau +44 -0
  140. package/vendor/rbxutil/find/package.json +17 -0
  141. package/vendor/rbxutil/find/wally.toml +8 -0
  142. package/vendor/rbxutil/input/Gamepad.luau +559 -0
  143. package/vendor/rbxutil/input/Keyboard.luau +124 -0
  144. package/vendor/rbxutil/input/Mouse.luau +278 -0
  145. package/vendor/rbxutil/input/PreferredInput.luau +91 -0
  146. package/vendor/rbxutil/input/Touch.luau +120 -0
  147. package/vendor/rbxutil/input/init.luau +33 -0
  148. package/vendor/rbxutil/input/wally.toml +12 -0
  149. package/vendor/rbxutil/loader/index.d.ts +15 -0
  150. package/vendor/rbxutil/loader/init.luau +137 -0
  151. package/vendor/rbxutil/loader/wally.toml +8 -0
  152. package/vendor/rbxutil/log/index.d.ts +38 -0
  153. package/vendor/rbxutil/log/init.luau +746 -0
  154. package/vendor/rbxutil/log/wally.toml +8 -0
  155. package/vendor/rbxutil/net/init.luau +190 -0
  156. package/vendor/rbxutil/net/wally.toml +8 -0
  157. package/vendor/rbxutil/option/index.d.ts +44 -0
  158. package/vendor/rbxutil/option/init.luau +489 -0
  159. package/vendor/rbxutil/option/init.test.luau +342 -0
  160. package/vendor/rbxutil/option/wally.toml +8 -0
  161. package/vendor/rbxutil/pid/index.d.ts +53 -0
  162. package/vendor/rbxutil/pid/init.luau +195 -0
  163. package/vendor/rbxutil/pid/package.json +16 -0
  164. package/vendor/rbxutil/pid/wally.toml +9 -0
  165. package/vendor/rbxutil/quaternion/index.d.ts +117 -0
  166. package/vendor/rbxutil/quaternion/init.luau +570 -0
  167. package/vendor/rbxutil/quaternion/package.json +16 -0
  168. package/vendor/rbxutil/quaternion/wally.toml +9 -0
  169. package/vendor/rbxutil/query/index.d.ts +43 -0
  170. package/vendor/rbxutil/query/init.luau +117 -0
  171. package/vendor/rbxutil/query/package.json +18 -0
  172. package/vendor/rbxutil/query/wally.toml +9 -0
  173. package/vendor/rbxutil/sequent/index.d.ts +28 -0
  174. package/vendor/rbxutil/sequent/init.luau +340 -0
  175. package/vendor/rbxutil/sequent/package.json +16 -0
  176. package/vendor/rbxutil/sequent/wally.toml +9 -0
  177. package/vendor/rbxutil/ser/init.luau +175 -0
  178. package/vendor/rbxutil/ser/init.test.luau +50 -0
  179. package/vendor/rbxutil/ser/wally.toml +11 -0
  180. package/vendor/rbxutil/shake/index.d.ts +36 -0
  181. package/vendor/rbxutil/shake/init.luau +532 -0
  182. package/vendor/rbxutil/shake/init.test.luau +267 -0
  183. package/vendor/rbxutil/shake/package.json +16 -0
  184. package/vendor/rbxutil/shake/wally.toml +9 -0
  185. package/vendor/rbxutil/signal/index.d.ts +100 -0
  186. package/vendor/rbxutil/signal/init.luau +432 -0
  187. package/vendor/rbxutil/signal/init.test.luau +190 -0
  188. package/vendor/rbxutil/signal/package.json +17 -0
  189. package/vendor/rbxutil/signal/wally.toml +9 -0
  190. package/vendor/rbxutil/silo/TableWatcher.luau +65 -0
  191. package/vendor/rbxutil/silo/Util.luau +55 -0
  192. package/vendor/rbxutil/silo/init.luau +338 -0
  193. package/vendor/rbxutil/silo/init.test.luau +215 -0
  194. package/vendor/rbxutil/silo/wally.toml +8 -0
  195. package/vendor/rbxutil/spring/index.d.ts +40 -0
  196. package/vendor/rbxutil/spring/init.luau +97 -0
  197. package/vendor/rbxutil/spring/package.json +17 -0
  198. package/vendor/rbxutil/spring/wally.toml +8 -0
  199. package/vendor/rbxutil/stream/index.d.ts +88 -0
  200. package/vendor/rbxutil/stream/init.luau +597 -0
  201. package/vendor/rbxutil/stream/package.json +18 -0
  202. package/vendor/rbxutil/stream/wally.toml +9 -0
  203. package/vendor/rbxutil/streamable/Streamable.luau +202 -0
  204. package/vendor/rbxutil/streamable/StreamableUtil.luau +80 -0
  205. package/vendor/rbxutil/streamable/init.luau +8 -0
  206. package/vendor/rbxutil/streamable/wally.toml +12 -0
  207. package/vendor/rbxutil/symbol/init.luau +56 -0
  208. package/vendor/rbxutil/symbol/init.test.luau +37 -0
  209. package/vendor/rbxutil/symbol/wally.toml +8 -0
  210. package/vendor/rbxutil/table-util/init.luau +938 -0
  211. package/vendor/rbxutil/table-util/init.test.luau +439 -0
  212. package/vendor/rbxutil/table-util/wally.toml +8 -0
  213. package/vendor/rbxutil/task-queue/index.d.ts +27 -0
  214. package/vendor/rbxutil/task-queue/init.luau +97 -0
  215. package/vendor/rbxutil/task-queue/wally.toml +8 -0
  216. package/vendor/rbxutil/timer/index.d.ts +81 -0
  217. package/vendor/rbxutil/timer/init.luau +249 -0
  218. package/vendor/rbxutil/timer/init.test.luau +73 -0
  219. package/vendor/rbxutil/timer/wally.toml +11 -0
  220. package/vendor/rbxutil/tree/index.d.ts +15 -0
  221. package/vendor/rbxutil/tree/init.luau +137 -0
  222. package/vendor/rbxutil/tree/wally.toml +8 -0
  223. package/vendor/rbxutil/trove/index.d.ts +46 -0
  224. package/vendor/rbxutil/trove/init.luau +787 -0
  225. package/vendor/rbxutil/trove/init.test.luau +203 -0
  226. package/vendor/rbxutil/trove/wally.toml +8 -0
  227. package/vendor/rbxutil/typed-remote/init.luau +196 -0
  228. package/vendor/rbxutil/typed-remote/wally.toml +8 -0
  229. package/vendor/rbxutil/wait-for/index.d.ts +17 -0
  230. package/vendor/rbxutil/wait-for/init.luau +257 -0
  231. package/vendor/rbxutil/wait-for/init.test.luau +182 -0
  232. package/vendor/rbxutil/wait-for/wally.toml +11 -0
  233. package/vendor/t/t.lua +1350 -0
  234. package/vendor/testez/Context.lua +26 -0
  235. package/vendor/testez/Expectation.lua +311 -0
  236. package/vendor/testez/ExpectationContext.lua +38 -0
  237. package/vendor/testez/LifecycleHooks.lua +89 -0
  238. package/vendor/testez/Reporters/TeamCityReporter.lua +102 -0
  239. package/vendor/testez/Reporters/TextReporter.lua +106 -0
  240. package/vendor/testez/Reporters/TextReporterQuiet.lua +97 -0
  241. package/vendor/testez/TestBootstrap.lua +147 -0
  242. package/vendor/testez/TestEnum.lua +28 -0
  243. package/vendor/testez/TestPlan.lua +304 -0
  244. package/vendor/testez/TestPlanner.lua +40 -0
  245. package/vendor/testez/TestResults.lua +112 -0
  246. package/vendor/testez/TestRunner.lua +188 -0
  247. package/vendor/testez/TestSession.lua +243 -0
  248. package/vendor/testez/init.lua +40 -0
@@ -0,0 +1,532 @@
1
+ --!native
2
+
3
+ local RunService = game:GetService("RunService")
4
+
5
+ --[=[
6
+ @within Shake
7
+ @type UpdateCallbackFn () -> (position: Vector3, rotation: Vector3, completed: boolean)
8
+ ]=]
9
+ type UpdateCallbackFn = () -> (Vector3, Vector3, boolean)
10
+
11
+ export type Shake = {
12
+ Amplitude: number,
13
+ Frequency: number,
14
+ FadeInTime: number,
15
+ FadeOutTime: number,
16
+ SustainTime: number,
17
+ Sustain: boolean,
18
+ PositionInfluence: Vector3,
19
+ RotationInfluence: Vector3,
20
+ TimeFunction: () -> number,
21
+
22
+ Start: (self: Shake) -> (),
23
+ Stop: (self: Shake) -> (),
24
+ IsShaking: (self: Shake) -> boolean,
25
+ StopSustain: (self: Shake) -> (),
26
+ Update: (self: Shake) -> (Vector3, Vector3, boolean),
27
+ OnSignal: (
28
+ self: Shake,
29
+ signal: RBXScriptSignal,
30
+ callback: (Vector3, Vector3, boolean) -> ()
31
+ ) -> RBXScriptConnection,
32
+ BindToRenderStep: (self: Shake, name: string, priority: number, callback: (Vector3, Vector3, boolean) -> ()) -> (),
33
+ Clone: (self: Shake) -> Shake,
34
+ Destroy: (self: Shake) -> (),
35
+ }
36
+
37
+ local rng = Random.new()
38
+ local renderId = 0
39
+
40
+ --[=[
41
+ @class Shake
42
+ Create realistic shake effects, such as camera or object shakes.
43
+
44
+ Creating a shake is very simple with this module. For every shake,
45
+ simply create a shake instance by calling `Shake.new()`. From
46
+ there, configure the shake however desired. Once configured,
47
+ call `shake:Start()` and then bind a function to it with either
48
+ `shake:OnSignal(...)` or `shake:BindToRenderStep(...)`.
49
+
50
+ The shake will output its values to the connected function, and then
51
+ automatically stop and clean up its connections once completed.
52
+
53
+ Shake instances can be reused indefinitely. However, only one shake
54
+ operation per instance can be running. If more than one is needed
55
+ of the same configuration, simply call `shake:Clone()` to duplicate
56
+ it.
57
+
58
+ Example of a simple camera shake:
59
+ ```lua
60
+ local priority = Enum.RenderPriority.Last.Value
61
+
62
+ local shake = Shake.new()
63
+ shake.FadeInTime = 0
64
+ shake.Frequency = 0.1
65
+ shake.Amplitude = 5
66
+ shake.RotationInfluence = Vector3.new(0.1, 0.1, 0.1)
67
+
68
+ shake:Start()
69
+ shake:BindToRenderStep(Shake.NextRenderName(), priority, function(pos, rot, isDone)
70
+ camera.CFrame *= CFrame.new(pos) * CFrame.Angles(rot.X, rot.Y, rot.Z)
71
+ end)
72
+ ```
73
+
74
+ Shakes will automatically stop once the shake has been completed. Shakes can
75
+ also be used continuously if the `Sustain` property is set to `true`.
76
+
77
+ ## Fixing drift
78
+
79
+ If you are not controlling the initial CFrame of the camera (i.e. using Roblox's camera scripts),
80
+ then you might run into odd behavior with the above example. This is because Roblox's camera
81
+ scripts are influenced by the current CFrame value of the camera. Thus, the shake effect causes
82
+ odd side-effects, especially noticeable at higher FPS.
83
+
84
+ The solution is to simply store the camera's CFrame before applying the shake CFrame, and then
85
+ reapplying this stored CFrame value after rendering is complete (e.g. on Heartbeat).
86
+
87
+ ```lua
88
+ local camCf: CFrame
89
+
90
+ shake:BindToRenderStep(Shake.NextRenderName(), priority, function(pos, rot, isDone)
91
+ -- Store the CFrame value that was set from Roblox's camera scripts:
92
+ camCf = camera.CFrame
93
+
94
+ camera.CFrame *= CFrame.new(pos) * CFrame.Angles(rot.X, rot.Y, rot.Z)
95
+ end)
96
+
97
+ RunService.Heartbeat:Connect(function()
98
+ -- Reapply the camera script CFrame before they run again.
99
+ -- Heartbeat runs AFTER Roblox has rendered, so it will not affect the camera this frame.
100
+ camera.CFrame = camCf
101
+ end)
102
+ ```
103
+
104
+ ## Configuration
105
+
106
+ Here are some more helpful configuration examples:
107
+
108
+ ```lua
109
+ local shake = Shake.new()
110
+
111
+ -- The magnitude of the shake. Larger numbers means larger shakes.
112
+ shake.Amplitude = 5
113
+
114
+ -- The speed of the shake. Smaller frequencies mean faster shakes.
115
+ shake.Frequency = 0.1
116
+
117
+ -- Fade-in time before max amplitude shake. Set to 0 for immediate shake.
118
+ shake.FadeInTime = 0
119
+
120
+ -- Fade-out time. Set to 0 for immediate cutoff.
121
+ shake.FadeOutTime = 0
122
+
123
+ -- How long the shake sustains full amplitude before fading out
124
+ shake.SustainTime = 1
125
+
126
+ -- Set to true to never end the shake. Call shake:StopSustain() to start the fade-out.
127
+ shake.Sustain = true
128
+
129
+ -- Multiplies against the shake vector to control the final amplitude of the position.
130
+ -- Can be seen internally as: position = shakeVector * fadeInOut * positionInfluence
131
+ shake.PositionInfluence = Vector3.one
132
+
133
+ -- Multiplies against the shake vector to control the final amplitude of the rotation.
134
+ -- Can be seen internally as: position = shakeVector * fadeInOut * rotationInfluence
135
+ shake.RotationInfluence = Vector3.new(0.1, 0.1, 0.1)
136
+
137
+ ```
138
+ ]=]
139
+ local Shake = {}
140
+ Shake.__index = Shake
141
+
142
+ --[=[
143
+ @within Shake
144
+ @prop Amplitude number
145
+ Amplitude of the overall shake. For instance, an amplitude of `3` would mean the
146
+ peak magnitude for the outputted shake vectors would be about `3`.
147
+
148
+ Defaults to `1`.
149
+ ]=]
150
+
151
+ --[=[
152
+ @within Shake
153
+ @prop Frequency number
154
+ Frequency of the overall shake. This changes how slow or fast the
155
+ shake occurs.
156
+
157
+ Defaults to `1`.
158
+ ]=]
159
+
160
+ --[=[
161
+ @within Shake
162
+ @prop FadeInTime number
163
+ How long it takes for the shake to fade in, measured in seconds.
164
+
165
+ Defaults to `1`.
166
+ ]=]
167
+
168
+ --[=[
169
+ @within Shake
170
+ @prop FadeOutTime number
171
+ How long it takes for the shake to fade out, measured in seconds.
172
+
173
+ Defaults to `1`.
174
+ ]=]
175
+
176
+ --[=[
177
+ @within Shake
178
+ @prop SustainTime number
179
+ How long it takes for the shake sustains itself after fading in and
180
+ before fading out.
181
+
182
+ To sustain a shake indefinitely, set `Sustain`
183
+ to `true`, and call the `StopSustain()` method to stop the sustain
184
+ and fade out the shake effect.
185
+
186
+ Defaults to `0`.
187
+ ]=]
188
+
189
+ --[=[
190
+ @within Shake
191
+ @prop Sustain boolean
192
+ If `true`, the shake will sustain itself indefinitely once it fades
193
+ in. If `StopSustain()` is called, the sustain will end and the shake
194
+ will fade out based on the `FadeOutTime`.
195
+
196
+ Defaults to `false`.
197
+ ]=]
198
+
199
+ --[=[
200
+ @within Shake
201
+ @prop PositionInfluence Vector3
202
+ This is similar to `Amplitude` but multiplies against each axis
203
+ of the resultant shake vector, and only affects the position vector.
204
+
205
+ Defaults to `Vector3.one`.
206
+ ]=]
207
+
208
+ --[=[
209
+ @within Shake
210
+ @prop RotationInfluence Vector3
211
+ This is similar to `Amplitude` but multiplies against each axis
212
+ of the resultant shake vector, and only affects the rotation vector.
213
+
214
+ Defaults to `Vector3.one`.
215
+ ]=]
216
+
217
+ --[=[
218
+ @within Shake
219
+ @prop TimeFunction () -> number
220
+ The function used to get the current time. This defaults to
221
+ `time` during runtime, and `os.clock` otherwise. Usually this
222
+ will not need to be set, but it can be optionally configured
223
+ if desired.
224
+ ]=]
225
+
226
+ --[=[
227
+ @return Shake
228
+ Construct a new Shake instance.
229
+ ]=]
230
+ function Shake.new(): Shake
231
+ local self = setmetatable({}, Shake)
232
+
233
+ self.Amplitude = 1
234
+ self.Frequency = 1
235
+ self.FadeInTime = 1
236
+ self.FadeOutTime = 1
237
+ self.SustainTime = 0
238
+ self.Sustain = false
239
+ self.PositionInfluence = Vector3.one
240
+ self.RotationInfluence = Vector3.one
241
+ self.TimeFunction = if RunService:IsRunning() then time else os.clock
242
+
243
+ self._timeOffset = rng:NextNumber(-1e6, 1e6)
244
+ self._startTime = 0
245
+ self._running = false
246
+ self._signalConnections = {}
247
+ self._renderBindings = {}
248
+
249
+ return self
250
+ end
251
+
252
+ --[=[
253
+ Apply an inverse square intensity multiplier to the given vector based on the
254
+ distance away from some source. This can be used to simulate shake intensity
255
+ based on the distance the shake is occurring from some source.
256
+
257
+ For instance, if the shake is caused by an explosion in the game, the shake
258
+ can be calculated as such:
259
+
260
+ ```lua
261
+ local function Explosion(positionOfExplosion: Vector3)
262
+
263
+ local cam = workspace.CurrentCamera
264
+ local renderPriority = Enum.RenderPriority.Last.Value
265
+
266
+ local shake = Shake.new()
267
+ -- Set shake properties here
268
+
269
+ local function ExplosionShake(pos: Vector3, rot: Vector3)
270
+ local distance = (cam.CFrame.Position - positionOfExplosion).Magnitude
271
+ pos = Shake.InverseSquare(pos, distance)
272
+ rot = Shake.InverseSquare(rot, distance)
273
+ cam.CFrame *= CFrame.new(pos) * CFrame.Angles(rot.X, rot.Y, rot.Z)
274
+ end
275
+
276
+ shake:BindToRenderStep("ExplosionShake", renderPriority, ExplosionShake)
277
+
278
+ end
279
+ ```
280
+ ]=]
281
+ function Shake.InverseSquare(shake: Vector3, distance: number): Vector3
282
+ if distance < 1 then
283
+ distance = 1
284
+ end
285
+ local intensity = 1 / (distance * distance)
286
+ return shake * intensity
287
+ end
288
+
289
+ --[=[
290
+ Returns a unique render name for every call, which can
291
+ be used with the `BindToRenderStep` method optionally.
292
+
293
+ ```lua
294
+ shake:BindToRenderStep(Shake.NextRenderName(), ...)
295
+ ```
296
+ ]=]
297
+ function Shake.NextRenderName(): string
298
+ renderId += 1
299
+ return ("__shake_%.4i__"):format(renderId)
300
+ end
301
+
302
+ --[=[
303
+ Start the shake effect.
304
+
305
+ :::note
306
+ This **must** be called before calling `Update`. As such, it should also be
307
+ called once before or after calling `OnSignal` or `BindToRenderStep` methods.
308
+ :::
309
+ ]=]
310
+ function Shake:Start()
311
+ self._startTime = self.TimeFunction()
312
+ self._running = true
313
+ end
314
+
315
+ --[=[
316
+ Stops the shake effect. If using `OnSignal` or `BindToRenderStep`, those bound
317
+ functions will be disconnected/unbound.
318
+
319
+ `Stop` is automatically called when the shake effect is completed _or_ when the
320
+ `Destroy` method is called.
321
+ ]=]
322
+ function Shake:Stop()
323
+ self._running = false
324
+
325
+ for _, name in self._renderBindings do
326
+ RunService:UnbindFromRenderStep(name)
327
+ end
328
+ table.clear(self._renderBindings)
329
+
330
+ for _, conn in self._signalConnections do
331
+ conn:Disconnect()
332
+ end
333
+ table.clear(self._signalConnections)
334
+ end
335
+
336
+ --[=[
337
+ Returns `true` if the shake instance is currently running,
338
+ otherwise returns `false`.
339
+ ]=]
340
+ function Shake:IsShaking(): boolean
341
+ return self._running
342
+ end
343
+
344
+ --[=[
345
+ Schedules a sustained shake to stop. This works by setting the
346
+ `Sustain` field to `false` and letting the shake effect fade out
347
+ based on the `FadeOutTime` field.
348
+ ]=]
349
+ function Shake:StopSustain()
350
+ local now = self.TimeFunction()
351
+ self.Sustain = false
352
+ self.SustainTime = (now - self._startTime) - self.FadeInTime
353
+ end
354
+
355
+ --[=[
356
+ Calculates the current shake vector. This should be continuously
357
+ called inside a loop, such as `RunService.Heartbeat`. Alternatively,
358
+ `OnSignal` or `BindToRenderStep` can be used to automatically call
359
+ this function.
360
+
361
+ Returns a tuple of three values:
362
+ 1. `position: Vector3` - Position shake offset
363
+ 2. `rotation: Vector3` - Rotation shake offset
364
+ 3. `completed: boolean` - Flag indicating if the shake is finished
365
+
366
+ ```lua
367
+ local hb
368
+ hb = RunService.Heartbeat:Connect(function()
369
+ local offsetPosition, offsetRotation, isDone = shake:Update()
370
+ if isDone then
371
+ hb:Disconnect()
372
+ end
373
+ -- Use `offsetPosition` and `offsetRotation` here
374
+ end)
375
+ ```
376
+ ]=]
377
+ function Shake:Update(): (Vector3, Vector3, boolean)
378
+ local done = false
379
+
380
+ local now = self.TimeFunction()
381
+ local dur = now - self._startTime
382
+
383
+ local noiseInput = ((now + self._timeOffset) / self.Frequency) % 10000
384
+
385
+ local multiplierFadeIn = 1
386
+ local multiplierFadeOut = 1
387
+ if dur < self.FadeInTime then
388
+ -- Fade in
389
+ multiplierFadeIn = dur / self.FadeInTime
390
+ end
391
+ if not self.Sustain and dur > self.FadeInTime + self.SustainTime then
392
+ if self.FadeOutTime == 0 then
393
+ done = true
394
+ else
395
+ -- Fade out
396
+ multiplierFadeOut = 1 - (dur - self.FadeInTime - self.SustainTime) / self.FadeOutTime
397
+ if not self.Sustain and dur >= self.FadeInTime + self.SustainTime + self.FadeOutTime then
398
+ done = true
399
+ end
400
+ end
401
+ end
402
+
403
+ local offset = Vector3.new(
404
+ math.noise(noiseInput, 0) / 2,
405
+ math.noise(0, noiseInput) / 2,
406
+ math.noise(noiseInput, noiseInput) / 2
407
+ ) * self.Amplitude * math.min(multiplierFadeIn, multiplierFadeOut)
408
+
409
+ if done then
410
+ self:Stop()
411
+ end
412
+
413
+ return self.PositionInfluence * offset, self.RotationInfluence * offset, done
414
+ end
415
+
416
+ --[=[
417
+ @param signal Signal | RBXScriptSignal
418
+ @param callbackFn UpdateCallbackFn
419
+ @return Connection | RBXScriptConnection
420
+
421
+ Bind the `Update` method to a signal. For instance, this can be used
422
+ to connect to `RunService.Heartbeat`.
423
+
424
+ All connections are cleaned up when the shake instance is stopped
425
+ or destroyed.
426
+
427
+ ```lua
428
+ local function SomeShake(pos: Vector3, rot: Vector3, completed: boolean)
429
+ -- Shake
430
+ end
431
+
432
+ shake:OnSignal(RunService.Heartbeat, SomeShake)
433
+ ```
434
+ ]=]
435
+ function Shake:OnSignal(signal, callbackFn: UpdateCallbackFn)
436
+ local conn = signal:Connect(function()
437
+ callbackFn(self:Update())
438
+ end)
439
+
440
+ table.insert(self._signalConnections, conn)
441
+
442
+ return conn
443
+ end
444
+
445
+ --[=[
446
+ @param name string -- Name passed to `RunService:BindToRenderStep`
447
+ @param priority number -- Priority passed to `RunService:BindToRenderStep`
448
+ @param callbackFn UpdateCallbackFn
449
+
450
+ Bind the `Update` method to RenderStep.
451
+
452
+ All bound functions are cleaned up when the shake instance is stopped
453
+ or destroyed.
454
+
455
+ ```lua
456
+ local renderPriority = Enum.RenderPriority.Camera.Value
457
+
458
+ local function SomeShake(pos: Vector3, rot: Vector3, completed: boolean)
459
+ -- Shake
460
+ end
461
+
462
+ shake:BindToRenderStep("SomeShake", renderPriority, SomeShake)
463
+ ```
464
+ ]=]
465
+ function Shake:BindToRenderStep(name: string, priority: number, callbackFn: UpdateCallbackFn)
466
+ RunService:BindToRenderStep(name, priority, function()
467
+ callbackFn(self:Update())
468
+ end)
469
+
470
+ table.insert(self._renderBindings, name)
471
+ end
472
+
473
+ --[=[
474
+ @return Shake
475
+ Creates a new shake with identical properties as
476
+ this one. This does _not_ clone over playing state,
477
+ and thus the cloned instance will be in a stopped
478
+ state.
479
+
480
+ A use-case for using `Clone` would be to create a module
481
+ with a list of shake presets. These presets can be cloned
482
+ when desired for use. For instance, there might be presets
483
+ for explosions, recoil, or earthquakes.
484
+
485
+ ```lua
486
+ --------------------------------------
487
+ -- Example preset module
488
+ local ShakePresets = {}
489
+
490
+ local explosion = Shake.new()
491
+ -- Configure `explosion` shake here
492
+ ShakePresets.Explosion = explosion
493
+
494
+ return ShakePresets
495
+ --------------------------------------
496
+
497
+ -- Use the module:
498
+ local ShakePresets = require(somewhere.ShakePresets)
499
+ local explosionShake = ShakePresets.Explosion:Clone()
500
+ ```
501
+ ]=]
502
+ function Shake:Clone()
503
+ local shake = Shake.new()
504
+ local cloneFields = {
505
+ "Amplitude",
506
+ "Frequency",
507
+ "FadeInTime",
508
+ "FadeOutTime",
509
+ "SustainTime",
510
+ "Sustain",
511
+ "PositionInfluence",
512
+ "RotationInfluence",
513
+ "TimeFunction",
514
+ }
515
+ for _, field in cloneFields do
516
+ shake[field] = self[field]
517
+ end
518
+ return shake
519
+ end
520
+
521
+ --[=[
522
+ Alias for `Stop()`.
523
+ ]=]
524
+ function Shake:Destroy()
525
+ self:Stop()
526
+ end
527
+
528
+ return {
529
+ new = Shake.new,
530
+ InverseSquare = Shake.InverseSquare,
531
+ NextRenderName = Shake.NextRenderName,
532
+ }