PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.7
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.7
2.0.13 2.0.12 2.0.11 2.0.10 2.0.9 trunk 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8
blockenberg / blocks / mouse-trail / frontend.js

frontend.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.7, at blocks/mouse-trail/frontend.js

326 lines 12.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function () {
2 'use strict';
3
4 function lerpColor(a, b, t) {
5 function parse(c) {
6 var m = /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(c);
7 return m ? [parseInt(m[1], 16), parseInt(m[2], 16), parseInt(m[3], 16)] : [200, 180, 100];
8 }
9 var ca = parse(a), cb = parse(b);
10 return 'rgba(' +
11 Math.round(ca[0] + (cb[0] - ca[0]) * t) + ',' +
12 Math.round(ca[1] + (cb[1] - ca[1]) * t) + ',' +
13 Math.round(ca[2] + (cb[2] - ca[2]) * t) + ',{A})';
14 }
15
16 function rainbow(i, total) {
17 return 'hsl(' + Math.round((i / total) * 360) + ',90%,65%)';
18 }
19
20 // Star polygon path
21 function starPath(ctx, cx, cy, r, spikes) {
22 var step = Math.PI / spikes;
23 ctx.beginPath();
24 for (var i = 0; i < spikes * 2; i++) {
25 var ang = i * step - Math.PI / 2;
26 var ri = i % 2 === 0 ? r : r * 0.45;
27 ctx.lineTo(cx + Math.cos(ang) * ri, cy + Math.sin(ang) * ri);
28 }
29 ctx.closePath();
30 }
31
32 function initMouseTrail(appEl) {
33 var raw = appEl.dataset.opts;
34 if (!raw) return;
35 var opts;
36 try { opts = JSON.parse(raw); } catch (e) { return; }
37
38 // Mobile check
39 if (!opts.showOnMobile && /Mobi|Android|iPhone|iPad/i.test(navigator.userAgent)) {
40 // Replace app element with a simple section (no trail)
41 buildSectionOnly(appEl, opts);
42 return;
43 }
44
45 var isPage = opts.scope === 'page';
46 var particles = [];
47 var hue = 0;
48 var mouseX = -1000, mouseY = -1000;
49
50 // ── Build DOM ────────────────────────────────────────────────
51 var section = document.createElement('div');
52 section.className = 'bkbg-mt-section';
53 section.style.height = (opts.sectionHeight || 200) + 'px';
54 section.style.backgroundColor = opts.sectionBg || '#1e1b4b';
55 section.style.borderRadius = (opts.sectionRadius || 16) + 'px';
56
57 if (opts.previewText) {
58 var lbl = document.createElement('div');
59 lbl.className = 'bkbg-mt-label';
60 lbl.textContent = opts.previewText;
61 section.appendChild(lbl);
62 }
63
64 var canvas = document.createElement('canvas');
65 var ctx;
66 if (isPage) {
67 canvas.className = 'bkbg-mt-canvas';
68 canvas.style.mixBlendMode = opts.mixBlend || 'normal';
69 document.body.appendChild(canvas);
70 canvas.width = window.innerWidth;
71 canvas.height = window.innerHeight;
72 window.addEventListener('resize', function () {
73 canvas.width = window.innerWidth;
74 canvas.height = window.innerHeight;
75 });
76 } else {
77 canvas.className = 'bkbg-mt-canvas-scoped';
78 canvas.style.mixBlendMode = opts.mixBlend || 'normal';
79 section.appendChild(canvas);
80 }
81 ctx = canvas.getContext('2d');
82
83 appEl.parentNode.replaceChild(section, appEl);
84
85 // ── Event listeners ──────────────────────────────────────────
86 var target = isPage ? window : section;
87
88 target.addEventListener('mousemove', function (e) {
89 if (isPage) {
90 mouseX = e.clientX;
91 mouseY = e.clientY;
92 } else {
93 var rect = section.getBoundingClientRect();
94 mouseX = e.clientX - rect.left;
95 mouseY = e.clientY - rect.top;
96 }
97 spawnParticle(mouseX, mouseY, 1);
98 });
99
100 if (opts.burstOnClick) {
101 (isPage ? window : section).addEventListener('click', function (e) {
102 var bx = mouseX, by = mouseY;
103 if (!isPage) {
104 var rect = section.getBoundingClientRect();
105 bx = e.clientX - rect.left;
106 by = e.clientY - rect.top;
107 }
108 for (var i = 0; i < (opts.burstCount || 20); i++) {
109 spawnParticle(bx, by, 2);
110 }
111 });
112 }
113
114 // ── Particle spawning ────────────────────────────────────────
115 function spawnParticle(x, y, sizeMult) {
116 if (particles.length > (opts.particleCount || 30)) return;
117 var angle = Math.random() * Math.PI * 2;
118 var speed = Math.random() * 2.5 + 0.5;
119 var spread = opts.spreadRadius || 20;
120 var ps = (opts.particleSize || 8) * (sizeMult || 1) * (0.6 + Math.random() * 0.8);
121 var style = opts.trailStyle || 'sparkle';
122 var col = getColor(particles.length, opts.particleCount);
123
124 particles.push({
125 x: x + (Math.random() - 0.5) * spread * 0.5,
126 y: y + (Math.random() - 0.5) * spread * 0.5,
127 vx: Math.cos(angle) * speed * (spread / 20),
128 vy: Math.sin(angle) * speed * (spread / 20),
129 size: ps,
130 color: col,
131 life: 1.0,
132 style: style,
133 rot: Math.random() * Math.PI * 2,
134 rotSpeed: (Math.random() - 0.5) * 0.15
135 });
136 }
137
138 function getColor(idx, total) {
139 var mode = opts.colorMode || 'gradient';
140 if (mode === 'rainbow') { hue = (hue + 8) % 360; return 'hsl(' + hue + ',90%,65%)'; }
141 if (mode === 'gradient') {
142 var t = Math.random();
143 return lerpColor(opts.color1 || '#f59e0b', opts.color2 || '#ec4899', t).replace('{A}', '1');
144 }
145 return opts.color1 || '#f59e0b';
146 }
147
148 // ── Draw loop ────────────────────────────────────────────────
149 var raf;
150 function draw() {
151 raf = requestAnimationFrame(draw);
152
153 if (isPage) {
154 ctx.clearRect(0, 0, canvas.width, canvas.height);
155 } else {
156 canvas.width = section.offsetWidth;
157 canvas.height = section.offsetHeight;
158 ctx.clearRect(0, 0, canvas.width, canvas.height);
159 }
160
161 var fadeSpeed = (opts.trailFade || 60) / 1000;
162 var gravity = opts.gravity !== undefined ? opts.gravity : 0.15;
163 var glow = opts.glowEffect;
164 var glowSz = opts.glowSize || 12;
165
166 for (var i = particles.length - 1; i >= 0; i--) {
167 var p = particles[i];
168 p.x += p.vx;
169 p.y += p.vy;
170 p.vy += gravity;
171 p.vx *= 0.97;
172 p.life -= fadeSpeed;
173 p.rot += p.rotSpeed;
174
175 if (p.life <= 0) { particles.splice(i, 1); continue; }
176
177 ctx.globalAlpha = Math.max(0, p.life);
178 if (glow) { ctx.shadowBlur = glowSz; ctx.shadowColor = p.color; }
179
180 drawParticle(p);
181 ctx.shadowBlur = 0;
182 }
183 ctx.globalAlpha = 1;
184 }
185
186 function drawParticle(p) {
187 ctx.fillStyle = p.color;
188 ctx.strokeStyle = p.color;
189
190 switch (p.style) {
191 case 'dots':
192 ctx.beginPath();
193 ctx.arc(p.x, p.y, p.size / 2, 0, Math.PI * 2);
194 ctx.fill();
195 break;
196
197 case 'sparkle':
198 ctx.save();
199 ctx.translate(p.x, p.y);
200 ctx.rotate(p.rot);
201 ctx.beginPath();
202 // 4-point sparkle (cross + 45° cross)
203 var s = p.size / 2;
204 for (var j = 0; j < 8; j++) {
205 var a = j * Math.PI / 4;
206 var r = j % 2 === 0 ? s : s * 0.3;
207 if (j === 0) ctx.moveTo(Math.cos(a) * r, Math.sin(a) * r);
208 else ctx.lineTo(Math.cos(a) * r, Math.sin(a) * r);
209 }
210 ctx.closePath();
211 ctx.fill();
212 ctx.restore();
213 break;
214
215 case 'stars':
216 ctx.save();
217 ctx.translate(p.x, p.y);
218 ctx.rotate(p.rot);
219 starPath(ctx, 0, 0, p.size / 2, 5);
220 ctx.fill();
221 ctx.restore();
222 break;
223
224 case 'comet':
225 ctx.save();
226 ctx.translate(p.x, p.y);
227 ctx.rotate(Math.atan2(p.vy, p.vx));
228 var tailLen = p.size * 4;
229 var grad = ctx.createLinearGradient(-tailLen, 0, p.size / 2, 0);
230 grad.addColorStop(0, 'rgba(255,255,255,0)');
231 grad.addColorStop(1, p.color);
232 ctx.fillStyle = grad;
233 ctx.beginPath();
234 ctx.ellipse(0, 0, tailLen / 2, p.size / 4, 0, 0, Math.PI * 2);
235 ctx.fill();
236 ctx.fillStyle = p.color;
237 ctx.beginPath();
238 ctx.arc(p.size / 2, 0, p.size / 2, 0, Math.PI * 2);
239 ctx.fill();
240 ctx.restore();
241 break;
242
243 case 'fire':
244 ctx.save();
245 ctx.translate(p.x, p.y);
246 var rg = ctx.createRadialGradient(0, 0, 0, 0, 0, p.size);
247 rg.addColorStop(0, '#fff9c4');
248 rg.addColorStop(0.4, '#ff6f00');
249 rg.addColorStop(1, 'rgba(255,0,0,0)');
250 ctx.fillStyle = rg;
251 ctx.beginPath();
252 ctx.arc(0, 0, p.size, 0, Math.PI * 2);
253 ctx.fill();
254 ctx.restore();
255 break;
256
257 case 'snow':
258 ctx.beginPath();
259 ctx.arc(p.x, p.y, p.size / 3, 0, Math.PI * 2);
260 ctx.strokeStyle = p.color;
261 ctx.lineWidth = 1.5;
262 ctx.stroke();
263 // crosshairs
264 ctx.save();
265 ctx.translate(p.x, p.y);
266 ctx.rotate(p.rot);
267 var ss = p.size / 3;
268 for (var k = 0; k < 3; k++) {
269 ctx.save();
270 ctx.rotate(k * Math.PI / 3);
271 ctx.beginPath();
272 ctx.moveTo(0, -ss); ctx.lineTo(0, ss);
273 ctx.lineWidth = 1.5;
274 ctx.stroke();
275 ctx.restore();
276 }
277 ctx.restore();
278 break;
279
280 case 'ribbon':
281 ctx.save();
282 ctx.translate(p.x, p.y);
283 ctx.rotate(p.rot);
284 ctx.fillRect(-p.size / 2, -p.size / 6, p.size, p.size / 3);
285 ctx.restore();
286 break;
287
288 default:
289 ctx.beginPath();
290 ctx.arc(p.x, p.y, p.size / 2, 0, Math.PI * 2);
291 ctx.fill();
292 break;
293 }
294 }
295
296 draw();
297 }
298
299 function buildSectionOnly(appEl, opts) {
300 var section = document.createElement('div');
301 section.style.height = (opts.sectionHeight || 200) + 'px';
302 section.style.backgroundColor = opts.sectionBg || '#1e1b4b';
303 section.style.borderRadius = (opts.sectionRadius || 16) + 'px';
304 section.style.display = 'flex';
305 section.style.alignItems = 'center';
306 section.style.justifyContent = 'center';
307 if (opts.previewText) {
308 var lbl = document.createElement('div');
309 lbl.style.color = '#fff';
310 lbl.style.opacity = '0.6';
311 lbl.style.fontSize = '14px';
312 lbl.textContent = opts.previewText;
313 section.appendChild(lbl);
314 }
315 appEl.parentNode.replaceChild(section, appEl);
316 }
317
318 document.addEventListener('DOMContentLoaded', function () {
319 document.querySelectorAll('.bkbg-mt-app').forEach(initMouseTrail);
320 });
321
322 if (document.readyState === 'complete' || document.readyState === 'interactive') {
323 document.querySelectorAll('.bkbg-mt-app').forEach(initMouseTrail);
324 }
325 })();
326