sparkfx 1.2.1 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -12
- package/dist/{chunk-YLY5N62U.cjs → chunk-3AVUTKJ5.cjs} +8 -8
- package/dist/{chunk-YLY5N62U.cjs.map → chunk-3AVUTKJ5.cjs.map} +1 -1
- package/dist/{chunk-RD5XCTW4.js → chunk-FPJZKZGF.js} +3 -3
- package/dist/{chunk-RD5XCTW4.js.map → chunk-FPJZKZGF.js.map} +1 -1
- package/dist/{chunk-KXPTBR5B.cjs → chunk-GHLFOSXQ.cjs} +3 -3
- package/dist/{chunk-KXPTBR5B.cjs.map → chunk-GHLFOSXQ.cjs.map} +1 -1
- package/dist/{chunk-Y5V7MOLA.cjs → chunk-HB6NE443.cjs} +3 -3
- package/dist/{chunk-Y5V7MOLA.cjs.map → chunk-HB6NE443.cjs.map} +1 -1
- package/dist/{chunk-5YDUWTOY.js → chunk-LPB7JTCR.js} +3 -3
- package/dist/{chunk-5YDUWTOY.js.map → chunk-LPB7JTCR.js.map} +1 -1
- package/dist/{chunk-4BGOBPG6.js → chunk-SJKJ2GZW.js} +8 -8
- package/dist/{chunk-4BGOBPG6.js.map → chunk-SJKJ2GZW.js.map} +1 -1
- package/dist/headless.cjs +1 -1
- package/dist/headless.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +4 -5
- package/dist/index.d.ts +4 -5
- package/dist/index.js +1 -1
- package/dist/next.cjs +2 -2
- package/dist/next.js +1 -1
- package/dist/react.cjs +1 -1
- package/dist/react.js +1 -1
- package/dist/shadcn.cjs +2 -2
- package/dist/shadcn.js +1 -1
- package/dist/svelte.cjs +2 -2
- package/dist/svelte.js +1 -1
- package/dist/tailwind.cjs +1 -1
- package/dist/tailwind.js +1 -1
- package/dist/testing.cjs +2 -2
- package/dist/testing.js +1 -1
- package/dist/vue.cjs +2 -2
- package/dist/vue.js +1 -1
- package/package.json +2 -7
- package/dist/chunk-E3PKCBIJ.cjs +0 -299
- package/dist/chunk-E3PKCBIJ.cjs.map +0 -1
- package/dist/chunk-RMXXT53J.js +0 -299
- package/dist/chunk-RMXXT53J.js.map +0 -1
- package/dist/devtools.cjs +0 -2
- package/dist/devtools.cjs.map +0 -1
- package/dist/devtools.d.cts +0 -65
- package/dist/devtools.d.ts +0 -65
- package/dist/devtools.js +0 -2
- package/dist/devtools.js.map +0 -1
package/dist/chunk-RMXXT53J.js
DELETED
|
@@ -1,299 +0,0 @@
|
|
|
1
|
-
import {b}from'./chunk-RD5XCTW4.js';/* sparkfx v1.2.1 - Premium micro-interactions with Event Bus, Testing Kit & Devtools */
|
|
2
|
-
var c=`
|
|
3
|
-
/* SparkFX Devtools Panel */
|
|
4
|
-
.sparkfx-devtools {
|
|
5
|
-
--sparkfx-bg: #1a1a2e;
|
|
6
|
-
--sparkfx-bg-secondary: #16213e;
|
|
7
|
-
--sparkfx-text: #eee;
|
|
8
|
-
--sparkfx-text-dim: #888;
|
|
9
|
-
--sparkfx-accent: #e94560;
|
|
10
|
-
--sparkfx-success: #4ade80;
|
|
11
|
-
--sparkfx-warning: #fbbf24;
|
|
12
|
-
--sparkfx-border: #333;
|
|
13
|
-
|
|
14
|
-
position: fixed;
|
|
15
|
-
z-index: 999999;
|
|
16
|
-
font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
|
|
17
|
-
font-size: 12px;
|
|
18
|
-
line-height: 1.4;
|
|
19
|
-
color: var(--sparkfx-text);
|
|
20
|
-
background: var(--sparkfx-bg);
|
|
21
|
-
border: 1px solid var(--sparkfx-border);
|
|
22
|
-
border-radius: 8px;
|
|
23
|
-
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
|
24
|
-
min-width: 320px;
|
|
25
|
-
max-width: 400px;
|
|
26
|
-
max-height: 80vh;
|
|
27
|
-
overflow: hidden;
|
|
28
|
-
user-select: none;
|
|
29
|
-
backdrop-filter: blur(8px);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
.sparkfx-devtools.top-right { top: 16px; right: 16px; }
|
|
33
|
-
.sparkfx-devtools.top-left { top: 16px; left: 16px; }
|
|
34
|
-
.sparkfx-devtools.bottom-right { bottom: 16px; right: 16px; }
|
|
35
|
-
.sparkfx-devtools.bottom-left { bottom: 16px; left: 16px; }
|
|
36
|
-
|
|
37
|
-
.sparkfx-devtools.light {
|
|
38
|
-
--sparkfx-bg: #ffffff;
|
|
39
|
-
--sparkfx-bg-secondary: #f5f5f5;
|
|
40
|
-
--sparkfx-text: #1a1a1a;
|
|
41
|
-
--sparkfx-text-dim: #666;
|
|
42
|
-
--sparkfx-border: #ddd;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
.sparkfx-devtools-header {
|
|
46
|
-
display: flex;
|
|
47
|
-
align-items: center;
|
|
48
|
-
justify-content: space-between;
|
|
49
|
-
padding: 8px 12px;
|
|
50
|
-
background: var(--sparkfx-bg-secondary);
|
|
51
|
-
border-bottom: 1px solid var(--sparkfx-border);
|
|
52
|
-
cursor: move;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
.sparkfx-devtools-title {
|
|
56
|
-
display: flex;
|
|
57
|
-
align-items: center;
|
|
58
|
-
gap: 8px;
|
|
59
|
-
font-weight: 600;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
.sparkfx-devtools-title::before {
|
|
63
|
-
content: '\u26A1';
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
.sparkfx-devtools-close {
|
|
67
|
-
background: none;
|
|
68
|
-
border: none;
|
|
69
|
-
color: var(--sparkfx-text-dim);
|
|
70
|
-
cursor: pointer;
|
|
71
|
-
padding: 4px;
|
|
72
|
-
font-size: 16px;
|
|
73
|
-
line-height: 1;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
.sparkfx-devtools-close:hover {
|
|
77
|
-
color: var(--sparkfx-accent);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
.sparkfx-devtools-metrics {
|
|
81
|
-
display: flex;
|
|
82
|
-
gap: 16px;
|
|
83
|
-
padding: 8px 12px;
|
|
84
|
-
background: var(--sparkfx-bg-secondary);
|
|
85
|
-
border-bottom: 1px solid var(--sparkfx-border);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
.sparkfx-metric {
|
|
89
|
-
display: flex;
|
|
90
|
-
flex-direction: column;
|
|
91
|
-
align-items: center;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
.sparkfx-metric-value {
|
|
95
|
-
font-size: 18px;
|
|
96
|
-
font-weight: bold;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
.sparkfx-metric-value.good { color: var(--sparkfx-success); }
|
|
100
|
-
.sparkfx-metric-value.warning { color: var(--sparkfx-warning); }
|
|
101
|
-
.sparkfx-metric-value.bad { color: var(--sparkfx-accent); }
|
|
102
|
-
|
|
103
|
-
.sparkfx-metric-label {
|
|
104
|
-
font-size: 10px;
|
|
105
|
-
color: var(--sparkfx-text-dim);
|
|
106
|
-
text-transform: uppercase;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
.sparkfx-devtools-controls {
|
|
110
|
-
display: flex;
|
|
111
|
-
gap: 8px;
|
|
112
|
-
padding: 8px 12px;
|
|
113
|
-
border-bottom: 1px solid var(--sparkfx-border);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
.sparkfx-btn {
|
|
117
|
-
background: var(--sparkfx-bg-secondary);
|
|
118
|
-
border: 1px solid var(--sparkfx-border);
|
|
119
|
-
color: var(--sparkfx-text);
|
|
120
|
-
padding: 4px 12px;
|
|
121
|
-
border-radius: 4px;
|
|
122
|
-
cursor: pointer;
|
|
123
|
-
font-size: 11px;
|
|
124
|
-
font-family: inherit;
|
|
125
|
-
transition: all 0.15s;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
.sparkfx-btn:hover {
|
|
129
|
-
background: var(--sparkfx-accent);
|
|
130
|
-
border-color: var(--sparkfx-accent);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
.sparkfx-btn.active {
|
|
134
|
-
background: var(--sparkfx-accent);
|
|
135
|
-
border-color: var(--sparkfx-accent);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
.sparkfx-devtools-list {
|
|
139
|
-
max-height: 300px;
|
|
140
|
-
overflow-y: auto;
|
|
141
|
-
padding: 8px;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
.sparkfx-animation-item {
|
|
145
|
-
display: flex;
|
|
146
|
-
align-items: center;
|
|
147
|
-
gap: 8px;
|
|
148
|
-
padding: 6px 8px;
|
|
149
|
-
margin-bottom: 4px;
|
|
150
|
-
background: var(--sparkfx-bg-secondary);
|
|
151
|
-
border-radius: 4px;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
.sparkfx-animation-status {
|
|
155
|
-
width: 8px;
|
|
156
|
-
height: 8px;
|
|
157
|
-
border-radius: 50%;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
.sparkfx-animation-status.running { background: var(--sparkfx-success); }
|
|
161
|
-
.sparkfx-animation-status.paused { background: var(--sparkfx-warning); }
|
|
162
|
-
.sparkfx-animation-status.complete { background: var(--sparkfx-text-dim); }
|
|
163
|
-
|
|
164
|
-
.sparkfx-animation-info {
|
|
165
|
-
flex: 1;
|
|
166
|
-
min-width: 0;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
.sparkfx-animation-effect {
|
|
170
|
-
font-weight: 500;
|
|
171
|
-
white-space: nowrap;
|
|
172
|
-
overflow: hidden;
|
|
173
|
-
text-overflow: ellipsis;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
.sparkfx-animation-element {
|
|
177
|
-
font-size: 10px;
|
|
178
|
-
color: var(--sparkfx-text-dim);
|
|
179
|
-
white-space: nowrap;
|
|
180
|
-
overflow: hidden;
|
|
181
|
-
text-overflow: ellipsis;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
.sparkfx-animation-progress {
|
|
185
|
-
width: 60px;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
.sparkfx-progress-bar {
|
|
189
|
-
height: 4px;
|
|
190
|
-
background: var(--sparkfx-border);
|
|
191
|
-
border-radius: 2px;
|
|
192
|
-
overflow: hidden;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
.sparkfx-progress-fill {
|
|
196
|
-
height: 100%;
|
|
197
|
-
background: var(--sparkfx-accent);
|
|
198
|
-
border-radius: 2px;
|
|
199
|
-
transition: width 0.1s;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
.sparkfx-progress-text {
|
|
203
|
-
font-size: 10px;
|
|
204
|
-
text-align: right;
|
|
205
|
-
color: var(--sparkfx-text-dim);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
.sparkfx-devtools-empty {
|
|
209
|
-
padding: 24px;
|
|
210
|
-
text-align: center;
|
|
211
|
-
color: var(--sparkfx-text-dim);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
.sparkfx-devtools-footer {
|
|
215
|
-
padding: 6px 12px;
|
|
216
|
-
font-size: 10px;
|
|
217
|
-
color: var(--sparkfx-text-dim);
|
|
218
|
-
border-top: 1px solid var(--sparkfx-border);
|
|
219
|
-
display: flex;
|
|
220
|
-
justify-content: space-between;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
.sparkfx-warning-item {
|
|
224
|
-
display: flex;
|
|
225
|
-
align-items: center;
|
|
226
|
-
gap: 6px;
|
|
227
|
-
padding: 6px 12px;
|
|
228
|
-
background: rgba(251, 191, 36, 0.1);
|
|
229
|
-
border-bottom: 1px solid var(--sparkfx-border);
|
|
230
|
-
font-size: 11px;
|
|
231
|
-
color: var(--sparkfx-warning);
|
|
232
|
-
}
|
|
233
|
-
`,l=class{#r={shortcut:"Ctrl+Shift+S",position:"top-right",theme:"dark",showFps:true,showMemory:false,maxAnimations:20,updateInterval:100};#t=null;#s=null;#e=false;#n=false;#p=1;#a=new Map;#f=[];#o=[];#c=0;#d=null;#x=[];#i=[];constructor(){this.enable=this.enable.bind(this),this.disable=this.disable.bind(this),this.toggle=this.toggle.bind(this);}enable(){this.#e||typeof document>"u"||(this.#e=true,this.#k(),this.#w(),this.#L(),this.#M(),this.#C());}disable(){this.#e&&(this.#e=false,this.#y(),this.#b(),this.#$(),this.#S(),this.#I());}toggle(){this.#e?this.disable():this.enable();}pause(){this.#n=true,b.pause(),this.#l();}resume(){this.#n=false,b.resume(),this.#l();}slowMo(t){this.#p=Math.max(.1,Math.min(2,t)),this.#l();}exportLog(){let t={timestamp:new Date().toISOString(),version:"1.2.1",animations:Array.from(this.#a.values()),events:this.#f.slice(-100),warnings:this.#i,metrics:this.#h()},s=new Blob([JSON.stringify(t,null,2)],{type:"application/json"}),e=URL.createObjectURL(s),i=document.createElement("a");i.href=e,i.download=`sparkfx-log-${Date.now()}.json`,i.click(),URL.revokeObjectURL(e);}configure(t){this.#r={...this.#r,...t},this.#e&&this.#l();}get enabled(){return this.#e}#k(){this.#s||(this.#s=document.createElement("style"),this.#s.id="sparkfx-devtools-styles",this.#s.textContent=c,document.head.appendChild(this.#s));}#b(){this.#s&&(this.#s.remove(),this.#s=null);}#w(){if(this.#t)return;let t=document.createElement("div");t.className=`sparkfx-devtools ${this.#r.position} ${this.#r.theme}`,t.innerHTML=this.#m(),document.body.appendChild(t),this.#t=t,this.#v(),this.#E();}#y(){this.#t&&(this.#t.remove(),this.#t=null);}#m(){let t=this.#h(),s=Array.from(this.#a.values()).slice(0,this.#r.maxAnimations);return `
|
|
234
|
-
<div class="sparkfx-devtools-header">
|
|
235
|
-
<div class="sparkfx-devtools-title">SparkFX Devtools</div>
|
|
236
|
-
<button class="sparkfx-devtools-close" data-action="close">\xD7</button>
|
|
237
|
-
</div>
|
|
238
|
-
|
|
239
|
-
<div class="sparkfx-devtools-metrics">
|
|
240
|
-
<div class="sparkfx-metric">
|
|
241
|
-
<div class="sparkfx-metric-value ${this.#T(t.fps)}">${t.fps}</div>
|
|
242
|
-
<div class="sparkfx-metric-label">FPS</div>
|
|
243
|
-
</div>
|
|
244
|
-
<div class="sparkfx-metric">
|
|
245
|
-
<div class="sparkfx-metric-value">${t.animationCount}</div>
|
|
246
|
-
<div class="sparkfx-metric-label">Active</div>
|
|
247
|
-
</div>
|
|
248
|
-
<div class="sparkfx-metric">
|
|
249
|
-
<div class="sparkfx-metric-value ${t.cpuEstimate>50?"warning":""}">${t.cpuEstimate}%</div>
|
|
250
|
-
<div class="sparkfx-metric-label">CPU Est.</div>
|
|
251
|
-
</div>
|
|
252
|
-
</div>
|
|
253
|
-
|
|
254
|
-
${this.#i.length>0?`
|
|
255
|
-
<div class="sparkfx-warning-item">
|
|
256
|
-
\u26A0\uFE0F ${this.#i[this.#i.length-1]}
|
|
257
|
-
</div>
|
|
258
|
-
`:""}
|
|
259
|
-
|
|
260
|
-
<div class="sparkfx-devtools-controls">
|
|
261
|
-
<button class="sparkfx-btn ${this.#n?"":"active"}" data-action="pause">
|
|
262
|
-
${this.#n?"\u25B6 Resume":"\u23F8 Pause"}
|
|
263
|
-
</button>
|
|
264
|
-
<button class="sparkfx-btn ${this.#p<1?"active":""}" data-action="slowmo">
|
|
265
|
-
\u{1F422} ${this.#p}x
|
|
266
|
-
</button>
|
|
267
|
-
<button class="sparkfx-btn" data-action="export">
|
|
268
|
-
\u{1F4CB} Export
|
|
269
|
-
</button>
|
|
270
|
-
</div>
|
|
271
|
-
|
|
272
|
-
<div class="sparkfx-devtools-list">
|
|
273
|
-
${s.length===0?`
|
|
274
|
-
<div class="sparkfx-devtools-empty">
|
|
275
|
-
No active animations
|
|
276
|
-
</div>
|
|
277
|
-
`:s.map(e=>`
|
|
278
|
-
<div class="sparkfx-animation-item" data-id="${e.id}">
|
|
279
|
-
<div class="sparkfx-animation-status ${e.status}"></div>
|
|
280
|
-
<div class="sparkfx-animation-info">
|
|
281
|
-
<div class="sparkfx-animation-effect">${e.effect}</div>
|
|
282
|
-
<div class="sparkfx-animation-element">${e.element}</div>
|
|
283
|
-
</div>
|
|
284
|
-
<div class="sparkfx-animation-progress">
|
|
285
|
-
<div class="sparkfx-progress-bar">
|
|
286
|
-
<div class="sparkfx-progress-fill" style="width: ${e.progress*100}%"></div>
|
|
287
|
-
</div>
|
|
288
|
-
<div class="sparkfx-progress-text">${(e.progress*100).toFixed(0)}%</div>
|
|
289
|
-
</div>
|
|
290
|
-
</div>
|
|
291
|
-
`).join("")}
|
|
292
|
-
</div>
|
|
293
|
-
|
|
294
|
-
<div class="sparkfx-devtools-footer">
|
|
295
|
-
<span>v1.2.1</span>
|
|
296
|
-
<span>${this.#r.shortcut} to toggle</span>
|
|
297
|
-
</div>
|
|
298
|
-
`}#v(){this.#t&&this.#t.addEventListener("click",t=>{switch(t.target.dataset.action){case "close":this.disable();break;case "pause":this.#n?this.resume():this.pause();break;case "slowmo":let i=[1,.5,.25,2],o=(i.indexOf(this.#p)+1)%i.length;this.slowMo(i[o]??1);break;case "export":this.exportLog();break}});}#E(){if(!this.#t)return;let t=this.#t.querySelector(".sparkfx-devtools-header");if(!t)return;let s=false,e=0,i=0,r=0,o=0;t.addEventListener("mousedown",a=>{if(a.target.classList.contains("sparkfx-devtools-close"))return;s=true,e=a.clientX,i=a.clientY;let n=this.#t.getBoundingClientRect();r=n.left,o=n.top,this.#t.classList.remove("top-right","top-left","bottom-right","bottom-left"),this.#t.style.left=`${r}px`,this.#t.style.top=`${o}px`,this.#t.style.right="auto",this.#t.style.bottom="auto";}),document.addEventListener("mousemove",a=>{if(!s)return;let n=a.clientX-e,f=a.clientY-i;this.#t.style.left=`${r+n}px`,this.#t.style.top=`${o+f}px`;}),document.addEventListener("mouseup",()=>{s=false;});}#L(){document.addEventListener("keydown",this.#u);}#$(){document.removeEventListener("keydown",this.#u);}#u=t=>{t.ctrlKey&&t.shiftKey&&t.key.toLowerCase()==="s"&&(t.preventDefault(),this.toggle());};#M(){let t=b.on("*",s=>{if(this.#f.push(s),this.#f.length>1e3&&this.#f.shift(),s.animationId){let e=this.#a.get(s.animationId);e?(s.progress!==void 0&&(e.progress=s.progress),s.progress===1&&(e.status="complete",setTimeout(()=>{this.#a.delete(s.animationId);},1e3))):this.#a.set(s.animationId,{id:s.animationId,element:this.#F(s.element),effect:s.effect??"unknown",progress:s.progress??0,status:"running",startTime:s.timestamp,duration:300});}this.#P();});this.#x.push(t);}#S(){for(let t of this.#x)t();this.#x=[];}#C(){if(this.#d)return;let t=()=>{let s=performance.now();if(this.#c){let e=Math.round(1e3/(s-this.#c));this.#o.push(e),this.#o.length>60&&this.#o.shift();}this.#c=s,this.#e&&requestAnimationFrame(t);};requestAnimationFrame(t),this.#d=window.setInterval(()=>{this.#l();},this.#r.updateInterval);}#I(){this.#d&&(clearInterval(this.#d),this.#d=null);}#l(){this.#t&&(this.#t.innerHTML=this.#m(),this.#v());}#h(){let t=this.#o.length>0?Math.round(this.#o.reduce((i,r)=>i+r,0)/this.#o.length):60,s=Array.from(this.#a.values()).filter(i=>i.status==="running").length,e=Math.min(100,s*5);return {fps:t,animationCount:s,cpuEstimate:e}}#T(t){return t>=55?"good":t>=30?"warning":"bad"}#F(t){if(!t)return "unknown";let s=t.tagName.toLowerCase(),e=t.id?`#${t.id}`:"",i=t.className&&typeof t.className=="string"?`.${t.className.split(" ").filter(Boolean).slice(0,2).join(".")}`:"";return `${s}${e}${i}`||s}#P(){let t=this.#h();t.fps<30&&this.#g("Low FPS detected! Consider reducing animation complexity."),t.animationCount>10&&this.#g("Many concurrent animations. This may impact performance.");}#g(t){this.#i.includes(t)||(this.#i.push(t),this.#i.length>5&&this.#i.shift());}},x=new l;typeof window<"u"&&new URLSearchParams(window.location.search).has("sparkfx-debug")&&setTimeout(()=>x.enable(),100);export{l as a,x as b};//# sourceMappingURL=chunk-RMXXT53J.js.map
|
|
299
|
-
//# sourceMappingURL=chunk-RMXXT53J.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/devtools/index.ts"],"names":["DEVTOOLS_STYLES","SparkDevtools","#config","#panelElement","#styleElement","#isEnabled","#isPaused","#slowMoFactor","#animations","#eventHistory","#fpsHistory","#lastFrameTime","#updateIntervalId","#unsubscribers","#warnings","#injectStyles","#createPanel","#attachKeyboardShortcut","#subscribeToEvents","#startUpdateLoop","#removePanel","#removeStyles","#detachKeyboardShortcut","#unsubscribeFromEvents","#stopUpdateLoop","eventBus","#updateUI","factor","log","#getMetrics","blob","url","a","config","panel","#getPanelHTML","#attachPanelEvents","#makeDraggable","metrics","animations","#getFpsClass","anim","e","values","nextIndex","header","isDragging","startX","startY","startLeft","startTop","rect","dx","dy","#handleKeydown","unsub","payload","existing","#getElementDescription","#checkPerformance","measureFps","now","fps","avgFps","b","animationCount","cpuEstimate","element","tag","id","classes","#addWarning","message","devtools"],"mappings":"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","file":"chunk-RMXXT53J.js","sourcesContent":["/**\r\n * SparkFX Devtools - Browser Debugging Panel\r\n * \r\n * A floating panel that shows all active animations, performance metrics,\r\n * and provides controls for debugging animations.\r\n * \r\n * @example\r\n * ```typescript\r\n * import { devtools } from 'sparkfx'\r\n * \r\n * // Enable devtools (also works with Ctrl+Shift+S)\r\n * devtools.enable()\r\n * \r\n * // Programmatic controls\r\n * devtools.pause() // Pause all animations\r\n * devtools.resume() // Resume animations\r\n * devtools.slowMo(0.5) // Half speed\r\n * devtools.exportLog() // Export animation log\r\n * ```\r\n * \r\n * @version 1.2.1\r\n */\r\n\r\nimport { eventBus, type SparkEventPayload } from '../core/event-bus'\r\n\r\n// ============================================================================\r\n// TYPES\r\n// ============================================================================\r\n\r\n/** Animation info for display */\r\ninterface AnimationInfo {\r\n id: string\r\n element: string\r\n effect: string\r\n progress: number\r\n status: 'running' | 'paused' | 'complete'\r\n startTime: number\r\n duration: number\r\n}\r\n\r\n/** Performance metrics */\r\ninterface PerformanceMetrics {\r\n fps: number\r\n animationCount: number\r\n cpuEstimate: number\r\n memoryUsage?: number\r\n}\r\n\r\n/** Devtools configuration */\r\ninterface DevtoolsConfig {\r\n /** Keyboard shortcut to toggle panel */\r\n shortcut: string\r\n /** Panel position */\r\n position: 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left'\r\n /** Panel theme */\r\n theme: 'dark' | 'light' | 'auto'\r\n /** Show FPS counter */\r\n showFps: boolean\r\n /** Show memory usage */\r\n showMemory: boolean\r\n /** Max animations to display */\r\n maxAnimations: number\r\n /** Update interval in ms */\r\n updateInterval: number\r\n}\r\n\r\n// ============================================================================\r\n// STYLES\r\n// ============================================================================\r\n\r\nconst DEVTOOLS_STYLES = `\r\n/* SparkFX Devtools Panel */\r\n.sparkfx-devtools {\r\n --sparkfx-bg: #1a1a2e;\r\n --sparkfx-bg-secondary: #16213e;\r\n --sparkfx-text: #eee;\r\n --sparkfx-text-dim: #888;\r\n --sparkfx-accent: #e94560;\r\n --sparkfx-success: #4ade80;\r\n --sparkfx-warning: #fbbf24;\r\n --sparkfx-border: #333;\r\n \r\n position: fixed;\r\n z-index: 999999;\r\n font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;\r\n font-size: 12px;\r\n line-height: 1.4;\r\n color: var(--sparkfx-text);\r\n background: var(--sparkfx-bg);\r\n border: 1px solid var(--sparkfx-border);\r\n border-radius: 8px;\r\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);\r\n min-width: 320px;\r\n max-width: 400px;\r\n max-height: 80vh;\r\n overflow: hidden;\r\n user-select: none;\r\n backdrop-filter: blur(8px);\r\n}\r\n\r\n.sparkfx-devtools.top-right { top: 16px; right: 16px; }\r\n.sparkfx-devtools.top-left { top: 16px; left: 16px; }\r\n.sparkfx-devtools.bottom-right { bottom: 16px; right: 16px; }\r\n.sparkfx-devtools.bottom-left { bottom: 16px; left: 16px; }\r\n\r\n.sparkfx-devtools.light {\r\n --sparkfx-bg: #ffffff;\r\n --sparkfx-bg-secondary: #f5f5f5;\r\n --sparkfx-text: #1a1a1a;\r\n --sparkfx-text-dim: #666;\r\n --sparkfx-border: #ddd;\r\n}\r\n\r\n.sparkfx-devtools-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 8px 12px;\r\n background: var(--sparkfx-bg-secondary);\r\n border-bottom: 1px solid var(--sparkfx-border);\r\n cursor: move;\r\n}\r\n\r\n.sparkfx-devtools-title {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n font-weight: 600;\r\n}\r\n\r\n.sparkfx-devtools-title::before {\r\n content: '⚡';\r\n}\r\n\r\n.sparkfx-devtools-close {\r\n background: none;\r\n border: none;\r\n color: var(--sparkfx-text-dim);\r\n cursor: pointer;\r\n padding: 4px;\r\n font-size: 16px;\r\n line-height: 1;\r\n}\r\n\r\n.sparkfx-devtools-close:hover {\r\n color: var(--sparkfx-accent);\r\n}\r\n\r\n.sparkfx-devtools-metrics {\r\n display: flex;\r\n gap: 16px;\r\n padding: 8px 12px;\r\n background: var(--sparkfx-bg-secondary);\r\n border-bottom: 1px solid var(--sparkfx-border);\r\n}\r\n\r\n.sparkfx-metric {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n}\r\n\r\n.sparkfx-metric-value {\r\n font-size: 18px;\r\n font-weight: bold;\r\n}\r\n\r\n.sparkfx-metric-value.good { color: var(--sparkfx-success); }\r\n.sparkfx-metric-value.warning { color: var(--sparkfx-warning); }\r\n.sparkfx-metric-value.bad { color: var(--sparkfx-accent); }\r\n\r\n.sparkfx-metric-label {\r\n font-size: 10px;\r\n color: var(--sparkfx-text-dim);\r\n text-transform: uppercase;\r\n}\r\n\r\n.sparkfx-devtools-controls {\r\n display: flex;\r\n gap: 8px;\r\n padding: 8px 12px;\r\n border-bottom: 1px solid var(--sparkfx-border);\r\n}\r\n\r\n.sparkfx-btn {\r\n background: var(--sparkfx-bg-secondary);\r\n border: 1px solid var(--sparkfx-border);\r\n color: var(--sparkfx-text);\r\n padding: 4px 12px;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n font-size: 11px;\r\n font-family: inherit;\r\n transition: all 0.15s;\r\n}\r\n\r\n.sparkfx-btn:hover {\r\n background: var(--sparkfx-accent);\r\n border-color: var(--sparkfx-accent);\r\n}\r\n\r\n.sparkfx-btn.active {\r\n background: var(--sparkfx-accent);\r\n border-color: var(--sparkfx-accent);\r\n}\r\n\r\n.sparkfx-devtools-list {\r\n max-height: 300px;\r\n overflow-y: auto;\r\n padding: 8px;\r\n}\r\n\r\n.sparkfx-animation-item {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 6px 8px;\r\n margin-bottom: 4px;\r\n background: var(--sparkfx-bg-secondary);\r\n border-radius: 4px;\r\n}\r\n\r\n.sparkfx-animation-status {\r\n width: 8px;\r\n height: 8px;\r\n border-radius: 50%;\r\n}\r\n\r\n.sparkfx-animation-status.running { background: var(--sparkfx-success); }\r\n.sparkfx-animation-status.paused { background: var(--sparkfx-warning); }\r\n.sparkfx-animation-status.complete { background: var(--sparkfx-text-dim); }\r\n\r\n.sparkfx-animation-info {\r\n flex: 1;\r\n min-width: 0;\r\n}\r\n\r\n.sparkfx-animation-effect {\r\n font-weight: 500;\r\n white-space: nowrap;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n}\r\n\r\n.sparkfx-animation-element {\r\n font-size: 10px;\r\n color: var(--sparkfx-text-dim);\r\n white-space: nowrap;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n}\r\n\r\n.sparkfx-animation-progress {\r\n width: 60px;\r\n}\r\n\r\n.sparkfx-progress-bar {\r\n height: 4px;\r\n background: var(--sparkfx-border);\r\n border-radius: 2px;\r\n overflow: hidden;\r\n}\r\n\r\n.sparkfx-progress-fill {\r\n height: 100%;\r\n background: var(--sparkfx-accent);\r\n border-radius: 2px;\r\n transition: width 0.1s;\r\n}\r\n\r\n.sparkfx-progress-text {\r\n font-size: 10px;\r\n text-align: right;\r\n color: var(--sparkfx-text-dim);\r\n}\r\n\r\n.sparkfx-devtools-empty {\r\n padding: 24px;\r\n text-align: center;\r\n color: var(--sparkfx-text-dim);\r\n}\r\n\r\n.sparkfx-devtools-footer {\r\n padding: 6px 12px;\r\n font-size: 10px;\r\n color: var(--sparkfx-text-dim);\r\n border-top: 1px solid var(--sparkfx-border);\r\n display: flex;\r\n justify-content: space-between;\r\n}\r\n\r\n.sparkfx-warning-item {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 6px 12px;\r\n background: rgba(251, 191, 36, 0.1);\r\n border-bottom: 1px solid var(--sparkfx-border);\r\n font-size: 11px;\r\n color: var(--sparkfx-warning);\r\n}\r\n`\r\n\r\n// ============================================================================\r\n// DEVTOOLS CLASS\r\n// ============================================================================\r\n\r\nclass SparkDevtools {\r\n #config: DevtoolsConfig = {\r\n shortcut: 'Ctrl+Shift+S',\r\n position: 'top-right',\r\n theme: 'dark',\r\n showFps: true,\r\n showMemory: false,\r\n maxAnimations: 20,\r\n updateInterval: 100\r\n }\r\n\r\n #panelElement: HTMLElement | null = null\r\n #styleElement: HTMLStyleElement | null = null\r\n #isEnabled = false\r\n #isPaused = false\r\n #slowMoFactor = 1\r\n #animations = new Map<string, AnimationInfo>()\r\n #eventHistory: SparkEventPayload[] = []\r\n #fpsHistory: number[] = []\r\n #lastFrameTime = 0\r\n #updateIntervalId: number | null = null\r\n #unsubscribers: (() => void)[] = []\r\n #warnings: string[] = []\r\n\r\n constructor() {\r\n // Bind methods\r\n this.enable = this.enable.bind(this)\r\n this.disable = this.disable.bind(this)\r\n this.toggle = this.toggle.bind(this)\r\n }\r\n\r\n // ============================================================================\r\n // PUBLIC API\r\n // ============================================================================\r\n\r\n /** Enable devtools */\r\n enable(): void {\r\n if (this.#isEnabled || typeof document === 'undefined') return\r\n\r\n this.#isEnabled = true\r\n this.#injectStyles()\r\n this.#createPanel()\r\n this.#attachKeyboardShortcut()\r\n this.#subscribeToEvents()\r\n this.#startUpdateLoop()\r\n }\r\n\r\n /** Disable devtools */\r\n disable(): void {\r\n if (!this.#isEnabled) return\r\n\r\n this.#isEnabled = false\r\n this.#removePanel()\r\n this.#removeStyles()\r\n this.#detachKeyboardShortcut()\r\n this.#unsubscribeFromEvents()\r\n this.#stopUpdateLoop()\r\n }\r\n\r\n /** Toggle devtools visibility */\r\n toggle(): void {\r\n if (this.#isEnabled) {\r\n this.disable()\r\n } else {\r\n this.enable()\r\n }\r\n }\r\n\r\n /** Pause all animations */\r\n pause(): void {\r\n this.#isPaused = true\r\n eventBus.pause()\r\n this.#updateUI()\r\n }\r\n\r\n /** Resume all animations */\r\n resume(): void {\r\n this.#isPaused = false\r\n eventBus.resume()\r\n this.#updateUI()\r\n }\r\n\r\n /** Set slow motion factor */\r\n slowMo(factor: number): void {\r\n this.#slowMoFactor = Math.max(0.1, Math.min(2, factor))\r\n // Note: Actual slow-mo would require modifying animation durations\r\n // This is a simplified implementation\r\n this.#updateUI()\r\n }\r\n\r\n /** Export animation log */\r\n exportLog(): void {\r\n const log = {\r\n timestamp: new Date().toISOString(),\r\n version: '1.2.1',\r\n animations: Array.from(this.#animations.values()),\r\n events: this.#eventHistory.slice(-100),\r\n warnings: this.#warnings,\r\n metrics: this.#getMetrics()\r\n }\r\n\r\n const blob = new Blob([JSON.stringify(log, null, 2)], { type: 'application/json' })\r\n const url = URL.createObjectURL(blob)\r\n const a = document.createElement('a')\r\n a.href = url\r\n a.download = `sparkfx-log-${Date.now()}.json`\r\n a.click()\r\n URL.revokeObjectURL(url)\r\n }\r\n\r\n /** Configure devtools */\r\n configure(config: Partial<DevtoolsConfig>): void {\r\n this.#config = { ...this.#config, ...config }\r\n if (this.#isEnabled) {\r\n this.#updateUI()\r\n }\r\n }\r\n\r\n /** Check if devtools is enabled */\r\n get enabled(): boolean {\r\n return this.#isEnabled\r\n }\r\n\r\n // ============================================================================\r\n // PRIVATE METHODS\r\n // ============================================================================\r\n\r\n #injectStyles(): void {\r\n if (this.#styleElement) return\r\n\r\n this.#styleElement = document.createElement('style')\r\n this.#styleElement.id = 'sparkfx-devtools-styles'\r\n this.#styleElement.textContent = DEVTOOLS_STYLES\r\n document.head.appendChild(this.#styleElement)\r\n }\r\n\r\n #removeStyles(): void {\r\n if (this.#styleElement) {\r\n this.#styleElement.remove()\r\n this.#styleElement = null\r\n }\r\n }\r\n\r\n #createPanel(): void {\r\n if (this.#panelElement) return\r\n\r\n const panel = document.createElement('div')\r\n panel.className = `sparkfx-devtools ${this.#config.position} ${this.#config.theme}`\r\n panel.innerHTML = this.#getPanelHTML()\r\n\r\n document.body.appendChild(panel)\r\n this.#panelElement = panel\r\n\r\n // Attach panel event listeners\r\n this.#attachPanelEvents()\r\n\r\n // Make draggable\r\n this.#makeDraggable()\r\n }\r\n\r\n #removePanel(): void {\r\n if (this.#panelElement) {\r\n this.#panelElement.remove()\r\n this.#panelElement = null\r\n }\r\n }\r\n\r\n #getPanelHTML(): string {\r\n const metrics = this.#getMetrics()\r\n const animations = Array.from(this.#animations.values())\r\n .slice(0, this.#config.maxAnimations)\r\n\r\n return `\r\n <div class=\"sparkfx-devtools-header\">\r\n <div class=\"sparkfx-devtools-title\">SparkFX Devtools</div>\r\n <button class=\"sparkfx-devtools-close\" data-action=\"close\">×</button>\r\n </div>\r\n \r\n <div class=\"sparkfx-devtools-metrics\">\r\n <div class=\"sparkfx-metric\">\r\n <div class=\"sparkfx-metric-value ${this.#getFpsClass(metrics.fps)}\">${metrics.fps}</div>\r\n <div class=\"sparkfx-metric-label\">FPS</div>\r\n </div>\r\n <div class=\"sparkfx-metric\">\r\n <div class=\"sparkfx-metric-value\">${metrics.animationCount}</div>\r\n <div class=\"sparkfx-metric-label\">Active</div>\r\n </div>\r\n <div class=\"sparkfx-metric\">\r\n <div class=\"sparkfx-metric-value ${metrics.cpuEstimate > 50 ? 'warning' : ''}\">${metrics.cpuEstimate}%</div>\r\n <div class=\"sparkfx-metric-label\">CPU Est.</div>\r\n </div>\r\n </div>\r\n \r\n ${this.#warnings.length > 0 ? `\r\n <div class=\"sparkfx-warning-item\">\r\n ⚠️ ${this.#warnings[this.#warnings.length - 1]}\r\n </div>\r\n ` : ''}\r\n \r\n <div class=\"sparkfx-devtools-controls\">\r\n <button class=\"sparkfx-btn ${this.#isPaused ? '' : 'active'}\" data-action=\"pause\">\r\n ${this.#isPaused ? '▶ Resume' : '⏸ Pause'}\r\n </button>\r\n <button class=\"sparkfx-btn ${this.#slowMoFactor < 1 ? 'active' : ''}\" data-action=\"slowmo\">\r\n 🐢 ${this.#slowMoFactor}x\r\n </button>\r\n <button class=\"sparkfx-btn\" data-action=\"export\">\r\n 📋 Export\r\n </button>\r\n </div>\r\n \r\n <div class=\"sparkfx-devtools-list\">\r\n ${animations.length === 0 ? `\r\n <div class=\"sparkfx-devtools-empty\">\r\n No active animations\r\n </div>\r\n ` : animations.map(anim => `\r\n <div class=\"sparkfx-animation-item\" data-id=\"${anim.id}\">\r\n <div class=\"sparkfx-animation-status ${anim.status}\"></div>\r\n <div class=\"sparkfx-animation-info\">\r\n <div class=\"sparkfx-animation-effect\">${anim.effect}</div>\r\n <div class=\"sparkfx-animation-element\">${anim.element}</div>\r\n </div>\r\n <div class=\"sparkfx-animation-progress\">\r\n <div class=\"sparkfx-progress-bar\">\r\n <div class=\"sparkfx-progress-fill\" style=\"width: ${anim.progress * 100}%\"></div>\r\n </div>\r\n <div class=\"sparkfx-progress-text\">${(anim.progress * 100).toFixed(0)}%</div>\r\n </div>\r\n </div>\r\n `).join('')}\r\n </div>\r\n \r\n <div class=\"sparkfx-devtools-footer\">\r\n <span>v1.2.1</span>\r\n <span>${this.#config.shortcut} to toggle</span>\r\n </div>\r\n `\r\n }\r\n\r\n #attachPanelEvents(): void {\r\n if (!this.#panelElement) return\r\n\r\n this.#panelElement.addEventListener('click', (e) => {\r\n const target = e.target as HTMLElement\r\n const action = target.dataset.action\r\n\r\n switch (action) {\r\n case 'close':\r\n this.disable()\r\n break\r\n case 'pause':\r\n if (this.#isPaused) {\r\n this.resume()\r\n } else {\r\n this.pause()\r\n }\r\n break\r\n case 'slowmo':\r\n // Cycle through slow-mo values\r\n const values = [1, 0.5, 0.25, 2]\r\n const currentIndex = values.indexOf(this.#slowMoFactor)\r\n const nextIndex = (currentIndex + 1) % values.length\r\n this.slowMo(values[nextIndex] ?? 1)\r\n break\r\n case 'export':\r\n this.exportLog()\r\n break\r\n }\r\n })\r\n }\r\n\r\n #makeDraggable(): void {\r\n if (!this.#panelElement) return\r\n\r\n const header = this.#panelElement.querySelector('.sparkfx-devtools-header') as HTMLElement\r\n if (!header) return\r\n\r\n let isDragging = false\r\n let startX = 0\r\n let startY = 0\r\n let startLeft = 0\r\n let startTop = 0\r\n\r\n header.addEventListener('mousedown', (e) => {\r\n if ((e.target as HTMLElement).classList.contains('sparkfx-devtools-close')) return\r\n\r\n isDragging = true\r\n startX = e.clientX\r\n startY = e.clientY\r\n\r\n const rect = this.#panelElement!.getBoundingClientRect()\r\n startLeft = rect.left\r\n startTop = rect.top\r\n\r\n // Remove position classes and use absolute positioning\r\n this.#panelElement!.classList.remove('top-right', 'top-left', 'bottom-right', 'bottom-left')\r\n this.#panelElement!.style.left = `${startLeft}px`\r\n this.#panelElement!.style.top = `${startTop}px`\r\n this.#panelElement!.style.right = 'auto'\r\n this.#panelElement!.style.bottom = 'auto'\r\n })\r\n\r\n document.addEventListener('mousemove', (e) => {\r\n if (!isDragging) return\r\n\r\n const dx = e.clientX - startX\r\n const dy = e.clientY - startY\r\n\r\n this.#panelElement!.style.left = `${startLeft + dx}px`\r\n this.#panelElement!.style.top = `${startTop + dy}px`\r\n })\r\n\r\n document.addEventListener('mouseup', () => {\r\n isDragging = false\r\n })\r\n }\r\n\r\n #attachKeyboardShortcut(): void {\r\n document.addEventListener('keydown', this.#handleKeydown)\r\n }\r\n\r\n #detachKeyboardShortcut(): void {\r\n document.removeEventListener('keydown', this.#handleKeydown)\r\n }\r\n\r\n #handleKeydown = (e: KeyboardEvent): void => {\r\n // Ctrl+Shift+S\r\n if (e.ctrlKey && e.shiftKey && e.key.toLowerCase() === 's') {\r\n e.preventDefault()\r\n this.toggle()\r\n }\r\n }\r\n\r\n #subscribeToEvents(): void {\r\n // Subscribe to all animation events\r\n const unsub = eventBus.on('*', (payload) => {\r\n this.#eventHistory.push(payload)\r\n if (this.#eventHistory.length > 1000) {\r\n this.#eventHistory.shift()\r\n }\r\n\r\n // Update animation tracking\r\n if (payload.animationId) {\r\n const existing = this.#animations.get(payload.animationId)\r\n\r\n if (!existing) {\r\n this.#animations.set(payload.animationId, {\r\n id: payload.animationId,\r\n element: this.#getElementDescription(payload.element),\r\n effect: payload.effect ?? 'unknown',\r\n progress: payload.progress ?? 0,\r\n status: 'running',\r\n startTime: payload.timestamp,\r\n duration: 300\r\n })\r\n } else {\r\n if (payload.progress !== undefined) {\r\n existing.progress = payload.progress\r\n }\r\n\r\n // Check for completion\r\n if (payload.progress === 1) {\r\n existing.status = 'complete'\r\n // Remove after a short delay\r\n setTimeout(() => {\r\n this.#animations.delete(payload.animationId!)\r\n }, 1000)\r\n }\r\n }\r\n }\r\n\r\n // Check for performance warnings\r\n this.#checkPerformance()\r\n })\r\n\r\n this.#unsubscribers.push(unsub)\r\n }\r\n\r\n #unsubscribeFromEvents(): void {\r\n for (const unsub of this.#unsubscribers) {\r\n unsub()\r\n }\r\n this.#unsubscribers = []\r\n }\r\n\r\n #startUpdateLoop(): void {\r\n if (this.#updateIntervalId) return\r\n\r\n // FPS counter using requestAnimationFrame\r\n const measureFps = () => {\r\n const now = performance.now()\r\n if (this.#lastFrameTime) {\r\n const fps = Math.round(1000 / (now - this.#lastFrameTime))\r\n this.#fpsHistory.push(fps)\r\n if (this.#fpsHistory.length > 60) {\r\n this.#fpsHistory.shift()\r\n }\r\n }\r\n this.#lastFrameTime = now\r\n\r\n if (this.#isEnabled) {\r\n requestAnimationFrame(measureFps)\r\n }\r\n }\r\n requestAnimationFrame(measureFps)\r\n\r\n // UI update loop\r\n this.#updateIntervalId = window.setInterval(() => {\r\n this.#updateUI()\r\n }, this.#config.updateInterval)\r\n }\r\n\r\n #stopUpdateLoop(): void {\r\n if (this.#updateIntervalId) {\r\n clearInterval(this.#updateIntervalId)\r\n this.#updateIntervalId = null\r\n }\r\n }\r\n\r\n #updateUI(): void {\r\n if (!this.#panelElement) return\r\n this.#panelElement.innerHTML = this.#getPanelHTML()\r\n this.#attachPanelEvents()\r\n }\r\n\r\n #getMetrics(): PerformanceMetrics {\r\n const avgFps = this.#fpsHistory.length > 0\r\n ? Math.round(this.#fpsHistory.reduce((a, b) => a + b, 0) / this.#fpsHistory.length)\r\n : 60\r\n\r\n const animationCount = Array.from(this.#animations.values())\r\n .filter(a => a.status === 'running').length\r\n\r\n // Rough CPU estimate based on animation count\r\n const cpuEstimate = Math.min(100, animationCount * 5)\r\n\r\n return {\r\n fps: avgFps,\r\n animationCount,\r\n cpuEstimate\r\n }\r\n }\r\n\r\n #getFpsClass(fps: number): string {\r\n if (fps >= 55) return 'good'\r\n if (fps >= 30) return 'warning'\r\n return 'bad'\r\n }\r\n\r\n #getElementDescription(element: Element | null | undefined): string {\r\n if (!element) return 'unknown'\r\n\r\n const tag = element.tagName.toLowerCase()\r\n const id = element.id ? `#${element.id}` : ''\r\n const classes = element.className && typeof element.className === 'string'\r\n ? `.${element.className.split(' ').filter(Boolean).slice(0, 2).join('.')}`\r\n : ''\r\n\r\n return `${tag}${id}${classes}` || tag\r\n }\r\n\r\n #checkPerformance(): void {\r\n const metrics = this.#getMetrics()\r\n\r\n if (metrics.fps < 30) {\r\n this.#addWarning('Low FPS detected! Consider reducing animation complexity.')\r\n }\r\n\r\n if (metrics.animationCount > 10) {\r\n this.#addWarning('Many concurrent animations. This may impact performance.')\r\n }\r\n }\r\n\r\n #addWarning(message: string): void {\r\n // Avoid duplicate warnings\r\n if (!this.#warnings.includes(message)) {\r\n this.#warnings.push(message)\r\n if (this.#warnings.length > 5) {\r\n this.#warnings.shift()\r\n }\r\n }\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// SINGLETON EXPORT\r\n// ============================================================================\r\n\r\n/** Global devtools instance */\r\nexport const devtools = new SparkDevtools()\r\n\r\n// Auto-enable in development mode if URL has ?sparkfx-debug\r\nif (typeof window !== 'undefined') {\r\n const params = new URLSearchParams(window.location.search)\r\n if (params.has('sparkfx-debug')) {\r\n // Defer to allow page to load\r\n setTimeout(() => devtools.enable(), 100)\r\n }\r\n}\r\n\r\n// Export class for advanced usage\r\nexport { SparkDevtools }\r\n"]}
|
package/dist/devtools.cjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
'use strict';var chunkE3PKCBIJ_cjs=require('./chunk-E3PKCBIJ.cjs');require('./chunk-Y5V7MOLA.cjs');Object.defineProperty(exports,"SparkDevtools",{enumerable:true,get:function(){return chunkE3PKCBIJ_cjs.a}});Object.defineProperty(exports,"devtools",{enumerable:true,get:function(){return chunkE3PKCBIJ_cjs.b}});//# sourceMappingURL=devtools.cjs.map
|
|
2
|
-
//# sourceMappingURL=devtools.cjs.map
|
package/dist/devtools.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"devtools.cjs"}
|
package/dist/devtools.d.cts
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SparkFX Devtools - Browser Debugging Panel
|
|
3
|
-
*
|
|
4
|
-
* A floating panel that shows all active animations, performance metrics,
|
|
5
|
-
* and provides controls for debugging animations.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```typescript
|
|
9
|
-
* import { devtools } from 'sparkfx'
|
|
10
|
-
*
|
|
11
|
-
* // Enable devtools (also works with Ctrl+Shift+S)
|
|
12
|
-
* devtools.enable()
|
|
13
|
-
*
|
|
14
|
-
* // Programmatic controls
|
|
15
|
-
* devtools.pause() // Pause all animations
|
|
16
|
-
* devtools.resume() // Resume animations
|
|
17
|
-
* devtools.slowMo(0.5) // Half speed
|
|
18
|
-
* devtools.exportLog() // Export animation log
|
|
19
|
-
* ```
|
|
20
|
-
*
|
|
21
|
-
* @version 1.2.1
|
|
22
|
-
*/
|
|
23
|
-
/** Devtools configuration */
|
|
24
|
-
interface DevtoolsConfig {
|
|
25
|
-
/** Keyboard shortcut to toggle panel */
|
|
26
|
-
shortcut: string;
|
|
27
|
-
/** Panel position */
|
|
28
|
-
position: 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left';
|
|
29
|
-
/** Panel theme */
|
|
30
|
-
theme: 'dark' | 'light' | 'auto';
|
|
31
|
-
/** Show FPS counter */
|
|
32
|
-
showFps: boolean;
|
|
33
|
-
/** Show memory usage */
|
|
34
|
-
showMemory: boolean;
|
|
35
|
-
/** Max animations to display */
|
|
36
|
-
maxAnimations: number;
|
|
37
|
-
/** Update interval in ms */
|
|
38
|
-
updateInterval: number;
|
|
39
|
-
}
|
|
40
|
-
declare class SparkDevtools {
|
|
41
|
-
#private;
|
|
42
|
-
constructor();
|
|
43
|
-
/** Enable devtools */
|
|
44
|
-
enable(): void;
|
|
45
|
-
/** Disable devtools */
|
|
46
|
-
disable(): void;
|
|
47
|
-
/** Toggle devtools visibility */
|
|
48
|
-
toggle(): void;
|
|
49
|
-
/** Pause all animations */
|
|
50
|
-
pause(): void;
|
|
51
|
-
/** Resume all animations */
|
|
52
|
-
resume(): void;
|
|
53
|
-
/** Set slow motion factor */
|
|
54
|
-
slowMo(factor: number): void;
|
|
55
|
-
/** Export animation log */
|
|
56
|
-
exportLog(): void;
|
|
57
|
-
/** Configure devtools */
|
|
58
|
-
configure(config: Partial<DevtoolsConfig>): void;
|
|
59
|
-
/** Check if devtools is enabled */
|
|
60
|
-
get enabled(): boolean;
|
|
61
|
-
}
|
|
62
|
-
/** Global devtools instance */
|
|
63
|
-
declare const devtools: SparkDevtools;
|
|
64
|
-
|
|
65
|
-
export { SparkDevtools, devtools };
|
package/dist/devtools.d.ts
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SparkFX Devtools - Browser Debugging Panel
|
|
3
|
-
*
|
|
4
|
-
* A floating panel that shows all active animations, performance metrics,
|
|
5
|
-
* and provides controls for debugging animations.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```typescript
|
|
9
|
-
* import { devtools } from 'sparkfx'
|
|
10
|
-
*
|
|
11
|
-
* // Enable devtools (also works with Ctrl+Shift+S)
|
|
12
|
-
* devtools.enable()
|
|
13
|
-
*
|
|
14
|
-
* // Programmatic controls
|
|
15
|
-
* devtools.pause() // Pause all animations
|
|
16
|
-
* devtools.resume() // Resume animations
|
|
17
|
-
* devtools.slowMo(0.5) // Half speed
|
|
18
|
-
* devtools.exportLog() // Export animation log
|
|
19
|
-
* ```
|
|
20
|
-
*
|
|
21
|
-
* @version 1.2.1
|
|
22
|
-
*/
|
|
23
|
-
/** Devtools configuration */
|
|
24
|
-
interface DevtoolsConfig {
|
|
25
|
-
/** Keyboard shortcut to toggle panel */
|
|
26
|
-
shortcut: string;
|
|
27
|
-
/** Panel position */
|
|
28
|
-
position: 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left';
|
|
29
|
-
/** Panel theme */
|
|
30
|
-
theme: 'dark' | 'light' | 'auto';
|
|
31
|
-
/** Show FPS counter */
|
|
32
|
-
showFps: boolean;
|
|
33
|
-
/** Show memory usage */
|
|
34
|
-
showMemory: boolean;
|
|
35
|
-
/** Max animations to display */
|
|
36
|
-
maxAnimations: number;
|
|
37
|
-
/** Update interval in ms */
|
|
38
|
-
updateInterval: number;
|
|
39
|
-
}
|
|
40
|
-
declare class SparkDevtools {
|
|
41
|
-
#private;
|
|
42
|
-
constructor();
|
|
43
|
-
/** Enable devtools */
|
|
44
|
-
enable(): void;
|
|
45
|
-
/** Disable devtools */
|
|
46
|
-
disable(): void;
|
|
47
|
-
/** Toggle devtools visibility */
|
|
48
|
-
toggle(): void;
|
|
49
|
-
/** Pause all animations */
|
|
50
|
-
pause(): void;
|
|
51
|
-
/** Resume all animations */
|
|
52
|
-
resume(): void;
|
|
53
|
-
/** Set slow motion factor */
|
|
54
|
-
slowMo(factor: number): void;
|
|
55
|
-
/** Export animation log */
|
|
56
|
-
exportLog(): void;
|
|
57
|
-
/** Configure devtools */
|
|
58
|
-
configure(config: Partial<DevtoolsConfig>): void;
|
|
59
|
-
/** Check if devtools is enabled */
|
|
60
|
-
get enabled(): boolean;
|
|
61
|
-
}
|
|
62
|
-
/** Global devtools instance */
|
|
63
|
-
declare const devtools: SparkDevtools;
|
|
64
|
-
|
|
65
|
-
export { SparkDevtools, devtools };
|
package/dist/devtools.js
DELETED
package/dist/devtools.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"devtools.js"}
|