@rbxts/vfx-forge 2.2.2-ts.1
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/LICENSE +82 -0
- package/README.md +39 -0
- package/out/forge-vfx/effects/beam.luau +312 -0
- package/out/forge-vfx/effects/bezier.luau +392 -0
- package/out/forge-vfx/effects/camera_shake.luau +200 -0
- package/out/forge-vfx/effects/lightning.luau +1183 -0
- package/out/forge-vfx/effects/mesh.luau +466 -0
- package/out/forge-vfx/effects/particle.luau +64 -0
- package/out/forge-vfx/effects/randomizer.luau +110 -0
- package/out/forge-vfx/effects/screen.luau +61 -0
- package/out/forge-vfx/effects/shockwave_debris.luau +277 -0
- package/out/forge-vfx/effects/shockwave_line.luau +356 -0
- package/out/forge-vfx/effects/shockwave_ring.luau +252 -0
- package/out/forge-vfx/effects/sound.luau +311 -0
- package/out/forge-vfx/effects/spin.luau +88 -0
- package/out/forge-vfx/effects/tweener.luau +122 -0
- package/out/forge-vfx/emitters.luau +387 -0
- package/out/forge-vfx/index.d.ts +356 -0
- package/out/forge-vfx/init.luau +279 -0
- package/out/forge-vfx/mod/attributes.luau +227 -0
- package/out/forge-vfx/mod/color/Oklab.luau +93 -0
- package/out/forge-vfx/mod/color/sRGB.luau +71 -0
- package/out/forge-vfx/mod/common/bezier.luau +372 -0
- package/out/forge-vfx/mod/common/flipbook.luau +102 -0
- package/out/forge-vfx/mod/lerp.luau +210 -0
- package/out/forge-vfx/mod/logger.luau +20 -0
- package/out/forge-vfx/mod/shape.luau +207 -0
- package/out/forge-vfx/mod/tween.luau +161 -0
- package/out/forge-vfx/mod/utility.luau +707 -0
- package/out/forge-vfx/obj/Bezier.luau +268 -0
- package/out/forge-vfx/obj/ObjectCache.luau +289 -0
- package/out/forge-vfx/services/caches.luau +62 -0
- package/out/forge-vfx/services/effects.luau +234 -0
- package/out/forge-vfx/services/enabled_effects.luau +120 -0
- package/out/forge-vfx/services/texture_loader.luau +174 -0
- package/out/forge-vfx/types.luau +43 -0
- package/out/index.d.ts +3 -0
- package/out/init.luau +5 -0
- package/out/shake.d.ts +2 -0
- package/out/shake.luau +6 -0
- package/out/tsconfig.tsbuildinfo +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
--!native
|
|
2
|
+
--!optimize 2
|
|
3
|
+
local utility = require(script.Parent.utility)
|
|
4
|
+
|
|
5
|
+
local shape = {}
|
|
6
|
+
|
|
7
|
+
function shape.getSurfaceCFrame(cf: CFrame, n: Vector3, pos: Vector3)
|
|
8
|
+
local up = math.abs(n:Dot(Vector3.yAxis)) > 0.99 and Vector3.zAxis or Vector3.yAxis
|
|
9
|
+
local rot = CFrame.lookAt(Vector3.zero, n, up)
|
|
10
|
+
return cf * CFrame.new(pos) * rot
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
function shape.getPointWithinBox(seed: number, cframe: CFrame, size: Vector3, normal: Enum.NormalId)
|
|
14
|
+
debug.profilebegin("getPointWithinBox")
|
|
15
|
+
|
|
16
|
+
local rng = Random.new(seed)
|
|
17
|
+
|
|
18
|
+
local half = size / 2
|
|
19
|
+
|
|
20
|
+
-- stylua: ignore
|
|
21
|
+
local pos = Vector3.new(
|
|
22
|
+
rng:NextNumber(-1, 1),
|
|
23
|
+
rng:NextNumber(-1, 1),
|
|
24
|
+
rng:NextNumber(-1, 1)
|
|
25
|
+
) * half
|
|
26
|
+
|
|
27
|
+
local cf = shape.getSurfaceCFrame(cframe, Vector3.FromNormalId(normal), pos)
|
|
28
|
+
|
|
29
|
+
debug.profileend()
|
|
30
|
+
|
|
31
|
+
return cf
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
function shape.getPointOnBox(seed: number, cframe: CFrame, size: Vector3, normal: Enum.NormalId)
|
|
35
|
+
debug.profilebegin("getPointOnBox")
|
|
36
|
+
|
|
37
|
+
local rng = Random.new(seed)
|
|
38
|
+
|
|
39
|
+
local n = Vector3.FromNormalId(normal)
|
|
40
|
+
|
|
41
|
+
local half = size / 2
|
|
42
|
+
local axes = Vector3.one - n:Abs()
|
|
43
|
+
|
|
44
|
+
-- stylua: ignore
|
|
45
|
+
local s = Vector3.new(
|
|
46
|
+
rng:NextNumber(-1, 1),
|
|
47
|
+
rng:NextNumber(-1, 1),
|
|
48
|
+
rng:NextNumber(-1, 1)
|
|
49
|
+
) * half * axes
|
|
50
|
+
|
|
51
|
+
local cf = shape.getSurfaceCFrame(cframe, n, s + n * half)
|
|
52
|
+
|
|
53
|
+
debug.profileend()
|
|
54
|
+
|
|
55
|
+
return cf
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
function shape.getPointWithinCylinder(
|
|
59
|
+
seed: number,
|
|
60
|
+
min_radius: number,
|
|
61
|
+
partial: number,
|
|
62
|
+
cframe: CFrame,
|
|
63
|
+
size: Vector3,
|
|
64
|
+
normal: Enum.NormalId
|
|
65
|
+
)
|
|
66
|
+
debug.profilebegin("getPointWithinCylinder")
|
|
67
|
+
|
|
68
|
+
local rng = Random.new(seed)
|
|
69
|
+
|
|
70
|
+
local r = math.sqrt(rng:NextNumber(min_radius, 1))
|
|
71
|
+
local theta = rng:NextNumber(0, 2 * math.pi)
|
|
72
|
+
|
|
73
|
+
if normal == Enum.NormalId.Left or normal == Enum.NormalId.Right then
|
|
74
|
+
cframe *= CFrame.fromOrientation(0, math.pi / 2 * (normal == Enum.NormalId.Right and -1 or 1), 0)
|
|
75
|
+
size = Vector3.new(size.Z, size.Y, size.X)
|
|
76
|
+
elseif normal == Enum.NormalId.Front or normal == Enum.NormalId.Back then
|
|
77
|
+
cframe *= CFrame.fromOrientation(0, math.pi, 0)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
local z = rng:NextNumber()
|
|
81
|
+
local t = 1 - z ^ utility.lerp(0.5, 1, math.sqrt(partial))
|
|
82
|
+
|
|
83
|
+
local width = utility.lerp(1, partial, t)
|
|
84
|
+
|
|
85
|
+
-- stylua: ignore
|
|
86
|
+
local pos = Vector3.new(
|
|
87
|
+
t * 2 - 1,
|
|
88
|
+
r * math.sin(theta) * width,
|
|
89
|
+
r * math.cos(theta) * width
|
|
90
|
+
) * size / 2
|
|
91
|
+
|
|
92
|
+
-- stylua: ignore
|
|
93
|
+
local pos2 = Vector3.new(
|
|
94
|
+
0,
|
|
95
|
+
math.sin(theta) * width,
|
|
96
|
+
math.cos(theta) * width
|
|
97
|
+
) * size / 2
|
|
98
|
+
|
|
99
|
+
local tangent = Vector3.new(0, math.cos(theta) * width, -math.sin(theta) * width) * size / 2
|
|
100
|
+
local up = tangent.Magnitude > 0.001 and tangent.Unit or cframe.UpVector
|
|
101
|
+
local res = cframe * CFrame.new(pos) * CFrame.lookAt(Vector3.zero, pos2, up)
|
|
102
|
+
|
|
103
|
+
debug.profileend()
|
|
104
|
+
|
|
105
|
+
return res
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
function shape.getPointWithinSphere(
|
|
109
|
+
seed: number,
|
|
110
|
+
min_radius: number,
|
|
111
|
+
partial: number,
|
|
112
|
+
cframe: CFrame,
|
|
113
|
+
size: Vector3,
|
|
114
|
+
normal: Enum.NormalId
|
|
115
|
+
)
|
|
116
|
+
debug.profilebegin("getPointWithinSphere")
|
|
117
|
+
|
|
118
|
+
local rng = Random.new(seed)
|
|
119
|
+
|
|
120
|
+
local u = rng:NextNumber()
|
|
121
|
+
local v = rng:NextNumber()
|
|
122
|
+
|
|
123
|
+
local theta = u * 2 * math.pi
|
|
124
|
+
local phi = math.acos(2 * v - 1) * partial
|
|
125
|
+
local r = rng:NextNumber(min_radius, 1) ^ (0.3333333333333333)
|
|
126
|
+
|
|
127
|
+
local sinTheta = math.sin(theta)
|
|
128
|
+
local cosTheta = math.cos(theta)
|
|
129
|
+
local sinPhi = math.sin(phi)
|
|
130
|
+
local cosPhi = math.cos(phi)
|
|
131
|
+
|
|
132
|
+
local n = Vector3.FromNormalId(normal)
|
|
133
|
+
|
|
134
|
+
if normal == Enum.NormalId.Left or normal == Enum.NormalId.Right then
|
|
135
|
+
size = Vector3.new(size.Z, size.Y, size.X)
|
|
136
|
+
elseif normal == Enum.NormalId.Top or normal == Enum.NormalId.Bottom then
|
|
137
|
+
size = Vector3.new(size.X, size.Z, size.Y)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
local half = size / 2
|
|
141
|
+
local cf = shape.getSurfaceCFrame(cframe, n, Vector3.zero)
|
|
142
|
+
|
|
143
|
+
-- stylua: ignore
|
|
144
|
+
local pos = Vector3.new(
|
|
145
|
+
r * sinPhi * cosTheta,
|
|
146
|
+
r * sinPhi * sinTheta,
|
|
147
|
+
r * cosPhi
|
|
148
|
+
) * half
|
|
149
|
+
|
|
150
|
+
local tangent = Vector3.new(-sinPhi * sinTheta, sinPhi * cosTheta, 0) * half
|
|
151
|
+
|
|
152
|
+
local up = if tangent.Magnitude > 0.001 then tangent.Unit else Vector3.new(1, 0, 0)
|
|
153
|
+
local res = cf * CFrame.Angles(0, math.pi, 0) * CFrame.new(pos) * CFrame.lookAt(Vector3.zero, pos, up)
|
|
154
|
+
|
|
155
|
+
debug.profileend()
|
|
156
|
+
|
|
157
|
+
return res
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
function shape.getPointWithinDisc(
|
|
161
|
+
seed: number,
|
|
162
|
+
min_depth: number,
|
|
163
|
+
partial: number,
|
|
164
|
+
cframe: CFrame,
|
|
165
|
+
size: Vector3,
|
|
166
|
+
normal: Enum.NormalId
|
|
167
|
+
)
|
|
168
|
+
debug.profilebegin("getPointWithinDisc")
|
|
169
|
+
|
|
170
|
+
local rng = Random.new(seed)
|
|
171
|
+
|
|
172
|
+
local n = Vector3.FromNormalId(normal)
|
|
173
|
+
local axes = Vector3.one - n:Abs() * min_depth
|
|
174
|
+
|
|
175
|
+
local half = size / 2
|
|
176
|
+
|
|
177
|
+
local z = rng:NextNumber(min_depth, 1)
|
|
178
|
+
local d = utility.lerp(1, 0.5, partial ^ 4)
|
|
179
|
+
|
|
180
|
+
local t = z
|
|
181
|
+
|
|
182
|
+
local r = rng:NextNumber(1 - partial, 1) ^ d
|
|
183
|
+
local theta = rng:NextNumber(0, 2 * math.pi)
|
|
184
|
+
|
|
185
|
+
-- stylua: ignore
|
|
186
|
+
local s = Vector3.new(
|
|
187
|
+
t * 2 - 1,
|
|
188
|
+
r * math.sin(theta),
|
|
189
|
+
r * math.cos(theta)
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
if normal == Enum.NormalId.Bottom or normal == Enum.NormalId.Top then
|
|
193
|
+
s = Vector3.new(s.Z, s.X, s.Y)
|
|
194
|
+
elseif normal == Enum.NormalId.Front or normal == Enum.NormalId.Back then
|
|
195
|
+
s = Vector3.new(s.Y, s.Z, s.X)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
s *= half * axes
|
|
199
|
+
|
|
200
|
+
local cf = shape.getSurfaceCFrame(cframe, n, s + n * min_depth * half)
|
|
201
|
+
|
|
202
|
+
debug.profileend()
|
|
203
|
+
|
|
204
|
+
return cf
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
return shape
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
local RunService = game:GetService("RunService")
|
|
2
|
+
|
|
3
|
+
local logger = require(script.Parent.logger)
|
|
4
|
+
local utility = require(script.Parent.utility)
|
|
5
|
+
|
|
6
|
+
local Bezier = require(script.Parent.Parent.obj.Bezier)
|
|
7
|
+
|
|
8
|
+
local tween = {}
|
|
9
|
+
|
|
10
|
+
tween.bezier_cache = {} :: { [string]: Bezier.Bezier }
|
|
11
|
+
|
|
12
|
+
function tween.fromParams(
|
|
13
|
+
params: string,
|
|
14
|
+
duration: number,
|
|
15
|
+
animator: (alpha: number, deltaTime: number, elapsed: number) -> number?,
|
|
16
|
+
awaitTween: RBXScriptConnection?,
|
|
17
|
+
onFinish: ((organic: boolean) -> ())?,
|
|
18
|
+
startAtZero: boolean?,
|
|
19
|
+
stepAtPriority: number?
|
|
20
|
+
)
|
|
21
|
+
local bezier = tween.bezier_cache[params]
|
|
22
|
+
|
|
23
|
+
if not bezier then
|
|
24
|
+
local success, points = pcall(function()
|
|
25
|
+
return utility.deserializePath(params)
|
|
26
|
+
end)
|
|
27
|
+
|
|
28
|
+
if not success then
|
|
29
|
+
logger.error(`failed to decode bezier path data with error: {points}`)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
-- use 0 accuracy as it saves performance because there is no need to calculate the length
|
|
33
|
+
bezier = Bezier.new(points, 0)
|
|
34
|
+
tween.bezier_cache[params] = bezier
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
local elapsed = 0
|
|
38
|
+
|
|
39
|
+
local cleanupStepper
|
|
40
|
+
|
|
41
|
+
local function step(deltaTime)
|
|
42
|
+
-- roblox tweens apparently don't start from alpha=0
|
|
43
|
+
if not startAtZero and elapsed == 0 then
|
|
44
|
+
elapsed = math.clamp(elapsed + deltaTime, 0, math.max(duration, 0))
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
local t = math.clamp(elapsed / duration, 0, 1)
|
|
48
|
+
local alpha = 1 - bezier:getEase(t).y
|
|
49
|
+
|
|
50
|
+
local result = animator(alpha, deltaTime, elapsed)
|
|
51
|
+
|
|
52
|
+
if
|
|
53
|
+
(result == nil or (if duration ~= 0 then elapsed >= duration else elapsed > duration))
|
|
54
|
+
and (not awaitTween or not awaitTween.Connected)
|
|
55
|
+
then
|
|
56
|
+
cleanupStepper()
|
|
57
|
+
|
|
58
|
+
if onFinish then
|
|
59
|
+
onFinish(true)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
return
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
if result then
|
|
66
|
+
elapsed = math.clamp(elapsed + result, 0, math.max(duration, 0.001))
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
if not stepAtPriority then
|
|
71
|
+
local connection: RBXScriptConnection
|
|
72
|
+
connection = RunService.RenderStepped:Connect(step)
|
|
73
|
+
|
|
74
|
+
cleanupStepper = function()
|
|
75
|
+
connection:Disconnect()
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
return connection
|
|
79
|
+
else
|
|
80
|
+
local id = utility.getRandomId()
|
|
81
|
+
|
|
82
|
+
RunService:BindToRenderStep(id, stepAtPriority, step)
|
|
83
|
+
|
|
84
|
+
local bound = true
|
|
85
|
+
|
|
86
|
+
cleanupStepper = function()
|
|
87
|
+
if not bound then
|
|
88
|
+
return
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
bound = false
|
|
92
|
+
|
|
93
|
+
RunService:UnbindFromRenderStep(id)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
return cleanupStepper
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
function tween.timer(
|
|
101
|
+
duration: number,
|
|
102
|
+
counter: (deltaTime: number, elapsed: number) -> number,
|
|
103
|
+
awaitTween: RBXScriptConnection?,
|
|
104
|
+
scope: {}?,
|
|
105
|
+
stepAtPriority: number?
|
|
106
|
+
)
|
|
107
|
+
local main = coroutine.running()
|
|
108
|
+
|
|
109
|
+
local elapsed = 0
|
|
110
|
+
|
|
111
|
+
local cleanupStepper
|
|
112
|
+
|
|
113
|
+
local function step(deltaTime)
|
|
114
|
+
local result = counter(deltaTime, elapsed)
|
|
115
|
+
|
|
116
|
+
if
|
|
117
|
+
(result == nil or (if duration ~= 0 then elapsed >= duration else elapsed > duration))
|
|
118
|
+
and (not awaitTween or not awaitTween.Connected)
|
|
119
|
+
then
|
|
120
|
+
cleanupStepper()
|
|
121
|
+
task.spawn(main)
|
|
122
|
+
return
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
if result then
|
|
126
|
+
elapsed = math.clamp(elapsed + result, 0, math.max(duration, 0.001))
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
if not stepAtPriority then
|
|
131
|
+
local connection = RunService.RenderStepped:Connect(step)
|
|
132
|
+
|
|
133
|
+
cleanupStepper = function()
|
|
134
|
+
connection:Disconnect()
|
|
135
|
+
end
|
|
136
|
+
else
|
|
137
|
+
local id = utility.getRandomId()
|
|
138
|
+
|
|
139
|
+
RunService:BindToRenderStep(id, stepAtPriority, step)
|
|
140
|
+
|
|
141
|
+
local bound = true
|
|
142
|
+
|
|
143
|
+
cleanupStepper = function()
|
|
144
|
+
if not bound then
|
|
145
|
+
return
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
bound = false
|
|
149
|
+
|
|
150
|
+
RunService:UnbindFromRenderStep(id)
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
if scope then
|
|
155
|
+
table.insert(scope, cleanupStepper)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
coroutine.yield()
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
return tween
|