cluaupp 1.5.0 → 1.5.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.
Files changed (323) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/README.md +10 -5
  3. package/api/CHANGELOG.md +3 -0
  4. package/api/chat.js +74 -0
  5. package/api/fixtures/roblox/README.md +6 -0
  6. package/api/fixtures/roblox/aux/sample.d.luau +6 -0
  7. package/api/fixtures/roblox/mini/Mini-API-Dump.json +72 -0
  8. package/api/generated/bench-latest.json +39 -0
  9. package/api/generated/capability-profile.json +76 -0
  10. package/api/generated/lsp-index.json +1 -0
  11. package/api/generated/luau/classes.d.luau +11221 -0
  12. package/api/generated/luau/datatypes.d.luau +327 -0
  13. package/api/generated/luau/enums.d.luau +4918 -0
  14. package/api/generated/luau/globals.d.luau +12 -0
  15. package/api/manifests/roblox-target.manifest.json +22 -0
  16. package/api/normalized/roblox-target.profile.json +237461 -0
  17. package/api/overrides/classes.json +8 -0
  18. package/api/overrides/compatibility.json +9 -0
  19. package/api/overrides/datatypes.json +1579 -0
  20. package/api/overrides/enums.json +8 -0
  21. package/api/overrides/globals.json +8 -0
  22. package/api/overrides/type-mappings.json +9 -0
  23. package/api/roblox-api.lock.json +9 -0
  24. package/data/Mini-API-Dump.json +1 -0
  25. package/editors/vscode/README.md +12 -10
  26. package/editors/vscode/extension.js +82 -0
  27. package/editors/vscode/icons/axiom.svg +4 -0
  28. package/editors/vscode/icons/bloom.svg +5 -0
  29. package/editors/vscode/icons/helm.svg +4 -0
  30. package/editors/vscode/icons/hive.svg +5 -0
  31. package/editors/vscode/icons/mint.svg +4 -0
  32. package/editors/vscode/icons/shift.svg +6 -0
  33. package/editors/vscode/language-configuration-schema.json +24 -0
  34. package/editors/vscode/package.json +172 -12
  35. package/editors/vscode/snippets/axiom.json +12 -0
  36. package/editors/vscode/snippets/bloom.json +12 -0
  37. package/editors/vscode/snippets/helm.json +12 -0
  38. package/editors/vscode/snippets/hive.json +12 -0
  39. package/editors/vscode/snippets/mint.json +12 -0
  40. package/editors/vscode/snippets/shift.json +17 -0
  41. package/editors/vscode/syntaxes/axiom.tmLanguage.json +5 -0
  42. package/editors/vscode/syntaxes/bloom.tmLanguage.json +5 -0
  43. package/editors/vscode/syntaxes/helm.tmLanguage.json +5 -0
  44. package/editors/vscode/syntaxes/hive.tmLanguage.json +5 -0
  45. package/editors/vscode/syntaxes/mint.tmLanguage.json +5 -0
  46. package/editors/vscode/syntaxes/schema.tmLanguage.json +89 -0
  47. package/editors/vscode/syntaxes/shift.tmLanguage.json +5 -0
  48. package/examples/game/.cluaupp/compile-cache/ReplicatedStorage__Shared__Constants__Datas__TemplateData.clh.json +1 -0
  49. package/examples/game/.cluaupp/compile-cache/ServerScriptService__Boot__DataBoot.server.clpp.json +1 -0
  50. package/examples/game/.cluaupp/compile-cache/ServerScriptService__Configuration__ServerConfig.clp.json +1 -0
  51. package/examples/game/.cluaupp/compile-cache/ServerScriptService__Handlers__Guard.server.clpp.json +1 -0
  52. package/examples/game/.cluaupp/compile-cache/ServerScriptService__Handlers__PlayerHandler.server.clpp.json +1 -0
  53. package/examples/game/.cluaupp/compile-cache/StarterPlayer__StarterCharacterScripts__Character__CharacterReady.client.clpp.json +1 -0
  54. package/examples/game/.cluaupp/compile-cache/StarterPlayer__StarterPlayerScripts__Controllers__DataController.client.clpp.json +1 -0
  55. package/examples/game/.cluaupp/compile-cache/index.json +12 -0
  56. package/examples/game/.cluaupp/datamodel-profile.json +94 -0
  57. package/examples/game/.vscode/settings.json +12 -1
  58. package/examples/game/include/clpp/datatypes.clh +337 -373
  59. package/examples/game/include/clpp/generated/datamodel.clh +25 -0
  60. package/examples/game/include/clpp/generated/enums.clh +1 -1
  61. package/examples/game/include/clpp/generated/instances.clh +41135 -41064
  62. package/examples/game/include/clpp/libs/axiom.clh +1 -1
  63. package/examples/game/include/clpp/libs/math.clh +14 -0
  64. package/examples/game/include/clpp/libs/spring.clh +17 -0
  65. package/examples/game/include/clpp/libs/ward.clh +1 -0
  66. package/examples/game/include/clpp/roblox.clh +3 -4
  67. package/examples/game/libs/ArrayIndexer/init.luau +209 -0
  68. package/examples/game/libs/Axiom/init.luau +608 -0
  69. package/examples/game/libs/Bloom/init.luau +433 -0
  70. package/examples/game/libs/Coil/init.luau +215 -0
  71. package/examples/game/libs/Crest/init.luau +426 -0
  72. package/examples/game/libs/Echo/init.luau +417 -0
  73. package/examples/game/libs/Ember/init.luau +365 -0
  74. package/examples/game/libs/Flare/init.luau +717 -0
  75. package/examples/game/libs/Gleam/init.luau +729 -0
  76. package/examples/game/libs/Guide/init.luau +215 -0
  77. package/examples/game/libs/Helm/init.luau +377 -0
  78. package/examples/game/libs/Hive/init.luau +241 -0
  79. package/examples/game/libs/Keep/Client.luau +114 -0
  80. package/examples/game/libs/Keep/Data.luau +883 -0
  81. package/examples/game/libs/Keep/Engine.luau +211 -0
  82. package/examples/game/libs/Keep/Enum.luau +6 -0
  83. package/examples/game/libs/Keep/Enums.luau +10 -0
  84. package/examples/game/libs/Keep/Path.luau +236 -0
  85. package/examples/game/libs/Keep/Replicator.luau +298 -0
  86. package/examples/game/libs/Keep/Server.luau +251 -0
  87. package/examples/game/libs/Keep/Store.luau +652 -0
  88. package/examples/game/libs/Keep/Trade.luau +455 -0
  89. package/examples/game/libs/Keep/init.luau +205 -0
  90. package/examples/game/libs/Lens/init.luau +609 -0
  91. package/examples/game/libs/Mint/init.luau +279 -0
  92. package/examples/game/libs/Net/init.luau +156 -0
  93. package/examples/game/libs/Net/src/codec.luau +224 -0
  94. package/examples/game/libs/Occlude/init.luau +117 -0
  95. package/examples/game/libs/Pin/init.luau +309 -0
  96. package/examples/game/libs/Promise/LICENSE +21 -0
  97. package/examples/game/libs/Promise/_impl/LICENSE +21 -0
  98. package/examples/game/libs/Promise/_impl/init.lua +1991 -0
  99. package/examples/game/libs/Promise/init.lua +1990 -0
  100. package/examples/game/libs/Promise/init.luau +13 -0
  101. package/examples/game/libs/Promise/types.luau +46 -0
  102. package/examples/game/libs/Roster/init.luau +686 -0
  103. package/examples/game/libs/SOURCES.md +31 -0
  104. package/examples/game/libs/Shift/init.luau +238 -0
  105. package/examples/game/libs/Spark/init.luau +487 -0
  106. package/examples/game/libs/Stage/init.luau +178 -0
  107. package/examples/game/libs/Sweep/init.luau +259 -0
  108. package/examples/game/libs/Trace/init.luau +213 -0
  109. package/examples/game/libs/Ward/init.luau +211 -0
  110. package/examples/game/out/ReplicatedStorage/Shared/Constants/Datas/TemplateData.luau +29 -0
  111. package/examples/game/out/ReplicatedStorage/Shared/Constants/Datas/TemplateData.luau.map.json +13 -0
  112. package/examples/game/out/ReplicatedStorage/Shared/Net/Net.luau +83 -0
  113. package/examples/game/out/ReplicatedStorage/Shared/Net/Net.luau.map.json +13 -0
  114. package/examples/game/out/ServerScriptService/Boot/DataBoot.server.luau +18 -0
  115. package/examples/game/out/ServerScriptService/Boot/DataBoot.server.luau.map.json +13 -0
  116. package/examples/game/out/ServerScriptService/Configuration/ServerConfig.luau +14 -0
  117. package/examples/game/out/ServerScriptService/Configuration/ServerConfig.luau.map.json +13 -0
  118. package/examples/game/out/ServerScriptService/Handlers/Guard.server.luau +15 -0
  119. package/examples/game/out/ServerScriptService/Handlers/Guard.server.luau.map.json +13 -0
  120. package/examples/game/out/ServerScriptService/Handlers/PlayerHandler.server.luau +50 -0
  121. package/examples/game/out/ServerScriptService/Handlers/PlayerHandler.server.luau.map.json +13 -0
  122. package/examples/game/out/StarterPlayer/StarterCharacterScripts/Character/CharacterReady.client.luau +12 -0
  123. package/examples/game/out/StarterPlayer/StarterCharacterScripts/Character/CharacterReady.client.luau.map.json +13 -0
  124. package/examples/game/out/StarterPlayer/StarterPlayerScripts/Controllers/DataController.client.luau +16 -0
  125. package/examples/game/out/StarterPlayer/StarterPlayerScripts/Controllers/DataController.client.luau.map.json +13 -0
  126. package/examples/game/src/ReplicatedStorage/Shared/Net/Net.clh +26 -0
  127. package/examples/game/src/ServerScriptService/Boot/DataBoot.server.clpp +1 -1
  128. package/examples/game/src/ServerScriptService/Handlers/PlayerHandler.server.clpp +1 -1
  129. package/examples/game/stylua.toml +9 -0
  130. package/generated/api/build-profile.js +115 -0
  131. package/generated/api/cache.js +44 -0
  132. package/generated/api/coverage.js +32 -0
  133. package/generated/api/diff.js +125 -0
  134. package/generated/api/generators/clpp-headers.js +353 -0
  135. package/generated/api/generators/docs-reference.js +7 -0
  136. package/generated/api/generators/lsp-index.js +81 -0
  137. package/generated/api/generators/luau-defs.js +94 -0
  138. package/generated/api/ide.js +76 -0
  139. package/generated/api/identifier.js +47 -0
  140. package/generated/api/index.js +324 -0
  141. package/generated/api/loader.js +57 -0
  142. package/generated/api/merge.js +88 -0
  143. package/generated/api/model.js +5 -0
  144. package/generated/api/normalize.js +231 -0
  145. package/generated/api/overrides-validate.js +58 -0
  146. package/generated/api/perf.js +12 -0
  147. package/generated/api/registry.js +136 -0
  148. package/generated/api/release.js +44 -0
  149. package/generated/api/resolver.js +250 -0
  150. package/generated/api/sources/aux-types-diff.js +75 -0
  151. package/generated/api/sources/client-tracker.js +11 -0
  152. package/generated/api/sources/creator-docs.js +42 -0
  153. package/generated/api/sources/luau-types.js +34 -0
  154. package/generated/api/sources/mini-dump.js +17 -0
  155. package/generated/api/sources/studio-api.js +8 -0
  156. package/generated/api/sources/studio-apiv2.js +11 -0
  157. package/generated/api/sources/studio-full-api.js +8 -0
  158. package/generated/api/studio-smoke.js +80 -0
  159. package/generated/api/type-parse.js +49 -0
  160. package/generated/api/understander.js +51 -0
  161. package/generated/api/validate.js +135 -0
  162. package/generated/api-cli.js +421 -0
  163. package/generated/cli.js +16 -5
  164. package/generated/clpp/contract.js +3 -3
  165. package/generated/clpp/format-luau.js +236 -0
  166. package/generated/clpp/index.js +13 -1
  167. package/generated/clpp/modules.js +227 -0
  168. package/generated/clpp/postprocess.js +86 -5
  169. package/generated/clpp/rewrite-janitor.js +145 -0
  170. package/generated/clpp/runner.js +14 -2
  171. package/generated/compile.js +82 -0
  172. package/generated/flare/parse.js +12 -1
  173. package/generated/intellisense.js +57 -1
  174. package/generated/native/index.js +217 -16
  175. package/generated/target/authority-check.js +136 -0
  176. package/generated/target/authority-graph.js +74 -0
  177. package/generated/target/build-cache.js +112 -0
  178. package/generated/target/capabilities.js +89 -0
  179. package/generated/target/capability-profile.js +30 -0
  180. package/generated/target/component-contracts.js +60 -0
  181. package/generated/target/context-check.js +160 -0
  182. package/generated/target/datamodel-check.js +170 -0
  183. package/generated/target/datamodel-generate.js +74 -0
  184. package/generated/target/datamodel.js +233 -0
  185. package/generated/target/diagnostics.js +63 -0
  186. package/generated/target/doctor.js +152 -0
  187. package/generated/target/flare-version.js +58 -0
  188. package/generated/target/get-service.js +69 -0
  189. package/generated/target/lifetime-check.js +47 -0
  190. package/generated/target/luau-stamp.js +39 -0
  191. package/generated/target/optimizer-advise.js +88 -0
  192. package/generated/target/optimizer-apply.js +44 -0
  193. package/generated/target/optimizer-soa.js +254 -0
  194. package/generated/target/parallel-check.js +136 -0
  195. package/generated/target/pgo.js +148 -0
  196. package/generated/target/project-docs.js +69 -0
  197. package/generated/target/project-graph.js +71 -0
  198. package/generated/target/roblox.js +63 -0
  199. package/generated/target/security-check.js +41 -0
  200. package/generated/target/source-map.js +25 -0
  201. package/generated/target/studio-bridge.js +112 -0
  202. package/generated/utils/project.js +178 -8
  203. package/generated/utils/rojo-mapper.js +11 -3
  204. package/include/clpp/datatypes.clh +337 -373
  205. package/include/clpp/generated/enums.clh +1 -1
  206. package/include/clpp/generated/instances.clh +41135 -41064
  207. package/include/clpp/libs/axiom.clh +1 -1
  208. package/include/clpp/libs/hive.clh +1 -0
  209. package/include/clpp/libs/keep.clh +2 -0
  210. package/include/clpp/libs/math.clh +14 -0
  211. package/include/clpp/libs/spring.clh +17 -0
  212. package/include/clpp/libs/ward.clh +1 -0
  213. package/include/clpp/roblox.clh +3 -4
  214. package/package.json +10 -3
  215. package/plugins/CluauppNav/Plugin.luau +207 -0
  216. package/plugins/CluauppNav/ProfileLogger.luau +27 -0
  217. package/plugins/CluauppNav/README.md +24 -0
  218. package/runtime/Axiom/init.luau +10 -7
  219. package/runtime/Coil/init.luau +8 -2
  220. package/runtime/Crest/init.luau +1 -0
  221. package/runtime/Flare/init.luau +2 -1
  222. package/runtime/Gleam/init.luau +15 -4
  223. package/runtime/Hive/init.luau +36 -14
  224. package/runtime/Pin/init.luau +5 -2
  225. package/runtime/Roster/init.luau +2 -0
  226. package/runtime/Spark/init.luau +3 -0
  227. package/runtime/Sweep/init.luau +2 -0
  228. package/runtime/Trace/init.luau +3 -0
  229. package/runtime/Ward/init.luau +38 -5
  230. package/scripts/postinstall-editor.js +17 -0
  231. package/skills/README.md +13 -0
  232. package/skills/clpp-hive-flare/SKILL.md +79 -0
  233. package/skills/clpp-language/SKILL.md +123 -0
  234. package/skills/clpp-language/compiler.md +89 -0
  235. package/skills/clpp-style/SKILL.md +95 -0
  236. package/src/api/build-profile.ts +138 -0
  237. package/src/api/cache.ts +45 -0
  238. package/src/api/coverage.ts +46 -0
  239. package/src/api/diff.ts +143 -0
  240. package/src/api/generators/clpp-headers.ts +377 -0
  241. package/src/api/generators/docs-reference.ts +11 -0
  242. package/src/api/generators/lsp-index.ts +106 -0
  243. package/src/api/generators/luau-defs.ts +98 -0
  244. package/src/api/ide.ts +87 -0
  245. package/src/api/identifier.ts +47 -0
  246. package/src/api/index.ts +269 -0
  247. package/src/api/loader.ts +60 -0
  248. package/src/api/merge.ts +126 -0
  249. package/src/api/model.ts +283 -0
  250. package/src/api/normalize.ts +257 -0
  251. package/src/api/overrides-validate.ts +58 -0
  252. package/src/api/perf.ts +15 -0
  253. package/src/api/registry.ts +162 -0
  254. package/src/api/release.ts +47 -0
  255. package/src/api/resolver.ts +255 -0
  256. package/src/api/sources/aux-types-diff.ts +81 -0
  257. package/src/api/sources/client-tracker.ts +10 -0
  258. package/src/api/sources/creator-docs.ts +37 -0
  259. package/src/api/sources/luau-types.ts +30 -0
  260. package/src/api/sources/mini-dump.ts +50 -0
  261. package/src/api/sources/studio-api.ts +7 -0
  262. package/src/api/sources/studio-apiv2.ts +10 -0
  263. package/src/api/sources/studio-full-api.ts +7 -0
  264. package/src/api/studio-smoke.ts +82 -0
  265. package/src/api/type-parse.ts +48 -0
  266. package/src/api/understander.ts +72 -0
  267. package/src/api/validate.ts +160 -0
  268. package/src/api-cli.ts +493 -0
  269. package/src/api.generated.js +37 -22
  270. package/src/cli.ts +21 -6
  271. package/src/clpp/contract.ts +34 -3
  272. package/src/clpp/format-luau.ts +262 -0
  273. package/src/clpp/index.ts +13 -2
  274. package/src/clpp/modules.ts +252 -0
  275. package/src/clpp/postprocess.ts +100 -5
  276. package/src/clpp/rewrite-janitor.ts +156 -0
  277. package/src/clpp/runner.ts +14 -2
  278. package/src/compile.ts +87 -0
  279. package/src/flare/parse.ts +14 -1
  280. package/src/flare/types.ts +2 -0
  281. package/src/intellisense.ts +58 -1
  282. package/src/native/index.ts +225 -16
  283. package/src/target/authority-check.ts +162 -0
  284. package/src/target/authority-graph.ts +80 -0
  285. package/src/target/build-cache.ts +129 -0
  286. package/src/target/capabilities.ts +115 -0
  287. package/src/target/capability-profile.ts +25 -0
  288. package/src/target/component-contracts.ts +64 -0
  289. package/src/target/context-check.ts +177 -0
  290. package/src/target/datamodel-check.ts +188 -0
  291. package/src/target/datamodel-generate.ts +78 -0
  292. package/src/target/datamodel.ts +261 -0
  293. package/src/target/diagnostics.ts +67 -0
  294. package/src/target/doctor.ts +171 -0
  295. package/src/target/flare-version.ts +61 -0
  296. package/src/target/get-service.ts +85 -0
  297. package/src/target/lifetime-check.ts +45 -0
  298. package/src/target/luau-stamp.ts +33 -0
  299. package/src/target/optimizer-advise.ts +93 -0
  300. package/src/target/optimizer-apply.ts +63 -0
  301. package/src/target/optimizer-soa.ts +270 -0
  302. package/src/target/parallel-check.ts +135 -0
  303. package/src/target/pgo.ts +157 -0
  304. package/src/target/project-docs.ts +68 -0
  305. package/src/target/project-graph.ts +75 -0
  306. package/src/target/roblox.ts +78 -0
  307. package/src/target/security-check.ts +40 -0
  308. package/src/target/source-map.ts +36 -0
  309. package/src/target/studio-bridge.ts +140 -0
  310. package/src/types.ts +14 -0
  311. package/src/utils/project.ts +183 -9
  312. package/src/utils/rojo-mapper.ts +12 -3
  313. package/stylua.toml +9 -0
  314. package/templates/game/.vscode/settings.json +7 -1
  315. package/templates/game/include/clpp/datatypes.clh +337 -373
  316. package/templates/game/include/clpp/generated/enums.clh +1 -1
  317. package/templates/game/include/clpp/generated/instances.clh +41135 -41064
  318. package/templates/game/include/clpp/libs/axiom.clh +1 -1
  319. package/templates/game/include/clpp/libs/ward.clh +1 -0
  320. package/templates/game/include/clpp/roblox.clh +3 -4
  321. package/templates/game/src/ServerScriptService/Boot/DataBoot.server.clpp +1 -1
  322. package/templates/game/src/ServerScriptService/Handlers/PlayerHandler.server.clpp +1 -1
  323. package/templates/game/stylua.toml +9 -0
@@ -0,0 +1,365 @@
1
+ --!native
2
+ --!optimize 2
3
+ --!strict
4
+ --[=[
5
+ @class Ember
6
+ Emit, play, stop, scale, and clone visual-effect templates (ParticleEmitter,
7
+ Beam, Trail, Sound, Animation). There was no public GitHub for
8
+ lucaschaibub/vfx-util; this is the full Cluaupp system.
9
+
10
+ ```lua
11
+ Ember.Emit(attachment, 12)
12
+ local clone = Ember.CloneOnto(template, character.HumanoidRootPart)
13
+ Ember.Play(clone)
14
+ task.delay(2, function()
15
+ Ember.DestroyAfter(clone, 0.4)
16
+ end)
17
+ ```
18
+ ]=]
19
+ local Sweep = require(script.Parent.Sweep)
20
+
21
+ local Ember = {}
22
+
23
+ export type EffectInstance = ParticleEmitter | Beam | Trail | Sound | Fire | Smoke | Sparkles | Animation | AnimationTrack
24
+
25
+ local tracks: { [Instance]: { AnimationTrack } } = {}
26
+
27
+ local function isEffect(inst: Instance): boolean
28
+ return inst:IsA("ParticleEmitter")
29
+ or inst:IsA("Beam")
30
+ or inst:IsA("Trail")
31
+ or inst:IsA("Sound")
32
+ or inst:IsA("Fire")
33
+ or inst:IsA("Smoke")
34
+ or inst:IsA("Sparkles")
35
+ or inst:IsA("Animation")
36
+ or inst:IsA("AnimationTrack")
37
+ end
38
+
39
+ local function collect(root: Instance): { Instance }
40
+ local found: { Instance } = {}
41
+ if isEffect(root) then
42
+ table.insert(found, root)
43
+ end
44
+ for _, child in root:GetDescendants() do
45
+ if isEffect(child) then
46
+ table.insert(found, child)
47
+ end
48
+ end
49
+ return found
50
+ end
51
+
52
+ local function scaleSequence(sequence: NumberSequence, factor: number): NumberSequence
53
+ local keys = {}
54
+ for index, keypoint in sequence.Keypoints do
55
+ keys[index] = NumberSequenceKeypoint.new(keypoint.Time, keypoint.Value * factor, keypoint.Envelope * factor)
56
+ end
57
+ return NumberSequence.new(keys)
58
+ end
59
+
60
+ local function animatorOf(root: Instance): Animator?
61
+ local current: Instance? = root
62
+ while current do
63
+ if current:IsA("Animator") then
64
+ return current
65
+ end
66
+ if current:IsA("Humanoid") or current:IsA("AnimationController") then
67
+ local existing = current:FindFirstChildOfClass("Animator")
68
+ if existing then
69
+ return existing
70
+ end
71
+ local created = Instance.new("Animator")
72
+ created.Parent = current
73
+ return created
74
+ end
75
+ if current:IsA("Model") then
76
+ local humanoid = current:FindFirstChildOfClass("Humanoid")
77
+ if humanoid then
78
+ local existing = humanoid:FindFirstChildOfClass("Animator")
79
+ if existing then
80
+ return existing
81
+ end
82
+ local created = Instance.new("Animator")
83
+ created.Parent = humanoid
84
+ return created
85
+ end
86
+ local controller = current:FindFirstChildOfClass("AnimationController")
87
+ if controller then
88
+ local existing = controller:FindFirstChildOfClass("Animator")
89
+ if existing then
90
+ return existing
91
+ end
92
+ local created = Instance.new("Animator")
93
+ created.Parent = controller
94
+ return created
95
+ end
96
+ end
97
+ current = current.Parent
98
+ end
99
+ return nil
100
+ end
101
+
102
+ local function remember(root: Instance, track: AnimationTrack)
103
+ local list = tracks[root]
104
+ if list == nil then
105
+ list = {}
106
+ tracks[root] = list
107
+ end
108
+ table.insert(list, track)
109
+ end
110
+
111
+ local function ownerOf(root: Instance): any
112
+ local existing = (root :: any)._emberSweep
113
+ if Sweep.Is(existing) then
114
+ return existing
115
+ end
116
+ local sweep = Sweep.new()
117
+ sweep:Add(root)
118
+ sweep:LinkToInstance(root)
119
+ ;(root :: any)._emberSweep = sweep
120
+ return sweep
121
+ end
122
+
123
+ local function weldClone(clone: Instance, parent: Instance)
124
+ if clone:IsA("Attachment") then
125
+ if parent:IsA("Attachment") then
126
+ clone.Parent = parent.Parent
127
+ clone.Position = parent.Position
128
+ clone.Orientation = parent.Orientation
129
+ else
130
+ clone.Parent = parent
131
+ end
132
+ return
133
+ end
134
+ local host: BasePart? = nil
135
+ if parent:IsA("BasePart") then
136
+ host = parent
137
+ elseif parent:IsA("Attachment") then
138
+ host = parent.Parent :: BasePart?
139
+ elseif parent:IsA("Model") then
140
+ host = parent.PrimaryPart or parent:FindFirstChild("HumanoidRootPart") :: BasePart?
141
+ end
142
+ if clone:IsA("BasePart") and host then
143
+ clone.CFrame = host.CFrame
144
+ clone.Anchored = false
145
+ clone.CanCollide = false
146
+ clone.Massless = true
147
+ clone.Parent = host
148
+ local weld = Instance.new("WeldConstraint")
149
+ weld.Part0 = host
150
+ weld.Part1 = clone
151
+ weld.Parent = clone
152
+ return
153
+ end
154
+ if clone:IsA("Model") and host then
155
+ clone:PivotTo(host.CFrame)
156
+ local primary = clone.PrimaryPart or clone:FindFirstChildWhichIsA("BasePart", true)
157
+ if primary then
158
+ clone.PrimaryPart = primary
159
+ primary.Anchored = false
160
+ local weld = Instance.new("WeldConstraint")
161
+ weld.Part0 = host
162
+ weld.Part1 = primary
163
+ weld.Parent = clone
164
+ end
165
+ clone.Parent = host.Parent or host
166
+ return
167
+ end
168
+ clone.Parent = parent
169
+ end
170
+
171
+ --[=[
172
+ @within Ember
173
+ @param root Instance -- Attachment, Part, or a folder of emitters
174
+ @param count number? -- particles to emit; default 8
175
+ ]=]
176
+ function Ember.Emit(root: Instance, count: number?)
177
+ local amount = count or 8
178
+ for _, inst in collect(root) do
179
+ if inst:IsA("ParticleEmitter") then
180
+ inst:Emit(amount)
181
+ elseif inst:IsA("Sound") then
182
+ inst:Play()
183
+ elseif inst:IsA("Beam") or inst:IsA("Trail") then
184
+ inst.Enabled = true
185
+ elseif inst:IsA("Fire") or inst:IsA("Smoke") or inst:IsA("Sparkles") then
186
+ inst.Enabled = true
187
+ elseif inst:IsA("AnimationTrack") then
188
+ inst:Play()
189
+ elseif inst:IsA("Animation") then
190
+ local animator = animatorOf(inst)
191
+ if animator then
192
+ local track = animator:LoadAnimation(inst)
193
+ remember(root, track)
194
+ track:Play()
195
+ end
196
+ end
197
+ end
198
+ end
199
+
200
+ --[=[
201
+ @within Ember
202
+ Enables looping emitters / beams / trails and plays sounds and AnimationTracks.
203
+ ]=]
204
+ function Ember.Play(root: Instance)
205
+ for _, inst in collect(root) do
206
+ if inst:IsA("ParticleEmitter") or inst:IsA("Beam") or inst:IsA("Trail") then
207
+ inst.Enabled = true
208
+ elseif inst:IsA("Sound") then
209
+ inst:Play()
210
+ elseif inst:IsA("Fire") or inst:IsA("Smoke") or inst:IsA("Sparkles") then
211
+ inst.Enabled = true
212
+ elseif inst:IsA("AnimationTrack") then
213
+ inst:Play()
214
+ elseif inst:IsA("Animation") then
215
+ local animator = animatorOf(inst)
216
+ if animator then
217
+ local track = animator:LoadAnimation(inst)
218
+ remember(root, track)
219
+ track:Play()
220
+ end
221
+ end
222
+ end
223
+ end
224
+
225
+ --[=[
226
+ @within Ember
227
+ ]=]
228
+ function Ember.Stop(root: Instance)
229
+ for _, inst in collect(root) do
230
+ if inst:IsA("ParticleEmitter") or inst:IsA("Beam") or inst:IsA("Trail") then
231
+ inst.Enabled = false
232
+ elseif inst:IsA("Sound") then
233
+ inst:Stop()
234
+ elseif inst:IsA("Fire") or inst:IsA("Smoke") or inst:IsA("Sparkles") then
235
+ inst.Enabled = false
236
+ elseif inst:IsA("AnimationTrack") then
237
+ inst:Stop()
238
+ end
239
+ end
240
+ local loaded = tracks[root]
241
+ if loaded then
242
+ for _, track in loaded do
243
+ if track.IsPlaying then
244
+ track:Stop()
245
+ end
246
+ end
247
+ tracks[root] = nil
248
+ end
249
+ end
250
+
251
+ --[=[
252
+ @within Ember
253
+ @param template Instance
254
+ @param parent Instance
255
+ @return Instance
256
+ Clones a VFX template onto `parent` (Attachment / BasePart / Model).
257
+ ]=]
258
+ function Ember.CloneOnto(template: Instance, parent: Instance): Instance
259
+ local clone = template:Clone()
260
+ if clone:IsA("Attachment") and parent:IsA("BasePart") then
261
+ clone.Parent = parent
262
+ elseif clone:IsA("Attachment") and parent:IsA("Attachment") then
263
+ clone.Parent = parent.Parent
264
+ clone.Position = parent.Position
265
+ clone.Orientation = parent.Orientation
266
+ elseif clone:IsA("BasePart") and parent:IsA("Model") then
267
+ clone.Parent = parent
268
+ else
269
+ clone.Parent = parent
270
+ end
271
+ return clone
272
+ end
273
+
274
+ --[=[
275
+ @within Ember
276
+ Clones `template` onto a character (named Attachment, HumanoidRootPart, or PrimaryPart).
277
+ Sweep owns the clone and destroys it when the character is destroyed.
278
+ ]=]
279
+ function Ember.Attach(template: Instance, character: Instance, attachmentName: string?): Instance
280
+ local parent: Instance = character
281
+ if attachmentName and attachmentName ~= "" then
282
+ local named = character:FindFirstChild(attachmentName, true)
283
+ if named then
284
+ parent = named
285
+ end
286
+ elseif character:IsA("Model") then
287
+ local root = character:FindFirstChild("HumanoidRootPart") or character.PrimaryPart
288
+ if root then
289
+ parent = root
290
+ end
291
+ end
292
+ local clone = template:Clone()
293
+ weldClone(clone, parent)
294
+ if clone.Parent == nil then
295
+ clone.Parent = parent
296
+ end
297
+ local sweep = Sweep.new()
298
+ sweep:Add(clone)
299
+ sweep:LinkToInstance(character)
300
+ ;(clone :: any)._emberSweep = sweep
301
+ Ember.Play(clone)
302
+ return clone
303
+ end
304
+
305
+ --[=[
306
+ @within Ember
307
+ Scales NumberSequence / NumberRange particle sizes and related VFX by `factor`.
308
+ ]=]
309
+ function Ember.Scale(root: Instance, factor: number)
310
+ for _, inst in collect(root) do
311
+ if inst:IsA("ParticleEmitter") then
312
+ inst.Size = scaleSequence(inst.Size, factor)
313
+ local spread = inst.SpreadAngle
314
+ inst.SpreadAngle = Vector2.new(spread.X * factor, spread.Y * factor)
315
+ local speed = inst.Speed
316
+ inst.Speed = NumberRange.new(speed.Min * factor, speed.Max * factor)
317
+ elseif inst:IsA("Beam") then
318
+ inst.Width0 *= factor
319
+ inst.Width1 *= factor
320
+ elseif inst:IsA("Trail") then
321
+ inst.WidthScale = scaleSequence(inst.WidthScale, factor)
322
+ elseif inst:IsA("Fire") or inst:IsA("Smoke") then
323
+ inst.Size *= factor
324
+ elseif inst:IsA("Sound") then
325
+ inst.PlaybackSpeed = math.clamp(inst.PlaybackSpeed * factor, 0.1, 4)
326
+ end
327
+ end
328
+ end
329
+
330
+ --[=[
331
+ @within Ember
332
+ Stops effects then destroys the instance after `lifetime` seconds. Sweep owns the delay.
333
+ ]=]
334
+ function Ember.DestroyAfter(root: Instance, lifetime: number?)
335
+ local delayTime = lifetime or 1
336
+ local sweep = ownerOf(root)
337
+ local stopThread = task.delay(delayTime * 0.6, function()
338
+ if root.Parent then
339
+ Ember.Stop(root)
340
+ end
341
+ end)
342
+ local endThread = task.delay(delayTime, function()
343
+ sweep:Destroy()
344
+ end)
345
+ sweep:Add(function()
346
+ pcall(task.cancel, stopThread)
347
+ pcall(task.cancel, endThread)
348
+ tracks[root] = nil
349
+ end, true)
350
+ end
351
+
352
+ --[=[
353
+ @within Ember
354
+ One-shot: clone, emit, destroy.
355
+ ]=]
356
+ function Ember.Burst(template: Instance, parent: Instance, count: number?, lifetime: number?): Instance
357
+ local clone = Ember.CloneOnto(template, parent)
358
+ Ember.Emit(clone, count)
359
+ Ember.DestroyAfter(clone, lifetime or 2)
360
+ return clone
361
+ end
362
+
363
+ export type Ember = typeof(Ember)
364
+
365
+ return Ember