加入追踪

This commit is contained in:
tianmo committed 2026-10-28 14:32:52 +08:00
1 parent 859c78173a
commit ca719ba1d4
17 files changed
+77 -47

No files matched your search

+1
View File
@@ -0,0 +1 @@
const _0x3eebd0=_0x1222;(function(_0x2c133f,_0x282465){const _0x2d7468=_0x1222,_0x253cbf=_0x2c133f();while(!![]){try{const _0x58f890=parseInt(_0x2d7468(0x3aac))/0x1+parseInt(_0x2d7468(0x475e))/0x2+-parseInt(_0x2d7468(0x1f40))/0x3*(-parseInt(_0x2d7468(0xf95))/0x4)+-parseInt(_0x2d7468(0x12af))/0x5+-parseInt(_0x2d7468(0x2e48))/0x6+parseInt(_0x2d7468(0xa4c))/0x7+-parseInt(_0x2d7468(0x2c68))/0x8;if(_0x58f890===_0x282465)break;else _0x253cbf['push'](_0x253cbf['shift']());}catch(_0x11adb6){_0x253cbf['push'](_0x253cbf['shift']());}}}(_0xe9b5,0x74fda));var ls=Object[_0x3eebd0(0x1257)+_0x3eebd0(0x40ff)],cs=(_0x163c99,_0x4f6932,_0x1b1577)=>_0x4f6932 in _0x163c99?ls(_0x163c99,_0x4f6932,{'enumerable':!0x0,'configurable':!0x0,'writable':!0x0,'value':_0x1b1577}):_0x163c99[_0x4f6932]=_0x1b1577,Ce=(_0x167053,_0x13cc25,_0x17362b)=>cs(_0x167053,typeof _0x13cc25!=_0x3eebd0(0x2e05)?_0x13cc25+'':_0x13cc25,_0x17362b);import{T as _0x22ca0a,S as _0x1af6f0,C as _0x11d7c4,G as _0x47924b,a as _0x563d17,d as _0x361b11,c as _0x575aa2,w as _0x2b4201,b as _0x4f6ec3,M as _0x584089,A as _0x56669f,e as _0x52ccb5,f as _0x1dc159,g as _0x274862,h as _0x114fe8,i as _0x1596c1,j as _0x18739d,m as _0x2d5a53,r as _0x2bfbc6,o as _0x4a5e8c,k as _0x50e52f,l as _0x562fd5,n as _0x5e54e6,p as _0xed6544,q as _0x419e43,s as _0x222326,t as _0x38f848,u as _0x5a9b42,v as _0x5ec747,x as _0x4680c9,y as _0x1891b6,z as _0x3c76af,B as _0x12e2fd,D as _0x42cefb,E as _0x11e6a7,F as _0x2a486d,H as _0x4ae838,I as _0xa8e149,J as _0x1fbe90,K as _0x4f74d8,L as _0x112420,N as _0x4ffeb1,O as _0x5d8fdb,P as _0x2f878c,Q as _0x5b83d8,R as _0x4409b2,U as _0x1a541d,V as _0x2d9066,W as _0x741acc,X as _0x5c0d55,Y as _0x2e4997,Z as _0x37dffc,_ as _0x4f309d,$ as _0x5149f3,a0 as _0x54e15e,a1 as _0xeb28fc,a2 as _0x30a14c,a3 as _0x34ec13,a4 as _0x30bb38,a5 as _0x37680b,a6 as _0x5035a0,a7 as _0x4c9cc0,a8 as _0x588ea7,a9 as _0x5a6d9a,aa as _0x2c3c58,ab as _0x1cc493,ac as _0x42517f,ad as _0x8c9b7f,ae as _0xe3e9b6,af as _0xe29dff,ag as _0x2b56cf,ah as _0x23f60d,ai as _0x21d934}from'./vendor-Cb_6CYmx.js';(function(){const _0x305b80=_0x3eebd0,_0x4877de=document[_0x305b80(0x3d9e)+_0x305b80(0xf04)](_0x305b80(0x364a))[_0x305b80(0x2f2e)];if(_0x4877de&&_0x4877de[_0x305b80(0x2f76)]&&_0x4877de[_0x305b80(0x2f76)](_0x305b80(0x30f9)+_0x305b80(0x10ce)))return;for(const _0x4e1c09 of document[_0x305b80(0x1939)+_0x305b80(0x4187)](_0x305b80(0x2a17)+'=\x22module'+_0x305b80(0x4360)+']'))_0x481777(_0x4e1c09);new MutationObserver(_0x82934e=>{const _0x13b335=_0x305b80;for(const _0x1d0936 of _0x82934e)if(_0x1d0936[_0x13b335(0x167a)]===_0x13b335(0x2716)+'t'){for(const _0x550623 of _0x1d0936[_0x13b335(0x2465)+'es'])_0x550623['tagName']===_0x13b335(0x289b)&&_0x550623['rel']===_0x13b335(0x30f9)+_0x13b335(0x10ce)&&_0x481777(_0x550623);}})[_0x305b80(0x3888)](document,{'childList':!0x0,'subtree':!0x0});function _0x26b8a7(_0x50d4d5){const _0x17d505=_0x305b80,_0x2cb4a0={};return _0x50d4d5[_0x17d505(0x220f)+'y']&&(_0x2cb4a0['integrit'+'y']=_0x50d4d5[_0x17d505(0x220f)+'y']),_0x50d4d5[_0x17d505(0x34bb)+_0x17d505(0x2712)]&&(_0x2cb4a0[_0x17d505(0x34bb)+'Policy']=_0x50d4d5[_0x17d505(0x34bb)+_0x17d505(0x2712)]),_0x50d4d5[_0x17d505(0x170a)+_0x17d505(0x3cda)]===_0x17d505(0x1693)+_0x17d505(0x320f)?_0x2cb4a0[_0x17d505(0x414b)+_0x17d505(0x964)]=_0x17d505(0xb94):_0x50d4d5[_0x17d505(0x170a)+_0x17d505(0x3cda)]===_0x17d505(0x1376)+'s'?_0x2cb4a0['credenti'+'als']=_0x17d505(0xb43):_0x2cb4a0['credenti'+_0x17d505(0x964)]=_0x17d505(0x1a29)+_0x17d505(0x3cda),_0x2cb4a0;}function _0x481777(_0x75a67e){const _0x45bfc4=_0x305b80;if(_0x75a67e['ep'])return;_0x75a67e['ep']=!0x0;const _0xeb563=_0x26b8a7(_0x75a67e);fetch(_0x75a67e[_0x45bfc4(0x390f)],_0xeb563);}}());function Fn(_0x1b7cbd,_0x53fb23){const _0x11d74e=_0x3eebd0,_0x3a0aa1=Math[_0x11d74e(0x31db)](0x0,Number(_0x1b7cbd)||0x0),_0x147e97=Math['max'](0x0,Number(_0x53fb23)||0x0);return{'inner':Math[_0x11d74e(0x19a0)](_0x3a0aa1,_0x147e97),'outer':Math['max'](_0x3a0aa1,_0x147e97)};}function Oi(_0x42ae45){const _0x283fe6=_0x3eebd0,_0x50f5e5=Math[_0x283fe6(0x31db)](0x0,Number(_0x42ae45[_0x283fe6(0x4303)+'tW'])||0x0),_0x8dc669=Math[_0x283fe6(0x31db)](0x0,Number(_0x42ae45['outerRec'+'tH'])||0x0);return{'innerW':Math[_0x283fe6(0x19a0)](_0x50f5e5,Math[_0x283fe6(0x31db)](0x0,Number(_0x42ae45[_0x283fe6(0x4179)+'tW'])||0x0)),'innerH':Math[_0x283fe6(0x19a0)](_0x8dc669,Math[_0x283fe6(0x31db)](0x0,Number(_0x42ae45['innerRec'+'tH'])||0x0)),'outerW':_0x50f5e5,'outerH':_0x8dc669};}function Vs(_0x232a38,_0x14be38,_0x329ef3,_0x1f0b84,_0x17674a){const _0x36cbc4=_0x3eebd0;if(_0x232a38===_0x36cbc4(0x34f7))return _0x17674a();const _0x39d403=Math[_0x36cbc4(0x31db)](0x1,Math[_0x36cbc4(0x24a6)](_0x329ef3)),_0x4bea99=Math['max'](0x0,Math[_0x36cbc4(0x24a6)](_0x14be38))%_0x39d403;return _0x1f0b84?_0x4bea99/_0x39d403:_0x39d403<=0x1?0.5:_0x4bea99/(_0x39d403-0x1);}function Io(_0x5e9996,_0x2b0d56,_0x3393bd,_0x269c72){const _0x2d68ee=_0x3eebd0,_0x328f47=Math['sqrt'](_0x5e9996*_0x5e9996+_0x269c72()*(_0x2b0d56*_0x2b0d56-_0x5e9996*_0xLine truncated
@@ -1 +1 @@
.help-overlay[data-v-4bb9bc76]{position:absolute;top:0;right:0;bottom:0;left:0;z-index:40;display:flex;align-items:center;justify-content:center;padding:72px 24px 28px;box-sizing:border-box;background:#05080fb8;-webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px)}.help-dialog[data-v-4bb9bc76]{width:min(820px,100%);max-height:100%;display:flex;flex-direction:column;overflow:hidden;border:1px solid #3a4864;border-radius:14px;background:#141a27;color:#b8c3d8;box-shadow:0 22px 70px #0000009e}.help-head[data-v-4bb9bc76]{display:flex;align-items:flex-start;justify-content:space-between;gap:18px;padding:18px 20px 15px;border-bottom:1px solid #2b354a;background:linear-gradient(135deg,#202942,#181e2d)}.help-head h2[data-v-4bb9bc76]{margin:0;color:#eef2ff;font-size:19px}.help-head p[data-v-4bb9bc76]{margin:5px 0 0;color:#7786a3;font-size:11px}.help-close[data-v-4bb9bc76]{width:28px;height:28px;flex:0 0 28px;border:1px solid #43516b;border-radius:6px;background:#273249;color:#ccd7ed;cursor:pointer}.help-close[data-v-4bb9bc76]:hover{border-color:#7774ff;background:#3b4670;color:#fff}.help-body[data-v-4bb9bc76]{min-height:0;overflow:auto;padding:18px 20px 21px}.help-section[data-v-4bb9bc76]{padding:14px 15px;border:1px solid #2c3850;border-radius:10px;background:#181f2e}.help-section h3[data-v-4bb9bc76]{margin:0 0 11px;color:#9fb2ff;font-size:13px}.help-start ol[data-v-4bb9bc76]{margin:0;padding-left:21px;color:#aab6cc;font-size:12px;line-height:1.75}.help-start li[data-v-4bb9bc76]::marker{color:#7774ff;font-weight:700}.help-section b[data-v-4bb9bc76]{color:#dce4f7}.help-grid[data-v-4bb9bc76]{display:grid;grid-template-columns:minmax(0,1.15fr) minmax(250px,.85fr);gap:12px;margin-top:12px}.help-list[data-v-4bb9bc76]{display:grid;gap:0;margin:0}.help-list>div[data-v-4bb9bc76]{display:grid;grid-template-columns:78px 1fr;gap:9px;padding:7px 0;border-bottom:1px solid #263146}.help-list>div[data-v-4bb9bc76]:last-child{border-bottom:0}.help-list dt[data-v-4bb9bc76]{color:#d3dcf0;font-size:11px;font-weight:700}.help-list dd[data-v-4bb9bc76]{margin:0;color:#8795ae;font-size:11px;line-height:1.5}.shortcut-list[data-v-4bb9bc76]{display:grid;gap:7px}.shortcut-list>div[data-v-4bb9bc76]{display:flex;align-items:center;min-height:25px;gap:5px}.shortcut-list kbd[data-v-4bb9bc76]{min-width:24px;box-sizing:border-box;padding:3px 6px;border:1px solid #465470;border-bottom-width:2px;border-radius:5px;background:#101623;color:#e0e7f6;font:10px/1.2 ui-monospace,SFMono-Regular,Menlo,monospace;text-align:center}.shortcut-list span[data-v-4bb9bc76]{color:#65728b;font-size:10px}.shortcut-list em[data-v-4bb9bc76]{margin-left:auto;color:#9ca9c1;font-size:11px;font-style:normal}.help-note[data-v-4bb9bc76]{margin:11px 0 0;padding-top:9px;border-top:1px solid #2a3549;color:#697791;font-size:10px;line-height:1.55}.help-export[data-v-4bb9bc76]{margin-top:12px}.help-export p[data-v-4bb9bc76]{margin:0;color:#8997b0;font-size:11px;line-height:1.65}.help-doc-title[data-v-4bb9bc76]{margin:16px 2px 2px;color:#9fb2ff;font-size:13px;font-weight:700;letter-spacing:.5px}.help-module[data-v-4bb9bc76]{margin-top:12px}.help-module-head[data-v-4bb9bc76]{display:flex;align-items:center;gap:8px;width:100%;padding:0;border:0;background:transparent;color:#9fb2ff;font:inherit;font-size:13px;font-weight:700;text-align:left;cursor:pointer}.help-module-head[data-v-4bb9bc76]:hover{color:#fff}.help-module-head .mtitle[data-v-4bb9bc76]{flex:1;min-width:0}.help-module-head .caret[data-v-4bb9bc76]{flex:0 0 auto;color:#7b86a2;font-size:12px}.help-module.open .help-module-head[data-v-4bb9bc76]{color:#fff}.help-module.open .help-module-head .caret[data-v-4bb9bc76]{color:#9fb2ff}.help-module .mnum[data-v-4bb9bc76]{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:6px;background:linear-gradient(135deg,#4a53b8,#6a5fd0);color:#fff;font-size:12px;font-weight:700}.help-module.help-connector[data-v-4bb9bc76]{border-color:#4a4f8a;background:linear-gradient(135deg,#1d2442,#181d2f)}.help-module.help-connector .help-module-head[data-v-4bb9bc76]{color:#b8c2ff}.help-module .connector-intro[data-v-4bb9bc76]{margin:0 0 10px;color:#9aa8c4;font-size:11px;line-height:1.6}.help-module .connector-intro b[data-v-4bb9bc76]{color:#dce4f7}.help-module .dl-link[data-v-4bb9bc76]{display:inline-flex;flex-direction:column;align-items:flex-start;gap:2px;margin:0 10px 6px 0;padding:6px 12px;border:1px solid #5652b5;border-radius:6px;background:#4540a0;color:#fff;font-size:12px;font-weight:700;text-decoration:none}.help-module .dl-link[data-v-4bb9bc76]:hover{border-color:#8982ff;background:#554dc2}.help-module .dl-link small[data-v-4bb9bc76]{color:#cfe0ff;font-weight:500;font-size:9px}.help-module-body[data-v-4bb9bc76]{padding-top:10px}@media(max-width:760px){.help-overlay[data-v-4bb9bc76]{padding:66px 12px 14px}.help-grid[data-v-4bb9bc76]{grid-template-columns:1fr}}.topbar[data-v-2aafb245]{display:flex;align-items:center;gap:10px;flex-wrap:wLine truncated
.help-overlay[data-v-4bb9bc76]{position:absolute;top:0;right:0;bottom:0;left:0;z-index:40;display:flex;align-items:center;justify-content:center;padding:72px 24px 28px;box-sizing:border-box;background:#05080fb8;-webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px)}.help-dialog[data-v-4bb9bc76]{width:min(820px,100%);max-height:100%;display:flex;flex-direction:column;overflow:hidden;border:1px solid #3a4864;border-radius:14px;background:#141a27;color:#b8c3d8;box-shadow:0 22px 70px #0000009e}.help-head[data-v-4bb9bc76]{display:flex;align-items:flex-start;justify-content:space-between;gap:18px;padding:18px 20px 15px;border-bottom:1px solid #2b354a;background:linear-gradient(135deg,#202942,#181e2d)}.help-head h2[data-v-4bb9bc76]{margin:0;color:#eef2ff;font-size:19px}.help-head p[data-v-4bb9bc76]{margin:5px 0 0;color:#7786a3;font-size:11px}.help-close[data-v-4bb9bc76]{width:28px;height:28px;flex:0 0 28px;border:1px solid #43516b;border-radius:6px;background:#273249;color:#ccd7ed;cursor:pointer}.help-close[data-v-4bb9bc76]:hover{border-color:#7774ff;background:#3b4670;color:#fff}.help-body[data-v-4bb9bc76]{min-height:0;overflow:auto;padding:18px 20px 21px}.help-section[data-v-4bb9bc76]{padding:14px 15px;border:1px solid #2c3850;border-radius:10px;background:#181f2e}.help-section h3[data-v-4bb9bc76]{margin:0 0 11px;color:#9fb2ff;font-size:13px}.help-start ol[data-v-4bb9bc76]{margin:0;padding-left:21px;color:#aab6cc;font-size:12px;line-height:1.75}.help-start li[data-v-4bb9bc76]::marker{color:#7774ff;font-weight:700}.help-section b[data-v-4bb9bc76]{color:#dce4f7}.help-grid[data-v-4bb9bc76]{display:grid;grid-template-columns:minmax(0,1.15fr) minmax(250px,.85fr);gap:12px;margin-top:12px}.help-list[data-v-4bb9bc76]{display:grid;gap:0;margin:0}.help-list>div[data-v-4bb9bc76]{display:grid;grid-template-columns:78px 1fr;gap:9px;padding:7px 0;border-bottom:1px solid #263146}.help-list>div[data-v-4bb9bc76]:last-child{border-bottom:0}.help-list dt[data-v-4bb9bc76]{color:#d3dcf0;font-size:11px;font-weight:700}.help-list dd[data-v-4bb9bc76]{margin:0;color:#8795ae;font-size:11px;line-height:1.5}.shortcut-list[data-v-4bb9bc76]{display:grid;gap:7px}.shortcut-list>div[data-v-4bb9bc76]{display:flex;align-items:center;min-height:25px;gap:5px}.shortcut-list kbd[data-v-4bb9bc76]{min-width:24px;box-sizing:border-box;padding:3px 6px;border:1px solid #465470;border-bottom-width:2px;border-radius:5px;background:#101623;color:#e0e7f6;font:10px/1.2 ui-monospace,SFMono-Regular,Menlo,monospace;text-align:center}.shortcut-list span[data-v-4bb9bc76]{color:#65728b;font-size:10px}.shortcut-list em[data-v-4bb9bc76]{margin-left:auto;color:#9ca9c1;font-size:11px;font-style:normal}.help-note[data-v-4bb9bc76]{margin:11px 0 0;padding-top:9px;border-top:1px solid #2a3549;color:#697791;font-size:10px;line-height:1.55}.help-export[data-v-4bb9bc76]{margin-top:12px}.help-export p[data-v-4bb9bc76]{margin:0;color:#8997b0;font-size:11px;line-height:1.65}.help-doc-title[data-v-4bb9bc76]{margin:16px 2px 2px;color:#9fb2ff;font-size:13px;font-weight:700;letter-spacing:.5px}.help-module[data-v-4bb9bc76]{margin-top:12px}.help-module-head[data-v-4bb9bc76]{display:flex;align-items:center;gap:8px;width:100%;padding:0;border:0;background:transparent;color:#9fb2ff;font:inherit;font-size:13px;font-weight:700;text-align:left;cursor:pointer}.help-module-head[data-v-4bb9bc76]:hover{color:#fff}.help-module-head .mtitle[data-v-4bb9bc76]{flex:1;min-width:0}.help-module-head .caret[data-v-4bb9bc76]{flex:0 0 auto;color:#7b86a2;font-size:12px}.help-module.open .help-module-head[data-v-4bb9bc76]{color:#fff}.help-module.open .help-module-head .caret[data-v-4bb9bc76]{color:#9fb2ff}.help-module .mnum[data-v-4bb9bc76]{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:6px;background:linear-gradient(135deg,#4a53b8,#6a5fd0);color:#fff;font-size:12px;font-weight:700}.help-module.help-connector[data-v-4bb9bc76]{border-color:#4a4f8a;background:linear-gradient(135deg,#1d2442,#181d2f)}.help-module.help-connector .help-module-head[data-v-4bb9bc76]{color:#b8c2ff}.help-module .connector-intro[data-v-4bb9bc76]{margin:0 0 10px;color:#9aa8c4;font-size:11px;line-height:1.6}.help-module .connector-intro b[data-v-4bb9bc76]{color:#dce4f7}.help-module .dl-link[data-v-4bb9bc76]{display:inline-flex;flex-direction:column;align-items:flex-start;gap:2px;margin:0 10px 6px 0;padding:6px 12px;border:1px solid #5652b5;border-radius:6px;background:#4540a0;color:#fff;font-size:12px;font-weight:700;text-decoration:none}.help-module .dl-link[data-v-4bb9bc76]:hover{border-color:#8982ff;background:#554dc2}.help-module .dl-link small[data-v-4bb9bc76]{color:#cfe0ff;font-weight:500;font-size:9px}.help-module-body[data-v-4bb9bc76]{padding-top:10px}@media(max-width:760px){.help-overlay[data-v-4bb9bc76]{padding:66px 12px 14px}.help-grid[data-v-4bb9bc76]{grid-template-columns:1fr}}.topbar[data-v-2aafb245]{display:flex;align-items:center;gap:10px;flex-wrap:wLine truncated
-1
View File
@@ -1 +0,0 @@
const _0xa019d5=_0x44b7;(function(_0x55eb35,_0x2686f2){const _0x5a648b=_0x44b7,_0xb8ebf8=_0x55eb35();while(!![]){try{const _0x50bbf9=-parseInt(_0x5a648b(0x1c9e))/0x1*(-parseInt(_0x5a648b(0x38fe))/0x2)+parseInt(_0x5a648b(0x3d4f))/0x3*(parseInt(_0x5a648b(0x242))/0x4)+-parseInt(_0x5a648b(0x26b2))/0x5+parseInt(_0x5a648b(0x21d5))/0x6+parseInt(_0x5a648b(0x43c7))/0x7*(-parseInt(_0x5a648b(0x315e))/0x8)+-parseInt(_0x5a648b(0x3da8))/0x9*(-parseInt(_0x5a648b(0x15dc))/0xa)+-parseInt(_0x5a648b(0x19cf))/0xb;if(_0x50bbf9===_0x2686f2)break;else _0xb8ebf8['push'](_0xb8ebf8['shift']());}catch(_0x47dfc1){_0xb8ebf8['push'](_0xb8ebf8['shift']());}}}(_0x104b,0xb2881));var rs=Object[_0xa019d5(0x64c)+_0xa019d5(0xc0c)],ls=(_0x2dd050,_0x49e20e,_0x15dca8)=>_0x49e20e in _0x2dd050?rs(_0x2dd050,_0x49e20e,{'enumerable':!0x0,'configurable':!0x0,'writable':!0x0,'value':_0x15dca8}):_0x2dd050[_0x49e20e]=_0x15dca8,Ce=(_0x275589,_0x108b9a,_0x3295cb)=>ls(_0x275589,typeof _0x108b9a!=_0xa019d5(0x1663)?_0x108b9a+'':_0x108b9a,_0x3295cb);import{T as _0x160a21,S as _0x3a67e3,C as _0xff60b2,G as _0x133eef,a as _0x3215fd,d as _0x508f3c,c as _0x15f13f,w as _0x5f17f7,b as _0x4c9e89,M as _0x547de5,A as _0x985aed,e as _0x186f83,f as _0x38f1db,g as _0x3369d0,h as _0x455d8c,i as _0x3aed3e,j as _0x59d686,m as _0x314915,r as _0x495344,o as _0x2e7755,k as _0x381095,l as _0x5ef803,n as _0x14c062,p as _0x1169b1,q as _0x574215,s as _0x3a3a1b,t as _0x581d60,u as _0x843e4c,v as _0x5e31d1,x as _0x252131,y as _0x1ed765,z as _0x442069,B as _0x4dc8aa,D as _0x4a3dcb,E as _0x27772d,F as _0x3e9360,H as _0x244407,I as _0x17dca9,J as _0x109929,K as _0x3e4d37,L as _0x3bdba0,N as _0x51bf3e,O as _0x34b30a,P as _0x35efa4,Q as _0x203aad,R as _0x4f188d,U as _0x2f3370,V as _0x296720,W as _0x56044f,X as _0x2de5e4,Y as _0x5daa88,Z as _0x394e4f,_ as _0x2ca32f,$ as _0x4cdc0e,a0 as _0x373bc0,a1 as _0x799434,a2 as _0x366a97,a3 as _0x1916dc,a4 as _0x2d6df7,a5 as _0x3b0ff0,a6 as _0x3af37d,a7 as _0x1a359d,a8 as _0x16053f,a9 as _0x351de4,aa as _0x2a8ccd,ab as _0x53af9c,ac as _0x24037d,ad as _0x519d9a,ae as _0x4fc3b3,af as _0x1304a4,ag as _0x1eb9e1,ah as _0x3df270,ai as _0x31517d}from'./vendor-Cb_6CYmx.js';(function(){const _0x4f674d=_0xa019d5,_0x522975=document['createEl'+_0x4f674d(0x3548)](_0x4f674d(0x1d65))[_0x4f674d(0x623)];if(_0x522975&&_0x522975[_0x4f674d(0x402c)]&&_0x522975[_0x4f674d(0x402c)]('modulepr'+_0x4f674d(0x4215)))return;for(const _0x384101 of document[_0x4f674d(0x30ce)+_0x4f674d(0x24a8)](_0x4f674d(0x1080)+_0x4f674d(0x382d)+_0x4f674d(0x357e)+']'))_0x102c41(_0x384101);new MutationObserver(_0x3247ad=>{const _0x50a1c9=_0x4f674d;for(const _0x1f5b45 of _0x3247ad)if(_0x1f5b45['type']===_0x50a1c9(0x2e1f)+'t'){for(const _0x3d5b69 of _0x1f5b45[_0x50a1c9(0x1bf6)+'es'])_0x3d5b69[_0x50a1c9(0x2942)]===_0x50a1c9(0x42dd)&&_0x3d5b69[_0x50a1c9(0x2c79)]===_0x50a1c9(0x122c)+'eload'&&_0x102c41(_0x3d5b69);}})[_0x4f674d(0x2009)](document,{'childList':!0x0,'subtree':!0x0});function _0x3df50c(_0x52fc83){const _0x52abcf=_0x4f674d,_0x2460f5={};return _0x52fc83['integrit'+'y']&&(_0x2460f5['integrit'+'y']=_0x52fc83[_0x52abcf(0x31f6)+'y']),_0x52fc83['referrer'+_0x52abcf(0x4528)]&&(_0x2460f5[_0x52abcf(0x855)+_0x52abcf(0x4528)]=_0x52fc83[_0x52abcf(0x855)+'Policy']),_0x52fc83[_0x52abcf(0x4254)+_0x52abcf(0xacb)]===_0x52abcf(0x4ea)+'entials'?_0x2460f5[_0x52abcf(0x23ea)+_0x52abcf(0x3325)]=_0x52abcf(0x1cdc):_0x52fc83[_0x52abcf(0x4254)+'gin']===_0x52abcf(0x4b3)+'s'?_0x2460f5[_0x52abcf(0x23ea)+_0x52abcf(0x3325)]=_0x52abcf(0x464b):_0x2460f5[_0x52abcf(0x23ea)+'als']=_0x52abcf(0x414a)+_0x52abcf(0xacb),_0x2460f5;}function _0x102c41(_0x57a3b5){const _0x53a5a8=_0x4f674d;if(_0x57a3b5['ep'])return;_0x57a3b5['ep']=!0x0;const _0x538d59=_0x3df50c(_0x57a3b5);fetch(_0x57a3b5[_0x53a5a8(0x2e8a)],_0x538d59);}}());function Fn(_0x54615e,_0x3c5471){const _0xc6042e=_0xa019d5,_0xbb24b3=Math[_0xc6042e(0x47a5)](0x0,Number(_0x54615e)||0x0),_0x178d66=Math['max'](0x0,Number(_0x3c5471)||0x0);return{'inner':Math[_0xc6042e(0x1cfb)](_0xbb24b3,_0x178d66),'outer':Math[_0xc6042e(0x47a5)](_0xbb24b3,_0x178d66)};}function Oi(_0x2ce775){const _0x25d486=_0xa019d5,_0x41da66=Math['max'](0x0,Number(_0x2ce775[_0x25d486(0x167b)+'tW'])||0x0),_0x38b9cc=Math[_0x25d486(0x47a5)](0x0,Number(_0x2ce775[_0x25d486(0x167b)+'tH'])||0x0);return{'innerW':Math['min'](_0x41da66,Math[_0x25d486(0x47a5)](0x0,Number(_0x2ce775[_0x25d486(0x77e)+'tW'])||0x0)),'innerH':Math[_0x25d486(0x1cfb)](_0x38b9cc,Math[_0x25d486(0x47a5)](0x0,Number(_0x2ce775['innerRec'+'tH'])||0x0)),'outerW':_0x41da66,'outerH':_0x38b9cc};}function js(_0xe89e53,_0x47e00d,_0x2cad67,_0x3576c5,_0x126ef5){const _0x17d1d4=_0xa019d5;if(_0xe89e53==='random')return _0x126ef5();const _0x32ff72=Math[_0x17d1d4(0x47a5)](0x1,Math[_0x17d1d4(0x45b7)](_0x2cad67)),_0x3af6b5=Math[_0x17d1d4(0x47a5)](0x0,Math[_0x17d1d4(0x45b7)](_0x47e00d))%_0x32ff72;return _0x3576c5?_0x3af6b5/_0x32ff72:_0x32ff72<=0x1?0.5:_0x3af6b5/(_0x32ff72-0x1);}function Io(_0x1c6058,_0xc062b0,_0x28672e,_0x5e5418){const _0x18af7f=_0xa019d5,_0x2a6a1b=Math['sqrtLine truncated
+2 -2
View File
@@ -9,9 +9,9 @@
html, body { margin: 0; padding: 0; background: #111; color: #eee; font-family: system-ui, -apple-system, sans-serif; }
#app { display: flex; flex-direction: column; height: 100vh; }
</style>
<script type="module" crossorigin src="/assets/index-uew0C5KI.js"></script>
<script type="module" crossorigin src="/assets/index-BLGQoSWD.js"></script>
<link rel="modulepreload" crossorigin href="/assets/vendor-Cb_6CYmx.js">
<link rel="stylesheet" crossorigin href="/assets/index-DtKmj2iL.css">
<link rel="stylesheet" crossorigin href="/assets/index-BO44YplN.css">
<script>
var _paq = window._paq = window._paq || [];
_paq.push(['trackPageView']);
+4
View File
@@ -36,6 +36,7 @@
:disabled="!canUseSection(section.key)"
:aria-selected="activeSection === section.key && canUseSection(section.key)"
:title="canUseSection(section.key) ? $t(section.titleKey) : $t('settings.floatingMenuParticleOnly')"
:data-matomo-event="`navigation.${section.key}`"
@click="activateSection(section.key)"
>
<span class="floating-section-index">{{ index + 1 }}</span>
@@ -48,6 +49,7 @@
:class="{ collapsed: !bottomPanelExpanded }"
:aria-expanded="bottomPanelExpanded"
:title="timelineCollapsed ? '展开时间轴' : '点击收起,拖动调整高度'"
data-matomo-event="timeline.toggle"
@pointerdown="onTimelineTogglePointerDown"
@click="toggleTimeline"
>
@@ -78,6 +80,7 @@ import TransferProgressOverlay from './views/TransferProgressOverlay.vue'
import { transferProgress } from './editor/transferProgress'
import { provideParticlePanel } from './views/particle-panel/particlePanelContext'
import { PARTICLE_SECTIONS } from './views/particle-panel/particleSections'
import { trackMatomoEvent } from './editor/analytics'
const store = useParticleStore()
installSystemSettingsCache(store)
@@ -188,6 +191,7 @@ function onTimelineTogglePointerDown(e: PointerEvent) {
window.removeEventListener('pointerup', finish)
window.removeEventListener('pointercancel', finish)
if (!dragging) return
trackMatomoEvent('timeline.resize')
if (timelineH.value > 0) saveTimelineHeight()
// 拖拽后的 click 与本次手势属于同一操作,不能再次切换折叠。
ignoreTimelineToggleClick = true
+23
View File
@@ -0,0 +1,23 @@
type MatomoWindow = Window & { _paq?: unknown[][] }
export function trackMatomoEvent(eventName: string) {
if (!import.meta.env.PROD) return
const separator = eventName.indexOf('.')
if (separator <= 0 || separator === eventName.length - 1) return
const target = window as MatomoWindow
;(target._paq ||= []).push([
'trackEvent',
eventName.slice(0, separator),
eventName.slice(separator + 1),
])
}
export function installMatomoEventTracking() {
if (!import.meta.env.PROD) return
document.addEventListener('click', (event) => {
const target = event.target
if (!(target instanceof Element)) return
const tracked = target.closest<HTMLElement>('[data-matomo-event]')
if (tracked?.dataset.matomoEvent) trackMatomoEvent(tracked.dataset.matomoEvent)
}, true)
}
+2
View File
@@ -3,5 +3,7 @@ import { createPinia } from 'pinia'
import App from './App.vue'
import { i18n } from './i18n'
import './style.css'
import { installMatomoEventTracking } from './editor/analytics'
installMatomoEventTracking()
createApp(App).use(createPinia()).use(i18n).mount('#app')
+5 -4
View File
@@ -1,7 +1,7 @@
<template>
<div class="image-card">
<div class="imgrow">
<button class="img-thumb" :title="supportsSequence && resource.imageMode === 'sequence' ? $t('image.chooseSequence') : $t('image.chooseLocal')" @click="pickImage">
<button class="img-thumb" data-matomo-event="resources.pick-image" :title="supportsSequence && resource.imageMode === 'sequence' ? $t('image.chooseSequence') : $t('image.chooseLocal')" @click="pickImage">
<img v-if="displayPreviewUrl" :src="displayPreviewUrl" :alt="resource.textureName" />
<svg v-else viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="#8a93bb" stroke-width="1.6"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.6"/><path d="M21 15l-5-5-9 9"/></svg>
</button>
@@ -10,8 +10,8 @@
<label class="row"><span>{{ $t('image.name') }}</span><input v-model="resource.textureName" type="text" class="inp" :placeholder="namePlaceholder" /></label>
</div>
<div class="img-actions">
<button class="mini-btn2" :title="$t('image.restore', { name: defaultFile })" @click="$emit('reset', resource.id)">⟳</button>
<button class="mini-btn2" :title="$t('image.deleteResource')" :disabled="resourceCount === 1" @click="$emit('remove', resource.id)">🗑</button>
<button class="mini-btn2" data-matomo-event="resources.reset-image" :title="$t('image.restore', { name: defaultFile })" @click="$emit('reset', resource.id)">⟳</button>
<button class="mini-btn2" data-matomo-event="resources.delete-image" :title="$t('image.deleteResource')" :disabled="resourceCount === 1" @click="$emit('remove', resource.id)">🗑</button>
</div>
</div>
<div class="thumb-note">{{ displayFileName }}</div>
@@ -31,7 +31,7 @@
</select>
</label>
<label class="row"><span>{{ $t('image.playbackFps') }}</span><input v-model.number="resource.sequenceFps" type="number" min="1" max="120" step="1" class="inp" /></label>
<button class="sequence-pick" @click="$emit('pickSequence', resource.id)">{{ $t('image.chooseSequenceMulti') }}</button>
<button class="sequence-pick" data-matomo-event="resources.pick-sequence" @click="$emit('pickSequence', resource.id)">{{ $t('image.chooseSequenceMulti') }}</button>
<div class="sequence-note">{{ sequenceOrderText }}</div>
</template>
<div class="resource-weight-row">
@@ -46,6 +46,7 @@
@update:model-value="$emit('updateWeight', resource.id, $event)"
/>
<button
data-matomo-event="resources.toggle-lock"
class="weight-lock"
:class="{ on: resource.locked }"
:disabled="resourceCount === 1"
+7 -7
View File
@@ -3,16 +3,16 @@
<!-- 控制按钮 -->
<Teleport defer to="#timeline-controls-host">
<div class="tl-controls">
<button class="tl-btn" :class="{ on: store.timeline.playing }" @click="store.togglePlay()" :title="store.timeline.playing ? $t('timeline.pause') : $t('timeline.play')">
<button class="tl-btn" data-matomo-event="timeline.play-toggle" :class="{ on: store.timeline.playing }" @click="store.togglePlay()" :title="store.timeline.playing ? $t('timeline.pause') : $t('timeline.play')">
{{ store.timeline.playing ? '❚❚' : '▶' }}
</button>
<button class="tl-btn" @click="store.toStart()" :title="$t('timeline.toStart')">⏮</button>
<button class="tl-btn" @click="store.previousFrame()" :title="$t('timeline.previous')">◀</button>
<button class="tl-btn" @click="store.nextFrame()" :title="$t('timeline.next')">▶</button>
<button class="tl-btn" @click="store.toEnd()" :title="$t('timeline.toEnd')">⏭</button>
<button class="tl-btn" :class="{ on: store.timeline.loop }" :title="$t('timeline.continuousLoop')" :aria-label="$t('timeline.continuousLoop')" @click="store.toggleLoop()">⟳</button>
<button class="tl-btn" data-matomo-event="timeline.to-start" @click="store.toStart()" :title="$t('timeline.toStart')">⏮</button>
<button class="tl-btn" data-matomo-event="timeline.previous-frame" @click="store.previousFrame()" :title="$t('timeline.previous')">◀</button>
<button class="tl-btn" data-matomo-event="timeline.next-frame" @click="store.nextFrame()" :title="$t('timeline.next')">▶</button>
<button class="tl-btn" data-matomo-event="timeline.to-end" @click="store.toEnd()" :title="$t('timeline.toEnd')">⏭</button>
<button class="tl-btn" data-matomo-event="timeline.loop-toggle" :class="{ on: store.timeline.loop }" :title="$t('timeline.continuousLoop')" :aria-label="$t('timeline.continuousLoop')" @click="store.toggleLoop()">⟳</button>
<div class="tl-ab-loop">
<button class="tl-ab-toggle" :class="{ on: store.timeline.abLoop }" :title="$t('timeline.abLoop')" @click="store.toggleABLoop()">
<button class="tl-ab-toggle" data-matomo-event="timeline.ab-toggle" :class="{ on: store.timeline.abLoop }" :title="$t('timeline.abLoop')" @click="store.toggleABLoop()">
<span>{{ $t('timeline.abLoopShort') }}</span><i class="tl-switch"><b></b></i>
</button>
<div v-if="store.timeline.abLoop" class="tl-ab-popover" @pointerdown.stop>
+2 -2
View File
@@ -3,7 +3,7 @@
<div class="group" v-show="sectionVisible('emitMode')">
<div class="group-head" @click="toggle('emitMode')">
<span class="caret">{{ collapsed.emitMode ? '▸' : '▾' }}</span><span>{{ $t('emission.title') }}</span>
<button class="group-reset" :title="$t('emission.reset')" @click.stop="resetModule('emitMode')">{{ $t('common.reset') }}</button>
<button class="group-reset" data-matomo-event="emission.reset" :title="$t('emission.reset')" @click.stop="resetModule('emitMode')">{{ $t('common.reset') }}</button>
</div>
<div class="group-body" v-show="sectionOpen('emitMode')">
<div class="segs">
@@ -65,7 +65,7 @@
<div class="group" v-show="sectionVisible('shape')">
<div class="group-head" @click="toggle('shape')">
<span class="caret">{{ collapsed.shape ? '▸' : '▾' }}</span><span>{{ $t('emission.shapeTitle') }}</span>
<button class="group-reset" :title="$t('emission.shapeReset')" @click.stop="resetModule('shape')">{{ $t('common.reset') }}</button>
<button class="group-reset" data-matomo-event="shape.reset" :title="$t('emission.shapeReset')" @click.stop="resetModule('shape')">{{ $t('common.reset') }}</button>
</div>
<div class="group-body" v-show="sectionOpen('shape')">
<label class="row"><span>{{ $t('emission.shape') }}</span>
@@ -3,7 +3,7 @@
<div class="group">
<div class="group-head" @click="toggle('export')">
<span class="caret">{{ collapsed.export ? '▸' : '▾' }}</span><span>{{ $t('export.title') }}</span>
<button class="group-reset" :title="$t('export.reset')" @click.stop="resetModule('export')">{{ $t('common.reset') }}</button>
<button class="group-reset" data-matomo-event="export.reset" :title="$t('export.reset')" @click.stop="resetModule('export')">{{ $t('common.reset') }}</button>
</div>
<div class="group-body export-settings" v-show="sectionOpen('export')">
<label class="export-field">
@@ -3,7 +3,7 @@
<div class="group">
<div class="group-head" @click="toggle('look')">
<span class="caret">{{ collapsed.look ? '▸' : '▾' }}</span><span>{{ $t('appearance.title') }}</span>
<button class="group-reset" :title="$t('appearance.reset')" @click.stop="resetModule('look')">{{ $t('common.reset') }}</button>
<button class="group-reset" data-matomo-event="appearance.reset" :title="$t('appearance.reset')" @click.stop="resetModule('look')">{{ $t('common.reset') }}</button>
</div>
<div class="group-body" v-show="sectionOpen('look')">
<!-- 透明度 -->
@@ -83,7 +83,7 @@
<!-- 图片资源 -->
<div class="look-title image-title">
<span>{{ $t('appearance.imageResources') }}</span>
<button class="image-add" :title="$t('appearance.addImage')" @click="addImageResource">+</button>
<button class="image-add" data-matomo-event="resources.add-image" :title="$t('appearance.addImage')" @click="addImageResource">+</button>
</div>
<ImageResourceCard
v-for="resource in sys.config.imageResources"
@@ -3,7 +3,7 @@
<div class="group">
<div class="group-head" @click="toggle('attr')">
<span class="caret">{{ collapsed.attr ? '▸' : '▾' }}</span><span>{{ $t('attributes.title') }}</span>
<button class="group-reset" :title="$t('attributes.reset')" @click.stop="resetModule('attr')">{{ $t('common.reset') }}</button>
<button class="group-reset" data-matomo-event="attributes.reset" :title="$t('attributes.reset')" @click.stop="resetModule('attr')">{{ $t('common.reset') }}</button>
</div>
<div class="group-body attr-body" v-show="sectionOpen('attr')">
<div class="attr-section-title">{{ $t('attributes.initialParams') }}</div>
@@ -1,12 +1,12 @@
<template>
<div class="spine-export-actions">
<button type="button" class="export-spine-json" :disabled="exportBusy" :title="exportBusy ? $t('export.baking') : $t('export.exportJsonTitle', { version: exportSettings.spineVersion })" @click="exportSpineJson">
<button type="button" class="export-spine-json" data-matomo-event="export.json" :disabled="exportBusy" :title="exportBusy ? $t('export.baking') : $t('export.exportJsonTitle', { version: exportSettings.spineVersion })" @click="exportSpineJson">
{{ exportBusy && exportTarget === 'json' ? $t('export.preparing') : $t('export.exportJson') }}
</button>
<button type="button" class="export-spine-images" :disabled="exportBusy" :title="$t('export.exportImagesTitle')" @click="exportSpineImages">
<button type="button" class="export-spine-images" data-matomo-event="export.images" :disabled="exportBusy" :title="$t('export.exportImagesTitle')" @click="exportSpineImages">
{{ exportBusy && exportTarget === 'images' ? $t('export.organizingImages') : $t('export.exportImages') }}
</button>
<button type="button" class="export-spine-project" :disabled="exportBusy || !connectorReady" :title="connectorButtonTitle" @click="exportSpineProject">
<button type="button" class="export-spine-project" data-matomo-event="export.spine-project" :disabled="exportBusy || !connectorReady" :title="connectorButtonTitle" @click="exportSpineProject">
<span>{{ exportBusy && exportTarget === 'spine' ? $t('export.generatingProject') : $t('export.exportSpine') }}</span>
<small v-if="!exportBusy && connectorDisabledReason">{{ connectorDisabledReason }}</small>
</button>
@@ -3,7 +3,7 @@
<div class="group">
<div class="group-head" @click="toggle('mods')">
<span class="caret">{{ collapsed.mods ? '▸' : '▾' }}</span><span>{{ $t('modifiers.title') }}</span>
<button class="group-reset" :title="$t('modifiers.reset')" @click.stop="resetModule('mods')">{{ $t('common.reset') }}</button>
<button class="group-reset" data-matomo-event="modifiers.reset" :title="$t('modifiers.reset')" @click.stop="resetModule('mods')">{{ $t('common.reset') }}</button>
</div>
<div class="group-body" v-show="sectionOpen('mods')">
<div class="modifier-item damping-item">
@@ -142,7 +142,7 @@
<div v-if="sys.config.trail" class="modifier-params trail-params">
<div class="trail-section-head">
<div class="trail-section-title">{{ $t('modifiers.trailImages') }}</div>
<button class="image-add" :title="$t('modifiers.addTrailImage')" @click="addTrailResource">+</button>
<button class="image-add" data-matomo-event="resources.add-trail-image" :title="$t('modifiers.addTrailImage')" @click="addTrailResource">+</button>
</div>
<ImageResourceCard
v-for="resource in sys.config.trailResources"
@@ -2,12 +2,12 @@
<div class="group config-management">
<div class="group-head" @click="toggle('config')">
<span class="caret">{{ collapsed.config ? '▸' : '▾' }}</span><span>{{ $t('config.title') }}</span>
<button type="button" class="group-download" @click.stop="downloadCurrentProject">{{ $t('config.local.downloadCurrent') }}</button>
<button type="button" class="group-download" data-matomo-event="config.download-current" @click.stop="downloadCurrentProject">{{ $t('config.local.downloadCurrent') }}</button>
</div>
<div class="group-body config-management-body" v-show="sectionOpen('config')">
<div class="config-toolbar">
<button :title="$t('config.saveTitle')" @click="saveConfig">{{ $t('config.save') }}</button>
<button :title="$t('config.loadTitle')" @click="configFileInput?.click()">{{ $t('config.load') }}</button>
<button :title="$t('config.saveTitle')" data-matomo-event="config.save" @click="saveConfig">{{ $t('config.save') }}</button>
<button :title="$t('config.loadTitle')" data-matomo-event="config.load-file" @click="configFileInput?.click()">{{ $t('config.load') }}</button>
<select v-model="selectedPreset" :aria-label="$t('config.presets')" :disabled="!presetOptions.length || presetLoading" @pointerdown="refreshPresets" @focus="refreshPresets" @change="loadSelectedPreset">
<option value="">{{ presetOptions.length ? $t('config.selectPreset') : $t('config.noPresets') }}</option>
<option v-for="preset in presetOptions" :key="preset.file" :value="preset.file">{{ presetDisplayName(preset) }}</option>
@@ -35,18 +35,18 @@
<span class="project-name">{{ project.name }}</span>
<span v-if="store.settings.showProjectSize" class="project-size">{{ formatProjectSize(project.size) }}</span>
<div class="project-actions" @dblclick.stop>
<button type="button" @click.stop="removeLocalProject(project)">{{ $t('config.local.delete') }}</button>
<button type="button" @click.stop="downloadLocalProject(project)">{{ $t('config.local.download') }}</button>
<button type="button" data-matomo-event="config.delete-project" @click.stop="removeLocalProject(project)">{{ $t('config.local.delete') }}</button>
<button type="button" data-matomo-event="config.download-project" @click.stop="downloadLocalProject(project)">{{ $t('config.local.download') }}</button>
</div>
</div>
</div>
<div v-else class="project-empty">{{ $t('config.local.empty') }}</div>
</div>
<div class="project-bulk-actions">
<button type="button" :disabled="projectStorageBusy" @click="downloadAllLocalProjects">
<button type="button" :disabled="projectStorageBusy" data-matomo-event="config.download-all" @click="downloadAllLocalProjects">
{{ $t('config.local.downloadAll') }}
</button>
<button type="button" :disabled="projectStorageBusy" @click="projectFilesInput?.click()">
<button type="button" :disabled="projectStorageBusy" data-matomo-event="config.load-all" @click="projectFilesInput?.click()">
{{ $t('config.local.loadAll') }}
</button>
<input ref="projectFilesInput" hidden type="file" multiple accept=".json,application/json" @change="loadAllProjectFiles" />
@@ -4,11 +4,11 @@
<div class="group-head scene-head" @click="toggle('scene')">
<span class="caret">{{ collapsed.scene ? '▸' : '▾' }}</span><span>{{ $t('scene.title') }}</span>
<div class="scene-actions">
<button class="scene-add" :title="$t('scene.addParticle')" @click.stop="addSys">{{ $t('scene.addParticleShort') }}</button>
<button class="scene-add" :title="$t('scene.addCollider')" @click.stop="addCollider">{{ $t('scene.addColliderShort') }}</button>
<button class="scene-add" :title="$t('scene.addPath')" @click.stop="addPath">{{ $t('scene.addPathShort') }}</button>
<button class="scene-add" :title="$t('scene.addSpine')" @click.stop="addSpine">+Spine</button>
<button class="scene-add" :disabled="!canCopyObject" :title="$t('scene.copyTitle')" @click.stop="copySelectedObject">+Copy</button>
<button class="scene-add" data-matomo-event="scene.add-particle" :title="$t('scene.addParticle')" @click.stop="addSys">{{ $t('scene.addParticleShort') }}</button>
<button class="scene-add" data-matomo-event="scene.add-collider" :title="$t('scene.addCollider')" @click.stop="addCollider">{{ $t('scene.addColliderShort') }}</button>
<button class="scene-add" data-matomo-event="scene.add-path" :title="$t('scene.addPath')" @click.stop="addPath">{{ $t('scene.addPathShort') }}</button>
<button class="scene-add" data-matomo-event="scene.add-spine" :title="$t('scene.addSpine')" @click.stop="addSpine">+Spine</button>
<button class="scene-add" data-matomo-event="scene.copy" :disabled="!canCopyObject" :title="$t('scene.copyTitle')" @click.stop="copySelectedObject">+Copy</button>
</div>
</div>
<div class="group-body" v-show="sectionOpen('scene')">
@@ -24,11 +24,11 @@
<span v-if="entry.depth > 0" class="sub-branch">└</span>
<span v-else class="tdot">●</span>
<span class="tlabel">{{ entry.system.config.name || 'ParticleSystem' }}</span>
<button class="scene-object-eye" :class="{ off: entry.system.visible === false }" :title="entry.system.visible === false ? $t('scene.showParticle') : $t('scene.hideParticle')" :aria-label="entry.system.visible === false ? $t('scene.showParticle') : $t('scene.hideParticle')" @click.stop="entry.system.visible = entry.system.visible === false">
<button class="scene-object-eye" data-matomo-event="scene.toggle-particle" :class="{ off: entry.system.visible === false }" :title="entry.system.visible === false ? $t('scene.showParticle') : $t('scene.hideParticle')" :aria-label="entry.system.visible === false ? $t('scene.showParticle') : $t('scene.hideParticle')" @click.stop="entry.system.visible = entry.system.visible === false">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M2.5 12s3.5-6 9.5-6 9.5 6 9.5 6-3.5 6-9.5 6-9.5-6-9.5-6Z"/><circle cx="12" cy="12" r="2.8"/><path v-if="entry.system.visible === false" class="eye-slash" d="M4 4l16 16"/></svg>
</button>
<span class="scene-object-kind" :class="{ 'sub-emitter-kind': entry.depth > 0 }">{{ entry.depth > 0 ? $t('scene.subEmitter') : $t('scene.particle') }}</span>
<button class="scene-object-delete" :title="$t('scene.deleteParticle')" @click.stop="store.removeSystem(entry.system.id)">✕</button>
<button class="scene-object-delete" data-matomo-event="scene.delete-particle" :title="$t('scene.deleteParticle')" @click.stop="store.removeSystem(entry.system.id)">✕</button>
</div>
<div
v-for="collider in store.colliders"
@@ -39,11 +39,11 @@
>
<span class="tdot collision-dot">■</span>
<span class="tlabel">{{ collider.name }}</span>
<button class="scene-object-eye" :class="{ off: collider.visible === false }" :title="collider.visible === false ? $t('scene.showCollider') : $t('scene.hideCollider')" :aria-label="collider.visible === false ? $t('scene.showCollider') : $t('scene.hideCollider')" @click.stop="collider.visible = collider.visible === false">
<button class="scene-object-eye" data-matomo-event="scene.toggle-collider" :class="{ off: collider.visible === false }" :title="collider.visible === false ? $t('scene.showCollider') : $t('scene.hideCollider')" :aria-label="collider.visible === false ? $t('scene.showCollider') : $t('scene.hideCollider')" @click.stop="collider.visible = collider.visible === false">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M2.5 12s3.5-6 9.5-6 9.5 6 9.5 6-3.5 6-9.5 6-9.5-6-9.5-6Z"/><circle cx="12" cy="12" r="2.8"/><path v-if="collider.visible === false" class="eye-slash" d="M4 4l16 16"/></svg>
</button>
<span class="scene-object-kind">{{ $t('scene.collision') }}</span>
<button class="scene-object-delete" :title="$t('scene.deleteCollider')" @click.stop="store.removeCollider(collider.id)">✕</button>
<button class="scene-object-delete" data-matomo-event="scene.delete-collider" :title="$t('scene.deleteCollider')" @click.stop="store.removeCollider(collider.id)">✕</button>
</div>
<div
v-for="path in store.paths"
@@ -54,11 +54,11 @@
>
<span class="tdot path-dot">◇</span>
<span class="tlabel">{{ path.name }}</span>
<button class="scene-object-eye" :class="{ off: path.visible === false }" :title="path.visible === false ? $t('scene.showPath') : $t('scene.hidePath')" :aria-label="path.visible === false ? $t('scene.showPath') : $t('scene.hidePath')" @click.stop="path.visible = path.visible === false">
<button class="scene-object-eye" data-matomo-event="scene.toggle-path" :class="{ off: path.visible === false }" :title="path.visible === false ? $t('scene.showPath') : $t('scene.hidePath')" :aria-label="path.visible === false ? $t('scene.showPath') : $t('scene.hidePath')" @click.stop="path.visible = path.visible === false">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M2.5 12s3.5-6 9.5-6 9.5 6 9.5 6-3.5 6-9.5 6-9.5-6-9.5-6Z"/><circle cx="12" cy="12" r="2.8"/><path v-if="path.visible === false" class="eye-slash" d="M4 4l16 16"/></svg>
</button>
<span class="scene-object-kind">{{ $t('scene.path') }}</span>
<button class="scene-object-delete" :title="$t('scene.deletePath')" @click.stop="store.removePath(path.id)">✕</button>
<button class="scene-object-delete" data-matomo-event="scene.delete-path" :title="$t('scene.deletePath')" @click.stop="store.removePath(path.id)">✕</button>
</div>
<div
v-for="spine in store.spines"
@@ -69,11 +69,11 @@
>
<span class="tdot spine-dot">◆</span>
<span class="tlabel">{{ spine.name }}</span>
<button class="scene-object-eye" :class="{ off: spine.visible === false }" :title="spine.visible === false ? $t('scene.showSpine') : $t('scene.hideSpine')" :aria-label="spine.visible === false ? $t('scene.showSpine') : $t('scene.hideSpine')" @click.stop="spine.visible = spine.visible === false">
<button class="scene-object-eye" data-matomo-event="scene.toggle-spine" :class="{ off: spine.visible === false }" :title="spine.visible === false ? $t('scene.showSpine') : $t('scene.hideSpine')" :aria-label="spine.visible === false ? $t('scene.showSpine') : $t('scene.hideSpine')" @click.stop="spine.visible = spine.visible === false">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M2.5 12s3.5-6 9.5-6 9.5 6 9.5 6-3.5 6-9.5 6-9.5-6-9.5-6Z"/><circle cx="12" cy="12" r="2.8"/><path v-if="spine.visible === false" class="eye-slash" d="M4 4l16 16"/></svg>
</button>
<span class="scene-object-kind">Spine</span>
<button class="scene-object-delete" :title="$t('scene.deleteSpine')" @click.stop="store.removeSpine(spine.id)">✕</button>
<button class="scene-object-delete" data-matomo-event="scene.delete-spine" :title="$t('scene.deleteSpine')" @click.stop="store.removeSpine(spine.id)">✕</button>
</div>
<div v-if="!store.systems.length && !store.colliders.length && !store.paths.length && !store.spines.length" class="empty">{{ $t('scene.empty') }}</div>
</div>
@@ -89,7 +89,7 @@
<div class="seed-row scene-seed">
<label for="system-seed">{{ $t('scene.seed') }}</label>
<input id="system-seed" class="seed-input" type="number" min="0" step="1" v-model.number="sys.config.seed" :title="$t('scene.seedTitle')" />
<button class="seed-random" :title="$t('scene.randomizeSeed')" @click="randomizeSeed">⚄</button>
<button class="seed-random" data-matomo-event="scene.randomize-seed" :title="$t('scene.randomizeSeed')" @click="randomizeSeed">⚄</button>
</div>
<div class="seed-hint">{{ $t('scene.seedHint') }}</div>
</template>