sa2kit 2.0.1 → 2.0.3

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 (278) hide show
  1. package/README.md +1 -1
  2. package/dist/CollisionBalls-BpHufX3H.d.mts +41 -0
  3. package/dist/CollisionBalls-BpHufX3H.d.ts +41 -0
  4. package/dist/ConfigService-BxK06xP6.d.mts +262 -0
  5. package/dist/ConfigService-BxK06xP6.d.ts +262 -0
  6. package/dist/UniversalFileService-BpvbZitV.d.mts +139 -0
  7. package/dist/UniversalFileService-GsP6D3Rc.d.ts +139 -0
  8. package/dist/audioDetection/index.d.mts +449 -0
  9. package/dist/audioDetection/index.d.ts +449 -0
  10. package/dist/audioDetection/index.js +1244 -0
  11. package/dist/audioDetection/index.js.map +1 -0
  12. package/dist/audioDetection/index.mjs +1227 -0
  13. package/dist/audioDetection/index.mjs.map +1 -0
  14. package/dist/auth/legacy/core/index.d.mts +42 -0
  15. package/dist/auth/legacy/core/index.d.ts +42 -0
  16. package/dist/auth/legacy/core/index.js +242 -0
  17. package/dist/auth/legacy/core/index.js.map +1 -0
  18. package/dist/auth/legacy/core/index.mjs +226 -0
  19. package/dist/auth/legacy/core/index.mjs.map +1 -0
  20. package/dist/auth/legacy/db/index.d.mts +5 -0
  21. package/dist/auth/legacy/db/index.d.ts +5 -0
  22. package/dist/auth/legacy/db/index.js +261 -0
  23. package/dist/auth/legacy/db/index.js.map +1 -0
  24. package/dist/auth/legacy/db/index.mjs +250 -0
  25. package/dist/auth/legacy/db/index.mjs.map +1 -0
  26. package/dist/auth/legacy/index.d.mts +5 -0
  27. package/dist/auth/legacy/index.d.ts +5 -0
  28. package/dist/auth/legacy/index.js +1107 -0
  29. package/dist/auth/legacy/index.js.map +1 -0
  30. package/dist/auth/legacy/index.mjs +1086 -0
  31. package/dist/auth/legacy/index.mjs.map +1 -0
  32. package/dist/auth/legacy/logic/index.d.mts +9 -0
  33. package/dist/auth/legacy/logic/index.d.ts +9 -0
  34. package/dist/auth/legacy/logic/index.js +194 -0
  35. package/dist/auth/legacy/logic/index.js.map +1 -0
  36. package/dist/auth/legacy/logic/index.mjs +187 -0
  37. package/dist/auth/legacy/logic/index.mjs.map +1 -0
  38. package/dist/auth/legacy/miniapp/index.d.mts +5 -0
  39. package/dist/auth/legacy/miniapp/index.d.ts +5 -0
  40. package/dist/auth/legacy/miniapp/index.js +506 -0
  41. package/dist/auth/legacy/miniapp/index.js.map +1 -0
  42. package/dist/auth/legacy/miniapp/index.mjs +487 -0
  43. package/dist/auth/legacy/miniapp/index.mjs.map +1 -0
  44. package/dist/auth/legacy/routes/index.d.mts +53 -0
  45. package/dist/auth/legacy/routes/index.d.ts +53 -0
  46. package/dist/auth/legacy/routes/index.js +278 -0
  47. package/dist/auth/legacy/routes/index.js.map +1 -0
  48. package/dist/auth/legacy/routes/index.mjs +271 -0
  49. package/dist/auth/legacy/routes/index.mjs.map +1 -0
  50. package/dist/auth/legacy/schema/index.d.mts +401 -0
  51. package/dist/auth/legacy/schema/index.d.ts +401 -0
  52. package/dist/auth/legacy/schema/index.js +50 -0
  53. package/dist/auth/legacy/schema/index.js.map +1 -0
  54. package/dist/auth/legacy/schema/index.mjs +44 -0
  55. package/dist/auth/legacy/schema/index.mjs.map +1 -0
  56. package/dist/auth/legacy/server/index.d.mts +13 -0
  57. package/dist/auth/legacy/server/index.d.ts +13 -0
  58. package/dist/auth/legacy/server/index.js +21 -0
  59. package/dist/auth/legacy/server/index.js.map +1 -0
  60. package/dist/auth/legacy/server/index.mjs +19 -0
  61. package/dist/auth/legacy/server/index.mjs.map +1 -0
  62. package/dist/auth/legacy/services/index.d.mts +40 -0
  63. package/dist/auth/legacy/services/index.d.ts +40 -0
  64. package/dist/auth/legacy/services/index.js +258 -0
  65. package/dist/auth/legacy/services/index.js.map +1 -0
  66. package/dist/auth/legacy/services/index.mjs +252 -0
  67. package/dist/auth/legacy/services/index.mjs.map +1 -0
  68. package/dist/auth/legacy/ui/miniapp/index.d.mts +10 -0
  69. package/dist/auth/legacy/ui/miniapp/index.d.ts +10 -0
  70. package/dist/auth/legacy/ui/miniapp/index.js +298 -0
  71. package/dist/auth/legacy/ui/miniapp/index.js.map +1 -0
  72. package/dist/auth/legacy/ui/miniapp/index.mjs +290 -0
  73. package/dist/auth/legacy/ui/miniapp/index.mjs.map +1 -0
  74. package/dist/auth/legacy/ui/web/index.d.mts +22 -0
  75. package/dist/auth/legacy/ui/web/index.d.ts +22 -0
  76. package/dist/auth/legacy/ui/web/index.js +899 -0
  77. package/dist/auth/legacy/ui/web/index.js.map +1 -0
  78. package/dist/auth/legacy/ui/web/index.mjs +889 -0
  79. package/dist/auth/legacy/ui/web/index.mjs.map +1 -0
  80. package/dist/auth/legacy/web/index.d.mts +5 -0
  81. package/dist/auth/legacy/web/index.d.ts +5 -0
  82. package/dist/auth/legacy/web/index.js +1107 -0
  83. package/dist/auth/legacy/web/index.js.map +1 -0
  84. package/dist/auth/legacy/web/index.mjs +1086 -0
  85. package/dist/auth/legacy/web/index.mjs.map +1 -0
  86. package/dist/auth/rn/index.d.mts +64 -0
  87. package/dist/auth/rn/index.d.ts +64 -0
  88. package/dist/auth/rn/index.js +765 -0
  89. package/dist/auth/rn/index.js.map +1 -0
  90. package/dist/auth/rn/index.mjs +754 -0
  91. package/dist/auth/rn/index.mjs.map +1 -0
  92. package/dist/base-api-client-ACKKt13v.d.mts +277 -0
  93. package/dist/base-api-client-ACKKt13v.d.ts +277 -0
  94. package/dist/boothVaultService-Cn4WPhjg.d.mts +83 -0
  95. package/dist/boothVaultService-Cn4WPhjg.d.ts +83 -0
  96. package/dist/business/index.d.mts +6 -0
  97. package/dist/business/index.d.ts +6 -0
  98. package/dist/business/index.js +1682 -0
  99. package/dist/business/index.js.map +1 -0
  100. package/dist/business/index.mjs +1675 -0
  101. package/dist/business/index.mjs.map +1 -0
  102. package/dist/calendar/index.d.mts +1325 -0
  103. package/dist/calendar/index.d.ts +1325 -0
  104. package/dist/calendar/index.js +5964 -0
  105. package/dist/calendar/index.js.map +1 -0
  106. package/dist/calendar/index.mjs +5878 -0
  107. package/dist/calendar/index.mjs.map +1 -0
  108. package/dist/calendar/routes/index.d.mts +118 -0
  109. package/dist/calendar/routes/index.d.ts +118 -0
  110. package/dist/calendar/routes/index.js +755 -0
  111. package/dist/calendar/routes/index.js.map +1 -0
  112. package/dist/calendar/routes/index.mjs +747 -0
  113. package/dist/calendar/routes/index.mjs.map +1 -0
  114. package/dist/components/index.d.mts +405 -0
  115. package/dist/components/index.d.ts +405 -0
  116. package/dist/components/index.js +2516 -0
  117. package/dist/components/index.js.map +1 -0
  118. package/dist/components/index.mjs +2396 -0
  119. package/dist/components/index.mjs.map +1 -0
  120. package/dist/drizzle-schema-BNhqj2AZ.d.mts +1114 -0
  121. package/dist/drizzle-schema-BNhqj2AZ.d.ts +1114 -0
  122. package/dist/festivalCard/index.d.mts +76 -0
  123. package/dist/festivalCard/index.d.ts +76 -0
  124. package/dist/festivalCard/index.js +1492 -0
  125. package/dist/festivalCard/index.js.map +1 -0
  126. package/dist/festivalCard/index.mjs +1475 -0
  127. package/dist/festivalCard/index.mjs.map +1 -0
  128. package/dist/festivalCard/routes/index.d.mts +42 -0
  129. package/dist/festivalCard/routes/index.d.ts +42 -0
  130. package/dist/festivalCard/routes/index.js +361 -0
  131. package/dist/festivalCard/routes/index.js.map +1 -0
  132. package/dist/festivalCard/routes/index.mjs +356 -0
  133. package/dist/festivalCard/routes/index.mjs.map +1 -0
  134. package/dist/festivalCard/server/index.d.mts +120 -0
  135. package/dist/festivalCard/server/index.d.ts +120 -0
  136. package/dist/festivalCard/server/index.js +272 -0
  137. package/dist/festivalCard/server/index.js.map +1 -0
  138. package/dist/festivalCard/server/index.mjs +265 -0
  139. package/dist/festivalCard/server/index.mjs.map +1 -0
  140. package/dist/festivalCardService-BFCRhJrq.d.ts +13 -0
  141. package/dist/festivalCardService-GriR2VMc.d.mts +13 -0
  142. package/dist/index-1Ag7IBXN.d.ts +144 -0
  143. package/dist/index-DNKZ7-R_.d.mts +184 -0
  144. package/dist/index-DNKZ7-R_.d.ts +184 -0
  145. package/dist/index-DSel44Ke.d.mts +93 -0
  146. package/dist/index-DSel44Ke.d.ts +93 -0
  147. package/dist/index-DdeZSeTJ.d.mts +144 -0
  148. package/dist/index-DrPcMJPc.d.mts +250 -0
  149. package/dist/index-DrPcMJPc.d.ts +250 -0
  150. package/dist/index.d.mts +5334 -0
  151. package/dist/index.d.ts +5334 -0
  152. package/dist/index.js +18809 -0
  153. package/dist/index.js.map +1 -0
  154. package/dist/index.mjs +18533 -0
  155. package/dist/index.mjs.map +1 -0
  156. package/dist/mikuContest/ui/web/index.d.mts +2 -0
  157. package/dist/mikuContest/ui/web/index.d.ts +2 -0
  158. package/dist/mikuContest/ui/web/index.js +353 -0
  159. package/dist/mikuContest/ui/web/index.js.map +1 -0
  160. package/dist/mikuContest/ui/web/index.mjs +343 -0
  161. package/dist/mikuContest/ui/web/index.mjs.map +1 -0
  162. package/dist/mikuFireworks3D/index.d.mts +268 -0
  163. package/dist/mikuFireworks3D/index.d.ts +268 -0
  164. package/dist/mikuFireworks3D/index.js +1267 -0
  165. package/dist/mikuFireworks3D/index.js.map +1 -0
  166. package/dist/mikuFireworks3D/index.mjs +1228 -0
  167. package/dist/mikuFireworks3D/index.mjs.map +1 -0
  168. package/dist/mikuFusionGame/index.d.mts +117 -0
  169. package/dist/mikuFusionGame/index.d.ts +117 -0
  170. package/dist/mikuFusionGame/index.js +1208 -0
  171. package/dist/mikuFusionGame/index.js.map +1 -0
  172. package/dist/mikuFusionGame/index.mjs +1195 -0
  173. package/dist/mikuFusionGame/index.mjs.map +1 -0
  174. package/dist/mmd/admin/index.d.mts +487 -0
  175. package/dist/mmd/admin/index.d.ts +487 -0
  176. package/dist/mmd/admin/index.js +1058 -0
  177. package/dist/mmd/admin/index.js.map +1 -0
  178. package/dist/mmd/admin/index.mjs +1027 -0
  179. package/dist/mmd/admin/index.mjs.map +1 -0
  180. package/dist/mmd/index.d.mts +2467 -0
  181. package/dist/mmd/index.d.ts +2467 -0
  182. package/dist/mmd/index.js +10119 -0
  183. package/dist/mmd/index.js.map +1 -0
  184. package/dist/mmd/index.mjs +10028 -0
  185. package/dist/mmd/index.mjs.map +1 -0
  186. package/dist/mmd/server/index.d.mts +139 -0
  187. package/dist/mmd/server/index.d.ts +139 -0
  188. package/dist/mmd/server/index.js +424 -0
  189. package/dist/mmd/server/index.js.map +1 -0
  190. package/dist/mmd/server/index.mjs +404 -0
  191. package/dist/mmd/server/index.mjs.map +1 -0
  192. package/dist/music/index.d.mts +74 -0
  193. package/dist/music/index.d.ts +74 -0
  194. package/dist/music/index.js +830 -0
  195. package/dist/music/index.js.map +1 -0
  196. package/dist/music/index.mjs +809 -0
  197. package/dist/music/index.mjs.map +1 -0
  198. package/dist/music/server/index.d.mts +1 -0
  199. package/dist/music/server/index.d.ts +1 -0
  200. package/dist/music/server/index.js +194 -0
  201. package/dist/music/server/index.js.map +1 -0
  202. package/dist/music/server/index.mjs +182 -0
  203. package/dist/music/server/index.mjs.map +1 -0
  204. package/dist/navigation/index.d.mts +93 -0
  205. package/dist/navigation/index.d.ts +93 -0
  206. package/dist/navigation/index.js +453 -0
  207. package/dist/navigation/index.js.map +1 -0
  208. package/dist/navigation/index.mjs +443 -0
  209. package/dist/navigation/index.mjs.map +1 -0
  210. package/dist/portfolio/index.d.mts +66 -0
  211. package/dist/portfolio/index.d.ts +66 -0
  212. package/dist/portfolio/index.js +736 -0
  213. package/dist/portfolio/index.js.map +1 -0
  214. package/dist/portfolio/index.mjs +724 -0
  215. package/dist/portfolio/index.mjs.map +1 -0
  216. package/dist/qqbot/server/index.d.mts +216 -0
  217. package/dist/qqbot/server/index.d.ts +216 -0
  218. package/dist/qqbot/server/index.js +394 -0
  219. package/dist/qqbot/server/index.js.map +1 -0
  220. package/dist/qqbot/server/index.mjs +385 -0
  221. package/dist/qqbot/server/index.mjs.map +1 -0
  222. package/dist/qqbot/ui/web/index.d.mts +10 -0
  223. package/dist/qqbot/ui/web/index.d.ts +10 -0
  224. package/dist/qqbot/ui/web/index.js +105 -0
  225. package/dist/qqbot/ui/web/index.js.map +1 -0
  226. package/dist/qqbot/ui/web/index.mjs +99 -0
  227. package/dist/qqbot/ui/web/index.mjs.map +1 -0
  228. package/dist/screenReceiver/index.d.mts +86 -0
  229. package/dist/screenReceiver/index.d.ts +86 -0
  230. package/dist/screenReceiver/index.js +281 -0
  231. package/dist/screenReceiver/index.js.map +1 -0
  232. package/dist/screenReceiver/index.mjs +273 -0
  233. package/dist/screenReceiver/index.mjs.map +1 -0
  234. package/dist/testYourself/admin/index.d.mts +58 -0
  235. package/dist/testYourself/admin/index.d.ts +58 -0
  236. package/dist/testYourself/admin/index.js +1009 -0
  237. package/dist/testYourself/admin/index.js.map +1 -0
  238. package/dist/testYourself/admin/index.mjs +1002 -0
  239. package/dist/testYourself/admin/index.mjs.map +1 -0
  240. package/dist/testYourself/index.d.mts +53 -0
  241. package/dist/testYourself/index.d.ts +53 -0
  242. package/dist/testYourself/index.js +2551 -0
  243. package/dist/testYourself/index.js.map +1 -0
  244. package/dist/testYourself/index.mjs +2531 -0
  245. package/dist/testYourself/index.mjs.map +1 -0
  246. package/dist/testYourself/server/index.d.mts +1029 -0
  247. package/dist/testYourself/server/index.d.ts +1029 -0
  248. package/dist/testYourself/server/index.js +825 -0
  249. package/dist/testYourself/server/index.js.map +1 -0
  250. package/dist/testYourself/server/index.mjs +816 -0
  251. package/dist/testYourself/server/index.mjs.map +1 -0
  252. package/dist/types-BTiaMsBz.d.mts +292 -0
  253. package/dist/types-DyG3ZV9V.d.mts +270 -0
  254. package/dist/types-DyG3ZV9V.d.ts +270 -0
  255. package/dist/types-ERmJyjx8.d.ts +292 -0
  256. package/dist/types-HorDyIRv.d.mts +303 -0
  257. package/dist/types-HorDyIRv.d.ts +303 -0
  258. package/dist/types-tQfupO6d.d.mts +70 -0
  259. package/dist/types-tQfupO6d.d.ts +70 -0
  260. package/dist/vocaloidBooth/index.d.mts +64 -0
  261. package/dist/vocaloidBooth/index.d.ts +64 -0
  262. package/dist/vocaloidBooth/index.js +376 -0
  263. package/dist/vocaloidBooth/index.js.map +1 -0
  264. package/dist/vocaloidBooth/index.mjs +362 -0
  265. package/dist/vocaloidBooth/index.mjs.map +1 -0
  266. package/dist/vocaloidBooth/server/index.d.mts +111 -0
  267. package/dist/vocaloidBooth/server/index.d.ts +111 -0
  268. package/dist/vocaloidBooth/server/index.js +247 -0
  269. package/dist/vocaloidBooth/server/index.js.map +1 -0
  270. package/dist/vocaloidBooth/server/index.mjs +237 -0
  271. package/dist/vocaloidBooth/server/index.mjs.map +1 -0
  272. package/dist/vocaloidBooth/web/index.d.mts +3 -0
  273. package/dist/vocaloidBooth/web/index.d.ts +3 -0
  274. package/dist/vocaloidBooth/web/index.js +376 -0
  275. package/dist/vocaloidBooth/web/index.js.map +1 -0
  276. package/dist/vocaloidBooth/web/index.mjs +362 -0
  277. package/dist/vocaloidBooth/web/index.mjs.map +1 -0
  278. package/package.json +11 -1
@@ -0,0 +1,1267 @@
1
+ 'use strict';
2
+
3
+ var React3 = require('react');
4
+ var THREE2 = require('three');
5
+
6
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
+
8
+ function _interopNamespace(e) {
9
+ if (e && e.__esModule) return e;
10
+ var n = Object.create(null);
11
+ if (e) {
12
+ Object.keys(e).forEach(function (k) {
13
+ if (k !== 'default') {
14
+ var d = Object.getOwnPropertyDescriptor(e, k);
15
+ Object.defineProperty(n, k, d.get ? d : {
16
+ enumerable: true,
17
+ get: function () { return e[k]; }
18
+ });
19
+ }
20
+ });
21
+ }
22
+ n.default = e;
23
+ return Object.freeze(n);
24
+ }
25
+
26
+ var React3__default = /*#__PURE__*/_interopDefault(React3);
27
+ var THREE2__namespace = /*#__PURE__*/_interopNamespace(THREE2);
28
+
29
+ // src/mikuFireworks3D/components/MikuFireworks3D.tsx
30
+ function DanmakuPanel({ onSend }) {
31
+ const [text, setText] = React3.useState("");
32
+ const emit = () => {
33
+ const value = text.trim();
34
+ if (!value) {
35
+ return;
36
+ }
37
+ onSend(value);
38
+ setText("");
39
+ };
40
+ return /* @__PURE__ */ React3__default.default.createElement("div", { className: "rounded-xl border border-slate-600/40 bg-slate-900/70 p-3 text-slate-100 backdrop-blur-sm" }, /* @__PURE__ */ React3__default.default.createElement("div", { className: "flex gap-2" }, /* @__PURE__ */ React3__default.default.createElement(
41
+ "input",
42
+ {
43
+ type: "text",
44
+ value: text,
45
+ onChange: (event) => setText(event.target.value),
46
+ onKeyDown: (event) => {
47
+ if (event.key === "Enter") {
48
+ emit();
49
+ }
50
+ },
51
+ placeholder: "\u53D1\u9001\u5F39\u5E55\uFF08\u652F\u6301 /miku /avatar /normal\uFF09",
52
+ className: "flex-1 rounded-md border border-slate-600 bg-slate-950 px-2.5 py-2 text-sm text-slate-100 outline-none focus:border-cyan-400"
53
+ }
54
+ ), /* @__PURE__ */ React3__default.default.createElement(
55
+ "button",
56
+ {
57
+ type: "button",
58
+ onClick: emit,
59
+ className: "rounded-md bg-cyan-400 px-3 py-2 text-sm font-medium text-slate-950 hover:bg-cyan-300"
60
+ },
61
+ "\u53D1\u9001"
62
+ )));
63
+ }
64
+ function FireworksCanvas({ canvasRef }) {
65
+ return /* @__PURE__ */ React3__default.default.createElement(
66
+ "canvas",
67
+ {
68
+ ref: canvasRef,
69
+ className: "absolute inset-0 h-full w-full",
70
+ style: {
71
+ background: "radial-gradient(circle at 20% 20%, rgba(57,197,187,0.15) 0%, rgba(6,8,22,1) 45%, rgba(4,6,15,1) 100%)"
72
+ }
73
+ }
74
+ );
75
+ }
76
+
77
+ // src/mikuFireworks3D/constants.ts
78
+ var DEFAULT_MAX_PARTICLES = 5e3;
79
+ var DEFAULT_MAX_ACTIVE_FIREWORKS = 12;
80
+ var FIREWORK_KIND_LABELS = {
81
+ normal: "\u666E\u901A\u70DF\u82B1",
82
+ miku: "MIKU \u4E3B\u9898",
83
+ avatar: "\u5934\u50CF\u70DF\u82B1"
84
+ };
85
+ var MIKU_PALETTE = ["#39c5bb", "#66e3db", "#7ad8ff", "#b0fff8", "#8cf7e0"];
86
+ var NORMAL_PALETTE = ["#ffe066", "#ff6b6b", "#4dabf7", "#c77dff", "#69db7c"];
87
+ var DANMAKU_MAX_LENGTH = 32;
88
+ var DANMAKU_TRACK_COUNT = 8;
89
+
90
+ // src/mikuFireworks3D/components/FireworksControlPanel.tsx
91
+ function FireworksControlPanel({
92
+ selectedKind,
93
+ onKindChange,
94
+ autoLaunchOnDanmaku,
95
+ onAutoLaunchChange,
96
+ avatarUrl,
97
+ onAvatarUrlChange,
98
+ onLaunch,
99
+ fps,
100
+ realtimeConnected,
101
+ onlineCount
102
+ }) {
103
+ return /* @__PURE__ */ React3__default.default.createElement("div", { className: "rounded-xl border border-slate-600/40 bg-slate-900/70 p-3 text-slate-100 backdrop-blur-sm" }, /* @__PURE__ */ React3__default.default.createElement("div", { className: "mb-3 flex flex-wrap items-center gap-2" }, Object.keys(FIREWORK_KIND_LABELS).map((kind) => {
104
+ const active = kind === selectedKind;
105
+ return /* @__PURE__ */ React3__default.default.createElement(
106
+ "button",
107
+ {
108
+ key: kind,
109
+ type: "button",
110
+ onClick: () => onKindChange(kind),
111
+ className: `rounded-md px-3 py-1.5 text-sm transition ${active ? "bg-cyan-500 text-slate-950" : "bg-slate-700/70 hover:bg-slate-600/80"}`
112
+ },
113
+ FIREWORK_KIND_LABELS[kind]
114
+ );
115
+ }), /* @__PURE__ */ React3__default.default.createElement(
116
+ "button",
117
+ {
118
+ type: "button",
119
+ onClick: onLaunch,
120
+ className: "ml-auto rounded-md bg-emerald-400 px-3 py-1.5 text-sm font-medium text-slate-900 hover:bg-emerald-300"
121
+ },
122
+ "\u53D1\u5C04\u70DF\u82B1"
123
+ )), /* @__PURE__ */ React3__default.default.createElement("div", { className: "grid gap-2 md:grid-cols-2" }, /* @__PURE__ */ React3__default.default.createElement("label", { className: "flex items-center gap-2 text-sm" }, /* @__PURE__ */ React3__default.default.createElement(
124
+ "input",
125
+ {
126
+ type: "checkbox",
127
+ checked: autoLaunchOnDanmaku,
128
+ onChange: (event) => onAutoLaunchChange(event.target.checked)
129
+ }
130
+ ), "\u53D1\u9001\u5F39\u5E55\u540E\u81EA\u52A8\u653E\u70DF\u82B1"), /* @__PURE__ */ React3__default.default.createElement("div", { className: "text-sm text-slate-300" }, "FPS: ", fps), typeof realtimeConnected === "boolean" ? /* @__PURE__ */ React3__default.default.createElement("div", { className: "text-sm text-slate-300" }, "\u5B9E\u65F6\u72B6\u6001: ", realtimeConnected ? "\u5DF2\u8FDE\u63A5" : "\u672A\u8FDE\u63A5", typeof onlineCount === "number" ? ` \xB7 \u5728\u7EBF ${onlineCount}` : "") : null), selectedKind === "avatar" ? /* @__PURE__ */ React3__default.default.createElement("div", { className: "mt-2" }, /* @__PURE__ */ React3__default.default.createElement(
131
+ "input",
132
+ {
133
+ type: "url",
134
+ value: avatarUrl,
135
+ onChange: (event) => onAvatarUrlChange(event.target.value),
136
+ placeholder: "\u5934\u50CF\u56FE\u7247 URL\uFF08\u7528\u4E8E\u5934\u50CF\u70DF\u82B1\uFF09",
137
+ className: "w-full rounded-md border border-slate-600 bg-slate-950 px-2.5 py-2 text-sm text-slate-100 outline-none focus:border-cyan-400"
138
+ }
139
+ )) : null);
140
+ }
141
+ function useDanmakuController(options) {
142
+ const [items, setItems] = React3.useState([]);
143
+ const cursorRef = React3.useRef(0);
144
+ const removeItem = React3.useCallback((id) => {
145
+ setItems((prev) => prev.filter((item) => item.id !== id));
146
+ }, []);
147
+ const addIncoming = React3.useCallback((message) => {
148
+ setItems((prev) => {
149
+ const track = cursorRef.current % DANMAKU_TRACK_COUNT;
150
+ const item = {
151
+ ...message,
152
+ track,
153
+ durationMs: 8e3 + Math.floor(Math.random() * 2800)
154
+ };
155
+ return [...prev.slice(-40), item];
156
+ });
157
+ cursorRef.current += 1;
158
+ }, []);
159
+ const send = React3.useCallback(
160
+ (text, color, sendOptions) => {
161
+ const trimmed = text.trim();
162
+ if (!trimmed) {
163
+ return null;
164
+ }
165
+ const { content, launchKind } = parseCommand(trimmed);
166
+ const safeText = content.slice(0, DANMAKU_MAX_LENGTH);
167
+ if (!safeText) {
168
+ return null;
169
+ }
170
+ const message = {
171
+ id: `${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
172
+ text: safeText,
173
+ color,
174
+ timestamp: Date.now()
175
+ };
176
+ const optimistic = sendOptions?.optimistic ?? true;
177
+ if (optimistic) {
178
+ addIncoming(message);
179
+ }
180
+ options?.onSend?.(message);
181
+ return {
182
+ message,
183
+ launchKind
184
+ };
185
+ },
186
+ [addIncoming, options]
187
+ );
188
+ return React3.useMemo(
189
+ () => ({
190
+ items,
191
+ send,
192
+ addIncoming,
193
+ removeItem
194
+ }),
195
+ [addIncoming, items, removeItem, send]
196
+ );
197
+ }
198
+ function parseCommand(text) {
199
+ if (text.startsWith("/miku ")) {
200
+ return { launchKind: "miku", content: text.replace("/miku ", "").trim() };
201
+ }
202
+ if (text === "/miku") {
203
+ return { launchKind: "miku", content: "MIKU!" };
204
+ }
205
+ if (text.startsWith("/avatar ")) {
206
+ return { launchKind: "avatar", content: text.replace("/avatar ", "").trim() };
207
+ }
208
+ if (text === "/avatar") {
209
+ return { launchKind: "avatar", content: "Avatar Firework!" };
210
+ }
211
+ if (text.startsWith("/normal ")) {
212
+ return { launchKind: "normal", content: text.replace("/normal ", "").trim() };
213
+ }
214
+ if (text === "/normal") {
215
+ return { launchKind: "normal", content: "Fireworks!" };
216
+ }
217
+ return { content: text };
218
+ }
219
+ function createCircularSpriteTexture() {
220
+ const size = 64;
221
+ const canvas = document.createElement("canvas");
222
+ canvas.width = size;
223
+ canvas.height = size;
224
+ const ctx = canvas.getContext("2d");
225
+ if (!ctx) {
226
+ return new THREE2__namespace.CanvasTexture(canvas);
227
+ }
228
+ const center = size / 2;
229
+ const gradient = ctx.createRadialGradient(center, center, 2, center, center, center);
230
+ gradient.addColorStop(0, "rgba(255,255,255,1)");
231
+ gradient.addColorStop(0.4, "rgba(255,255,255,0.9)");
232
+ gradient.addColorStop(1, "rgba(255,255,255,0)");
233
+ ctx.fillStyle = gradient;
234
+ ctx.fillRect(0, 0, size, size);
235
+ const texture = new THREE2__namespace.CanvasTexture(canvas);
236
+ texture.needsUpdate = true;
237
+ return texture;
238
+ }
239
+
240
+ // src/mikuFireworks3D/utils/colorPalettes.ts
241
+ function pickPalette(kind) {
242
+ if (kind === "miku") {
243
+ return MIKU_PALETTE;
244
+ }
245
+ return NORMAL_PALETTE;
246
+ }
247
+ function pickRandomColor(colors) {
248
+ if (colors.length === 0) {
249
+ return "#ffffff";
250
+ }
251
+ const index = Math.floor(Math.random() * colors.length);
252
+ return colors[index] || "#ffffff";
253
+ }
254
+
255
+ // src/mikuFireworks3D/utils/avatarSprite.ts
256
+ async function sampleAvatarPoints(avatarUrl, sampleStep = 4, maxPoints = 500) {
257
+ const image = await loadImage(avatarUrl);
258
+ const size = 64;
259
+ const canvas = document.createElement("canvas");
260
+ canvas.width = size;
261
+ canvas.height = size;
262
+ const ctx = canvas.getContext("2d");
263
+ if (!ctx) {
264
+ return [];
265
+ }
266
+ ctx.clearRect(0, 0, size, size);
267
+ ctx.drawImage(image, 0, 0, size, size);
268
+ const { data } = ctx.getImageData(0, 0, size, size);
269
+ const points = [];
270
+ for (let y = 0; y < size; y += sampleStep) {
271
+ for (let x = 0; x < size; x += sampleStep) {
272
+ const index = (y * size + x) * 4;
273
+ const alpha = data[index + 3] ?? 0;
274
+ if (alpha < 24) {
275
+ continue;
276
+ }
277
+ const r = data[index] ?? 0;
278
+ const g = data[index + 1] ?? 0;
279
+ const b = data[index + 2] ?? 0;
280
+ const brightness = (r + g + b) / (3 * 255);
281
+ points.push({ x: x - size / 2, y: size / 2 - y, brightness });
282
+ if (points.length >= maxPoints) {
283
+ return points;
284
+ }
285
+ }
286
+ }
287
+ return points;
288
+ }
289
+ function loadImage(url) {
290
+ return new Promise((resolve, reject) => {
291
+ const image = new window.Image();
292
+ image.crossOrigin = "anonymous";
293
+ image.onload = () => resolve(image);
294
+ image.onerror = () => reject(new Error("Failed to load avatar image."));
295
+ image.src = url;
296
+ });
297
+ }
298
+
299
+ // src/mikuFireworks3D/engine/patterns/avatar.ts
300
+ async function createAvatarSeeds(avatarUrl, fallbackColor) {
301
+ const points = await sampleAvatarPoints(avatarUrl);
302
+ if (points.length === 0) {
303
+ return [];
304
+ }
305
+ return points.map((point) => {
306
+ const spread = 0.22;
307
+ return {
308
+ x: 0,
309
+ y: 0,
310
+ z: 0,
311
+ vx: point.x * spread + (Math.random() - 0.5) * 2.4,
312
+ vy: point.y * spread + Math.random() * 2.2,
313
+ vz: (Math.random() - 0.5) * 3.5,
314
+ life: 1.1 + point.brightness * 1.6,
315
+ color: fallbackColor
316
+ };
317
+ });
318
+ }
319
+
320
+ // src/mikuFireworks3D/engine/patterns/miku.ts
321
+ function createMikuSeeds(count) {
322
+ const seeds = [];
323
+ for (let i = 0; i < count; i += 1) {
324
+ const ratio = i / Math.max(count - 1, 1);
325
+ const angle = ratio * Math.PI * 2 * 2;
326
+ const radial = 7 + Math.random() * 9;
327
+ const spiralBoost = 3 + Math.random() * 4;
328
+ seeds.push({
329
+ x: 0,
330
+ y: 0,
331
+ z: 0,
332
+ vx: Math.cos(angle) * radial,
333
+ vy: Math.sin(angle * 0.5) * spiralBoost + 7,
334
+ vz: Math.sin(angle) * radial,
335
+ life: 1.2 + Math.random() * 1.5,
336
+ color: pickRandomColor(MIKU_PALETTE)
337
+ });
338
+ }
339
+ return seeds;
340
+ }
341
+
342
+ // src/mikuFireworks3D/engine/patterns/normal.ts
343
+ function createNormalSeeds(count, color) {
344
+ const seeds = [];
345
+ for (let i = 0; i < count; i += 1) {
346
+ const theta = Math.random() * Math.PI * 2;
347
+ const phi = Math.acos(2 * Math.random() - 1);
348
+ const speed = 8 + Math.random() * 12;
349
+ seeds.push({
350
+ x: 0,
351
+ y: 0,
352
+ z: 0,
353
+ vx: speed * Math.sin(phi) * Math.cos(theta),
354
+ vy: speed * Math.cos(phi),
355
+ vz: speed * Math.sin(phi) * Math.sin(theta),
356
+ life: 1 + Math.random() * 1.6,
357
+ color
358
+ });
359
+ }
360
+ return seeds;
361
+ }
362
+
363
+ // src/mikuFireworks3D/engine/emitters.ts
364
+ async function createSeedParticles(options) {
365
+ const palette = pickPalette(options.kind);
366
+ const color = options.color ?? pickRandomColor(palette);
367
+ if (options.kind === "miku") {
368
+ return createMikuSeeds(options.count);
369
+ }
370
+ if (options.kind === "avatar" && options.avatarUrl) {
371
+ const avatarSeeds = await createAvatarSeeds(options.avatarUrl, color);
372
+ if (avatarSeeds.length > 0) {
373
+ return avatarSeeds;
374
+ }
375
+ }
376
+ return createNormalSeeds(options.count, color);
377
+ }
378
+
379
+ // src/mikuFireworks3D/engine/particlePool.ts
380
+ var ParticlePool = class {
381
+ constructor() {
382
+ this.pool = [];
383
+ }
384
+ acquire() {
385
+ const reused = this.pool.pop();
386
+ if (reused) {
387
+ return reused;
388
+ }
389
+ return {
390
+ x: 0,
391
+ y: 0,
392
+ z: 0,
393
+ vx: 0,
394
+ vy: 0,
395
+ vz: 0,
396
+ life: 0,
397
+ maxLife: 1,
398
+ r: 1,
399
+ g: 1,
400
+ b: 1
401
+ };
402
+ }
403
+ release(particle) {
404
+ this.pool.push(particle);
405
+ }
406
+ };
407
+
408
+ // src/mikuFireworks3D/engine/postfx.ts
409
+ function evaluateDegradePolicy(fps) {
410
+ if (fps < 24) {
411
+ return { shouldDegrade: true, recommendedParticleScale: 0.65 };
412
+ }
413
+ if (fps < 34) {
414
+ return { shouldDegrade: true, recommendedParticleScale: 0.82 };
415
+ }
416
+ return { shouldDegrade: false, recommendedParticleScale: 1 };
417
+ }
418
+
419
+ // src/mikuFireworks3D/engine/FireworksEngine.ts
420
+ var FireworksEngine = class {
421
+ constructor(init) {
422
+ this.pool = new ParticlePool();
423
+ this.bursts = [];
424
+ this.animationFrameId = null;
425
+ this.lastTick = 0;
426
+ this.fpsWindow = { frames: 0, elapsed: 0, fps: 60, particleScale: 1 };
427
+ this.resizeObserver = null;
428
+ this.loop = () => {
429
+ const now = window.performance.now();
430
+ const dt = Math.min((now - this.lastTick) / 1e3, 0.05);
431
+ this.lastTick = now;
432
+ this.update(dt);
433
+ this.renderer.render(this.scene, this.camera);
434
+ this.animationFrameId = window.requestAnimationFrame(this.loop);
435
+ };
436
+ this.canvas = init.canvas;
437
+ this.container = init.container;
438
+ this.maxParticles = init.options?.maxParticles ?? DEFAULT_MAX_PARTICLES;
439
+ this.maxActiveFireworks = init.options?.maxActiveFireworks ?? DEFAULT_MAX_ACTIVE_FIREWORKS;
440
+ this.onError = init.options?.onError;
441
+ this.onFpsReport = init.options?.onFpsReport;
442
+ this.scene = new THREE2__namespace.Scene();
443
+ this.scene.background = new THREE2__namespace.Color("#060816");
444
+ this.camera = new THREE2__namespace.PerspectiveCamera(50, 1, 0.1, 1e3);
445
+ this.camera.position.set(0, 0, 45);
446
+ this.renderer = new THREE2__namespace.WebGLRenderer({
447
+ canvas: this.canvas,
448
+ alpha: true,
449
+ antialias: true,
450
+ powerPreference: "high-performance"
451
+ });
452
+ this.renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
453
+ this.spriteTexture = createCircularSpriteTexture();
454
+ this.attachResizeObserver();
455
+ this.resize();
456
+ }
457
+ start() {
458
+ if (this.animationFrameId != null) {
459
+ return;
460
+ }
461
+ this.lastTick = window.performance.now();
462
+ this.loop();
463
+ }
464
+ stop() {
465
+ if (this.animationFrameId != null) {
466
+ window.cancelAnimationFrame(this.animationFrameId);
467
+ this.animationFrameId = null;
468
+ }
469
+ }
470
+ async launch(payload) {
471
+ try {
472
+ this.enforceBurstCap();
473
+ const particleBudget = Math.max(80, Math.floor(280 * this.fpsWindow.particleScale));
474
+ const seeds = await createSeedParticles({
475
+ kind: payload.kind,
476
+ count: particleBudget,
477
+ color: payload.color,
478
+ avatarUrl: payload.avatarUrl
479
+ });
480
+ if (seeds.length === 0) {
481
+ return;
482
+ }
483
+ const launchPosition = payload.position ?? {
484
+ x: (Math.random() - 0.5) * 18,
485
+ y: -4 + Math.random() * 12,
486
+ z: (Math.random() - 0.5) * 4
487
+ };
488
+ const particles = [];
489
+ const positions = new Float32Array(seeds.length * 3);
490
+ const colors = new Float32Array(seeds.length * 3);
491
+ const colorHelper = new THREE2__namespace.Color();
492
+ for (let i = 0; i < seeds.length; i += 1) {
493
+ const seed = seeds[i];
494
+ if (!seed) {
495
+ continue;
496
+ }
497
+ const particle = this.pool.acquire();
498
+ particle.x = launchPosition.x + seed.x;
499
+ particle.y = launchPosition.y + seed.y;
500
+ particle.z = launchPosition.z + seed.z;
501
+ particle.vx = seed.vx;
502
+ particle.vy = seed.vy;
503
+ particle.vz = seed.vz;
504
+ particle.life = seed.life;
505
+ particle.maxLife = seed.life;
506
+ colorHelper.set(seed.color);
507
+ particle.r = colorHelper.r;
508
+ particle.g = colorHelper.g;
509
+ particle.b = colorHelper.b;
510
+ particles.push(particle);
511
+ const offset = i * 3;
512
+ positions[offset] = particle.x;
513
+ positions[offset + 1] = particle.y;
514
+ positions[offset + 2] = particle.z;
515
+ colors[offset] = particle.r;
516
+ colors[offset + 1] = particle.g;
517
+ colors[offset + 2] = particle.b;
518
+ }
519
+ if (this.totalParticleCount() + particles.length > this.maxParticles) {
520
+ this.releaseParticles(particles);
521
+ return;
522
+ }
523
+ const geometry = new THREE2__namespace.BufferGeometry();
524
+ geometry.setAttribute("position", new THREE2__namespace.BufferAttribute(positions, 3));
525
+ geometry.setAttribute("color", new THREE2__namespace.BufferAttribute(colors, 3));
526
+ const material = new THREE2__namespace.PointsMaterial({
527
+ size: payload.kind === "miku" ? 0.42 : 0.36,
528
+ vertexColors: true,
529
+ map: this.spriteTexture,
530
+ transparent: true,
531
+ opacity: 1,
532
+ depthWrite: false,
533
+ blending: THREE2__namespace.AdditiveBlending
534
+ });
535
+ const points = new THREE2__namespace.Points(geometry, material);
536
+ this.scene.add(points);
537
+ const burst = {
538
+ id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
539
+ points,
540
+ geometry,
541
+ material,
542
+ positions,
543
+ colors,
544
+ particles
545
+ };
546
+ this.bursts.push(burst);
547
+ } catch (error) {
548
+ this.onError?.(error instanceof Error ? error : new Error("Failed to launch firework."));
549
+ }
550
+ }
551
+ dispose() {
552
+ this.stop();
553
+ if (this.resizeObserver) {
554
+ this.resizeObserver.disconnect();
555
+ this.resizeObserver = null;
556
+ }
557
+ for (const burst of this.bursts) {
558
+ this.destroyBurst(burst);
559
+ }
560
+ this.bursts.length = 0;
561
+ this.spriteTexture.dispose();
562
+ this.renderer.dispose();
563
+ }
564
+ update(dt) {
565
+ const gravity = -8.8;
566
+ for (let b = this.bursts.length - 1; b >= 0; b -= 1) {
567
+ const burst = this.bursts[b];
568
+ if (!burst) {
569
+ continue;
570
+ }
571
+ let alive = 0;
572
+ for (let i = 0; i < burst.particles.length; i += 1) {
573
+ const particle = burst.particles[i];
574
+ if (!particle) {
575
+ continue;
576
+ }
577
+ particle.life -= dt;
578
+ if (particle.life <= 0) {
579
+ continue;
580
+ }
581
+ particle.vx *= 0.992;
582
+ particle.vy = particle.vy * 0.992 + gravity * dt;
583
+ particle.vz *= 0.992;
584
+ particle.x += particle.vx * dt;
585
+ particle.y += particle.vy * dt;
586
+ particle.z += particle.vz * dt;
587
+ const idx = i * 3;
588
+ burst.positions[idx] = particle.x;
589
+ burst.positions[idx + 1] = particle.y;
590
+ burst.positions[idx + 2] = particle.z;
591
+ const alpha = Math.max(particle.life / particle.maxLife, 0);
592
+ burst.colors[idx] = particle.r * alpha;
593
+ burst.colors[idx + 1] = particle.g * alpha;
594
+ burst.colors[idx + 2] = particle.b * alpha;
595
+ alive += 1;
596
+ }
597
+ const positionAttr = burst.geometry.getAttribute("position");
598
+ const colorAttr = burst.geometry.getAttribute("color");
599
+ positionAttr.needsUpdate = true;
600
+ colorAttr.needsUpdate = true;
601
+ burst.material.opacity = Math.min(1, 0.22 + alive / Math.max(burst.particles.length, 1));
602
+ if (alive === 0) {
603
+ this.bursts.splice(b, 1);
604
+ this.destroyBurst(burst);
605
+ }
606
+ }
607
+ this.updateFpsStats(dt);
608
+ }
609
+ updateFpsStats(dt) {
610
+ this.fpsWindow.frames += 1;
611
+ this.fpsWindow.elapsed += dt;
612
+ if (this.fpsWindow.elapsed < 0.6) {
613
+ return;
614
+ }
615
+ const fps = this.fpsWindow.frames / this.fpsWindow.elapsed;
616
+ this.fpsWindow.fps = fps;
617
+ const policy = evaluateDegradePolicy(fps);
618
+ this.fpsWindow.particleScale = policy.recommendedParticleScale;
619
+ this.onFpsReport?.(Math.round(fps));
620
+ this.fpsWindow.frames = 0;
621
+ this.fpsWindow.elapsed = 0;
622
+ }
623
+ totalParticleCount() {
624
+ return this.bursts.reduce((sum, burst) => sum + burst.particles.length, 0);
625
+ }
626
+ enforceBurstCap() {
627
+ while (this.bursts.length >= this.maxActiveFireworks) {
628
+ const burst = this.bursts.shift();
629
+ if (!burst) {
630
+ break;
631
+ }
632
+ this.destroyBurst(burst);
633
+ }
634
+ }
635
+ destroyBurst(burst) {
636
+ this.scene.remove(burst.points);
637
+ burst.geometry.dispose();
638
+ burst.material.dispose();
639
+ this.releaseParticles(burst.particles);
640
+ }
641
+ releaseParticles(particles) {
642
+ for (const particle of particles) {
643
+ this.pool.release(particle);
644
+ }
645
+ }
646
+ attachResizeObserver() {
647
+ this.resizeObserver = new ResizeObserver(() => this.resize());
648
+ this.resizeObserver.observe(this.container);
649
+ }
650
+ resize() {
651
+ const width = Math.max(1, this.container.clientWidth);
652
+ const height = Math.max(1, this.container.clientHeight);
653
+ this.camera.aspect = width / height;
654
+ this.camera.updateProjectionMatrix();
655
+ this.renderer.setSize(width, height, false);
656
+ }
657
+ };
658
+
659
+ // src/mikuFireworks3D/hooks/useFireworksEngine.ts
660
+ function useFireworksEngine(options) {
661
+ const containerRef = React3.useRef(null);
662
+ const canvasRef = React3.useRef(null);
663
+ const engineRef = React3.useRef(null);
664
+ const pendingLaunchesRef = React3.useRef([]);
665
+ const [fps, setFps] = React3.useState(60);
666
+ const [engineReady, setEngineReady] = React3.useState(false);
667
+ const [pendingLaunchCount, setPendingLaunchCount] = React3.useState(0);
668
+ const { maxParticles, maxActiveFireworks, onError, onFpsReport, onLaunch } = options || {};
669
+ React3.useEffect(() => {
670
+ if (!containerRef.current || !canvasRef.current) {
671
+ return;
672
+ }
673
+ const engine = new FireworksEngine({
674
+ container: containerRef.current,
675
+ canvas: canvasRef.current,
676
+ options: {
677
+ maxParticles,
678
+ maxActiveFireworks,
679
+ onError,
680
+ onFpsReport: (nextFps) => {
681
+ setFps(nextFps);
682
+ onFpsReport?.(nextFps);
683
+ }
684
+ }
685
+ });
686
+ engine.start();
687
+ engineRef.current = engine;
688
+ setEngineReady(true);
689
+ if (pendingLaunchesRef.current.length > 0) {
690
+ const pending = [...pendingLaunchesRef.current];
691
+ pendingLaunchesRef.current = [];
692
+ setPendingLaunchCount(0);
693
+ pending.forEach((payload) => {
694
+ void engine.launch(payload);
695
+ });
696
+ }
697
+ return () => {
698
+ engineRef.current?.dispose();
699
+ engineRef.current = null;
700
+ pendingLaunchesRef.current = [];
701
+ setPendingLaunchCount(0);
702
+ setEngineReady(false);
703
+ };
704
+ }, [maxParticles, maxActiveFireworks, onError, onFpsReport]);
705
+ const launch = React3.useCallback(
706
+ (payload) => {
707
+ if (!engineRef.current) {
708
+ pendingLaunchesRef.current.push(payload);
709
+ if (pendingLaunchesRef.current.length > 120) {
710
+ pendingLaunchesRef.current.splice(0, pendingLaunchesRef.current.length - 120);
711
+ }
712
+ setPendingLaunchCount(pendingLaunchesRef.current.length);
713
+ } else {
714
+ void engineRef.current.launch(payload);
715
+ }
716
+ onLaunch?.(payload);
717
+ },
718
+ [onLaunch]
719
+ );
720
+ const api = React3.useMemo(
721
+ () => ({
722
+ containerRef,
723
+ canvasRef,
724
+ launch,
725
+ fps,
726
+ engineReady,
727
+ pendingLaunchCount
728
+ }),
729
+ [engineReady, fps, launch, pendingLaunchCount]
730
+ );
731
+ return api;
732
+ }
733
+
734
+ // src/mikuFireworks3D/client/WebSocketTransport.ts
735
+ var WebSocketTransport = class {
736
+ constructor(config, callbacks) {
737
+ this.socket = null;
738
+ this.reconnectTimer = null;
739
+ this.isManualClose = false;
740
+ this.pendingQueue = [];
741
+ this.config = config;
742
+ this.callbacks = callbacks || {};
743
+ this.state = {
744
+ connected: false,
745
+ joined: false,
746
+ onlineCount: 0,
747
+ roomId: config.roomId
748
+ };
749
+ }
750
+ connect() {
751
+ if (this.socket && (this.socket.readyState === window.WebSocket.OPEN || this.socket.readyState === window.WebSocket.CONNECTING)) {
752
+ return;
753
+ }
754
+ this.isManualClose = false;
755
+ try {
756
+ this.socket = this.config.protocols ? new window.WebSocket(this.config.serverUrl, this.config.protocols) : new window.WebSocket(this.config.serverUrl);
757
+ this.socket.binaryType = "arraybuffer";
758
+ } catch {
759
+ this.callbacks.onError?.(new Error("Failed to create WebSocket connection."));
760
+ return;
761
+ }
762
+ this.socket.onopen = () => {
763
+ this.updateState({ connected: true, joined: false });
764
+ this.send({
765
+ type: "join",
766
+ roomId: this.config.roomId,
767
+ user: this.config.user
768
+ });
769
+ };
770
+ this.socket.onmessage = (event) => {
771
+ const parsed = parseServerMessage(event.data);
772
+ if (!parsed) {
773
+ return;
774
+ }
775
+ this.handleServerMessage(parsed);
776
+ };
777
+ this.socket.onerror = () => {
778
+ this.callbacks.onError?.(new Error("WebSocket transport error."));
779
+ };
780
+ this.socket.onclose = () => {
781
+ this.updateState({ connected: false, joined: false });
782
+ this.scheduleReconnect();
783
+ };
784
+ }
785
+ disconnect() {
786
+ this.isManualClose = true;
787
+ this.pendingQueue.length = 0;
788
+ if (this.reconnectTimer != null) {
789
+ window.clearTimeout(this.reconnectTimer);
790
+ this.reconnectTimer = null;
791
+ }
792
+ if (!this.socket) {
793
+ return;
794
+ }
795
+ this.send({ type: "leave" });
796
+ this.socket.close();
797
+ this.socket = null;
798
+ }
799
+ sendDanmaku(payload) {
800
+ this.send({
801
+ type: "danmaku.send",
802
+ payload
803
+ });
804
+ }
805
+ sendFirework(payload) {
806
+ this.send({
807
+ type: "firework.launch",
808
+ payload
809
+ });
810
+ }
811
+ getState() {
812
+ return this.state;
813
+ }
814
+ send(message) {
815
+ if (!this.socket || this.socket.readyState !== window.WebSocket.OPEN) {
816
+ if (message.type === "danmaku.send" || message.type === "firework.launch") {
817
+ this.pendingQueue.push(message);
818
+ }
819
+ return;
820
+ }
821
+ if ((message.type === "danmaku.send" || message.type === "firework.launch") && !this.state.joined) {
822
+ this.pendingQueue.push(message);
823
+ return;
824
+ }
825
+ this.socket.send(JSON.stringify(message));
826
+ }
827
+ updateState(partial) {
828
+ this.state = {
829
+ ...this.state,
830
+ ...partial
831
+ };
832
+ this.callbacks.onStateChange?.(this.state);
833
+ }
834
+ handleServerMessage(message) {
835
+ if (message.type === "joined") {
836
+ this.updateState({ roomId: message.roomId, onlineCount: message.onlineCount, joined: true });
837
+ this.flushPendingQueue();
838
+ return;
839
+ }
840
+ if (message.type === "room.user_joined" || message.type === "room.user_left") {
841
+ this.updateState({ onlineCount: message.onlineCount, roomId: message.roomId, joined: true });
842
+ this.flushPendingQueue();
843
+ return;
844
+ }
845
+ if (message.type === "room.snapshot") {
846
+ this.updateState({ roomId: message.roomId, onlineCount: message.users.length, joined: true });
847
+ this.flushPendingQueue();
848
+ this.callbacks.onSnapshot?.(message);
849
+ return;
850
+ }
851
+ if (message.type === "danmaku.broadcast") {
852
+ if (!this.state.joined) {
853
+ this.updateState({ joined: true, roomId: message.roomId });
854
+ this.flushPendingQueue();
855
+ }
856
+ this.callbacks.onDanmakuBroadcast?.(message.event);
857
+ return;
858
+ }
859
+ if (message.type === "firework.broadcast") {
860
+ if (!this.state.joined) {
861
+ this.updateState({ joined: true, roomId: message.roomId });
862
+ this.flushPendingQueue();
863
+ }
864
+ this.callbacks.onFireworkBroadcast?.(message.event);
865
+ return;
866
+ }
867
+ if (message.type === "error") {
868
+ this.callbacks.onError?.(new Error(`${message.code}: ${message.message}`));
869
+ }
870
+ }
871
+ scheduleReconnect() {
872
+ const reconnect = this.config.reconnect ?? true;
873
+ if (this.isManualClose || !reconnect) {
874
+ return;
875
+ }
876
+ if (this.reconnectTimer != null) {
877
+ return;
878
+ }
879
+ const delay = this.config.reconnectIntervalMs ?? 1500;
880
+ this.reconnectTimer = window.setTimeout(() => {
881
+ this.reconnectTimer = null;
882
+ this.connect();
883
+ }, delay);
884
+ }
885
+ flushPendingQueue() {
886
+ if (!this.socket || this.socket.readyState !== window.WebSocket.OPEN || !this.state.joined) {
887
+ return;
888
+ }
889
+ while (this.pendingQueue.length > 0) {
890
+ const message = this.pendingQueue.shift();
891
+ if (!message) {
892
+ break;
893
+ }
894
+ this.socket.send(JSON.stringify(message));
895
+ }
896
+ }
897
+ };
898
+ function parseServerMessage(raw) {
899
+ const text = decodeMessage(raw);
900
+ if (!text) {
901
+ return null;
902
+ }
903
+ try {
904
+ return JSON.parse(text);
905
+ } catch {
906
+ return null;
907
+ }
908
+ }
909
+ function decodeMessage(raw) {
910
+ if (typeof raw === "string") {
911
+ return raw;
912
+ }
913
+ if (raw instanceof ArrayBuffer) {
914
+ return new TextDecoder().decode(new Uint8Array(raw));
915
+ }
916
+ if (ArrayBuffer.isView(raw)) {
917
+ return new TextDecoder().decode(raw);
918
+ }
919
+ return null;
920
+ }
921
+
922
+ // src/mikuFireworks3D/hooks/useFireworksRealtime.ts
923
+ function useFireworksRealtime(options) {
924
+ const { config, enabled, onDanmakuBroadcast, onFireworkBroadcast, onSnapshot, onError, onStateChange } = options;
925
+ const transportRef = React3.useRef(null);
926
+ const callbackRef = React3.useRef({
927
+ onDanmakuBroadcast,
928
+ onFireworkBroadcast,
929
+ onSnapshot,
930
+ onError,
931
+ onStateChange
932
+ });
933
+ const serverUrl = config?.serverUrl ?? "";
934
+ const roomId = config?.roomId ?? "";
935
+ const userId = config?.user.userId ?? "";
936
+ const nickname = config?.user.nickname ?? "";
937
+ const avatarUrl = config?.user.avatarUrl ?? "";
938
+ const reconnect = config?.reconnect ?? true;
939
+ const reconnectIntervalMs = config?.reconnectIntervalMs ?? 1500;
940
+ const [state, setState] = React3.useState({
941
+ connected: false,
942
+ joined: false,
943
+ onlineCount: 0,
944
+ roomId
945
+ });
946
+ React3.useEffect(() => {
947
+ callbackRef.current = {
948
+ onDanmakuBroadcast,
949
+ onFireworkBroadcast,
950
+ onSnapshot,
951
+ onError,
952
+ onStateChange
953
+ };
954
+ }, [onDanmakuBroadcast, onError, onFireworkBroadcast, onSnapshot, onStateChange]);
955
+ const normalizedConfig = React3.useMemo(() => {
956
+ if (!serverUrl || !roomId || !userId) {
957
+ return void 0;
958
+ }
959
+ const protocols = Array.isArray(config?.protocols) ? [...config.protocols] : config?.protocols;
960
+ return {
961
+ serverUrl,
962
+ roomId,
963
+ user: {
964
+ userId,
965
+ nickname: nickname || void 0,
966
+ avatarUrl: avatarUrl || void 0
967
+ },
968
+ protocols,
969
+ reconnect,
970
+ reconnectIntervalMs
971
+ };
972
+ }, [avatarUrl, config?.protocols, nickname, reconnect, reconnectIntervalMs, roomId, serverUrl, userId]);
973
+ React3.useEffect(() => {
974
+ if (!enabled || !normalizedConfig) {
975
+ transportRef.current?.disconnect();
976
+ transportRef.current = null;
977
+ setState({
978
+ connected: false,
979
+ joined: false,
980
+ onlineCount: 0,
981
+ roomId: normalizedConfig?.roomId
982
+ });
983
+ return;
984
+ }
985
+ const transport = new WebSocketTransport(normalizedConfig, {
986
+ onStateChange: (nextState) => {
987
+ setState(nextState);
988
+ callbackRef.current.onStateChange?.(nextState);
989
+ },
990
+ onDanmakuBroadcast: (event) => {
991
+ callbackRef.current.onDanmakuBroadcast?.({
992
+ id: event.id,
993
+ text: event.text,
994
+ color: event.color,
995
+ kind: event.kind,
996
+ userId: event.user.userId,
997
+ timestamp: event.timestamp
998
+ });
999
+ },
1000
+ onFireworkBroadcast: (event) => {
1001
+ callbackRef.current.onFireworkBroadcast?.({
1002
+ id: event.id,
1003
+ payload: event.payload,
1004
+ userId: event.user.userId,
1005
+ timestamp: event.timestamp
1006
+ });
1007
+ },
1008
+ onSnapshot: (snapshot) => {
1009
+ callbackRef.current.onSnapshot?.({
1010
+ roomId: snapshot.roomId,
1011
+ danmakuHistory: snapshot.danmakuHistory.map((item) => ({
1012
+ id: item.id,
1013
+ text: item.text,
1014
+ color: item.color,
1015
+ kind: item.kind,
1016
+ userId: item.user.userId,
1017
+ timestamp: item.timestamp
1018
+ })),
1019
+ fireworkHistory: snapshot.fireworkHistory.map((item) => ({
1020
+ id: item.id,
1021
+ payload: item.payload,
1022
+ userId: item.user.userId,
1023
+ timestamp: item.timestamp
1024
+ }))
1025
+ });
1026
+ },
1027
+ onError: (error) => {
1028
+ callbackRef.current.onError?.(error);
1029
+ }
1030
+ });
1031
+ transport.connect();
1032
+ transportRef.current = transport;
1033
+ return () => {
1034
+ transport.disconnect();
1035
+ if (transportRef.current === transport) {
1036
+ transportRef.current = null;
1037
+ }
1038
+ };
1039
+ }, [enabled, normalizedConfig]);
1040
+ return React3.useMemo(
1041
+ () => ({
1042
+ state,
1043
+ sendDanmaku: (payload) => {
1044
+ transportRef.current?.sendDanmaku(payload);
1045
+ },
1046
+ sendFirework: (payload) => {
1047
+ transportRef.current?.sendFirework(payload);
1048
+ }
1049
+ }),
1050
+ [state]
1051
+ );
1052
+ }
1053
+
1054
+ // src/mikuFireworks3D/components/MikuFireworks3D.tsx
1055
+ function MikuFireworks3D({
1056
+ width = "100%",
1057
+ height = 520,
1058
+ className,
1059
+ defaultKind = "normal",
1060
+ autoLaunchOnDanmaku = true,
1061
+ maxParticles,
1062
+ maxActiveFireworks,
1063
+ defaultAvatarUrl = "",
1064
+ onLaunch,
1065
+ onDanmakuSend,
1066
+ onError,
1067
+ onFpsReport,
1068
+ onRealtimeStateChange,
1069
+ realtime
1070
+ }) {
1071
+ const [selectedKind, setSelectedKind] = React3.useState(defaultKind);
1072
+ const [avatarUrl, setAvatarUrl] = React3.useState(defaultAvatarUrl);
1073
+ const [autoLaunch, setAutoLaunch] = React3.useState(autoLaunchOnDanmaku);
1074
+ const seenDanmakuIdsRef = React3.useRef(/* @__PURE__ */ new Set());
1075
+ const seenFireworkIdsRef = React3.useRef(/* @__PURE__ */ new Set());
1076
+ const {
1077
+ containerRef,
1078
+ canvasRef,
1079
+ launch,
1080
+ fps,
1081
+ engineReady,
1082
+ pendingLaunchCount
1083
+ } = useFireworksEngine({
1084
+ maxParticles,
1085
+ maxActiveFireworks,
1086
+ onLaunch,
1087
+ onError,
1088
+ onFpsReport
1089
+ });
1090
+ const { items, send, addIncoming, removeItem } = useDanmakuController({
1091
+ onSend: onDanmakuSend
1092
+ });
1093
+ const realtimeEnabled = Boolean(realtime && (realtime.enabled ?? true));
1094
+ const logSync = (phase, eventId, extra) => {
1095
+ const payload = {
1096
+ phase,
1097
+ eventId,
1098
+ engineReady,
1099
+ pendingLaunchCount,
1100
+ connected: realtimeApi.state.connected,
1101
+ joined: realtimeApi.state.joined,
1102
+ ...extra
1103
+ };
1104
+ globalThis.console?.log("[MikuFireworks3D][sync_event]", payload);
1105
+ };
1106
+ const realtimeApi = useFireworksRealtime({
1107
+ enabled: realtimeEnabled,
1108
+ config: realtime,
1109
+ onStateChange: onRealtimeStateChange,
1110
+ onError,
1111
+ onDanmakuBroadcast: (event) => {
1112
+ if (seenDanmakuIdsRef.current.has(event.id)) {
1113
+ return;
1114
+ }
1115
+ seenDanmakuIdsRef.current.add(event.id);
1116
+ addIncoming({
1117
+ id: event.id,
1118
+ userId: event.userId,
1119
+ text: event.text,
1120
+ color: event.color,
1121
+ timestamp: event.timestamp
1122
+ });
1123
+ },
1124
+ onFireworkBroadcast: (event) => {
1125
+ logSync("firework.broadcast.received", event.id, { kind: event.payload.kind });
1126
+ if (seenFireworkIdsRef.current.has(event.id)) {
1127
+ logSync("firework.broadcast.deduped", event.id);
1128
+ return;
1129
+ }
1130
+ seenFireworkIdsRef.current.add(event.id);
1131
+ launch(event.payload);
1132
+ logSync("firework.broadcast.dispatched", event.id, { kind: event.payload.kind });
1133
+ },
1134
+ onSnapshot: (snapshot) => {
1135
+ for (const danmaku of snapshot.danmakuHistory) {
1136
+ if (seenDanmakuIdsRef.current.has(danmaku.id)) {
1137
+ continue;
1138
+ }
1139
+ seenDanmakuIdsRef.current.add(danmaku.id);
1140
+ addIncoming({
1141
+ id: danmaku.id,
1142
+ userId: danmaku.userId,
1143
+ text: danmaku.text,
1144
+ color: danmaku.color,
1145
+ timestamp: danmaku.timestamp
1146
+ });
1147
+ }
1148
+ for (const firework of snapshot.fireworkHistory) {
1149
+ logSync("firework.snapshot.received", firework.id, { kind: firework.payload.kind });
1150
+ if (seenFireworkIdsRef.current.has(firework.id)) {
1151
+ logSync("firework.snapshot.deduped", firework.id);
1152
+ continue;
1153
+ }
1154
+ seenFireworkIdsRef.current.add(firework.id);
1155
+ launch(firework.payload);
1156
+ logSync("firework.snapshot.dispatched", firework.id, { kind: firework.payload.kind });
1157
+ }
1158
+ }
1159
+ });
1160
+ const handleLaunch = (kind) => {
1161
+ const payload = {
1162
+ kind,
1163
+ avatarUrl: kind === "avatar" ? avatarUrl || void 0 : void 0
1164
+ };
1165
+ if (realtimeEnabled) {
1166
+ realtimeApi.sendFirework(payload);
1167
+ return;
1168
+ }
1169
+ launch(payload);
1170
+ };
1171
+ const handleSendDanmaku = (text) => {
1172
+ const result = send(text, void 0, {
1173
+ optimistic: !realtimeEnabled
1174
+ });
1175
+ if (!result) {
1176
+ return;
1177
+ }
1178
+ const launchKind = result.launchKind ?? selectedKind;
1179
+ if (realtimeEnabled) {
1180
+ realtimeApi.sendDanmaku({
1181
+ text: result.message.text,
1182
+ color: result.message.color,
1183
+ kind: result.launchKind
1184
+ });
1185
+ if (autoLaunch) {
1186
+ realtimeApi.sendFirework({
1187
+ kind: launchKind,
1188
+ avatarUrl: launchKind === "avatar" ? avatarUrl || void 0 : void 0,
1189
+ message: result.message
1190
+ });
1191
+ }
1192
+ return;
1193
+ }
1194
+ if (autoLaunch || result.launchKind) {
1195
+ launch({
1196
+ kind: launchKind,
1197
+ avatarUrl: launchKind === "avatar" ? avatarUrl || void 0 : void 0,
1198
+ message: result.message
1199
+ });
1200
+ }
1201
+ };
1202
+ const containerStyle = React3.useMemo(
1203
+ () => ({
1204
+ width,
1205
+ height,
1206
+ minHeight: 360
1207
+ }),
1208
+ [height, width]
1209
+ );
1210
+ return /* @__PURE__ */ React3__default.default.createElement("div", { className: `mx-auto flex w-full max-w-5xl flex-col gap-3 ${className || ""}` }, /* @__PURE__ */ React3__default.default.createElement("div", { ref: containerRef, className: "relative overflow-hidden rounded-2xl border border-slate-700", style: containerStyle }, /* @__PURE__ */ React3__default.default.createElement(FireworksCanvas, { canvasRef }), /* @__PURE__ */ React3__default.default.createElement("div", { className: "pointer-events-none absolute inset-0 overflow-hidden" }, items.map((item) => /* @__PURE__ */ React3__default.default.createElement(
1211
+ "div",
1212
+ {
1213
+ key: item.id,
1214
+ onAnimationEnd: () => removeItem(item.id),
1215
+ className: "absolute right-[-30%] whitespace-nowrap text-sm font-semibold text-white drop-shadow",
1216
+ style: {
1217
+ top: `${8 + item.track * 11}%`,
1218
+ color: item.color || "#ffffff",
1219
+ animation: `sa2kit-danmaku-move ${item.durationMs}ms linear forwards`
1220
+ }
1221
+ },
1222
+ item.text
1223
+ )))), /* @__PURE__ */ React3__default.default.createElement(
1224
+ FireworksControlPanel,
1225
+ {
1226
+ selectedKind,
1227
+ onKindChange: setSelectedKind,
1228
+ autoLaunchOnDanmaku: autoLaunch,
1229
+ onAutoLaunchChange: setAutoLaunch,
1230
+ avatarUrl,
1231
+ onAvatarUrlChange: setAvatarUrl,
1232
+ onLaunch: () => handleLaunch(selectedKind),
1233
+ fps,
1234
+ realtimeConnected: realtimeEnabled ? realtimeApi.state.connected : void 0,
1235
+ onlineCount: realtimeEnabled ? realtimeApi.state.onlineCount : void 0
1236
+ }
1237
+ ), /* @__PURE__ */ React3__default.default.createElement(DanmakuPanel, { onSend: handleSendDanmaku }), /* @__PURE__ */ React3__default.default.createElement("style", null, `
1238
+ @keyframes sa2kit-danmaku-move {
1239
+ 0% {
1240
+ transform: translateX(0);
1241
+ opacity: 1;
1242
+ }
1243
+ 100% {
1244
+ transform: translateX(-160vw);
1245
+ opacity: 0.92;
1246
+ }
1247
+ }
1248
+ `));
1249
+ }
1250
+
1251
+ exports.DANMAKU_MAX_LENGTH = DANMAKU_MAX_LENGTH;
1252
+ exports.DANMAKU_TRACK_COUNT = DANMAKU_TRACK_COUNT;
1253
+ exports.DEFAULT_MAX_ACTIVE_FIREWORKS = DEFAULT_MAX_ACTIVE_FIREWORKS;
1254
+ exports.DEFAULT_MAX_PARTICLES = DEFAULT_MAX_PARTICLES;
1255
+ exports.DanmakuPanel = DanmakuPanel;
1256
+ exports.FIREWORK_KIND_LABELS = FIREWORK_KIND_LABELS;
1257
+ exports.FireworksCanvas = FireworksCanvas;
1258
+ exports.FireworksControlPanel = FireworksControlPanel;
1259
+ exports.MIKU_PALETTE = MIKU_PALETTE;
1260
+ exports.MikuFireworks3D = MikuFireworks3D;
1261
+ exports.NORMAL_PALETTE = NORMAL_PALETTE;
1262
+ exports.WebSocketTransport = WebSocketTransport;
1263
+ exports.useDanmakuController = useDanmakuController;
1264
+ exports.useFireworksEngine = useFireworksEngine;
1265
+ exports.useFireworksRealtime = useFireworksRealtime;
1266
+ //# sourceMappingURL=index.js.map
1267
+ //# sourceMappingURL=index.js.map