@neo-ui-kit/react 1.3.5 → 1.3.7
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 +1 -1
- package/dist/chunks/{chunk-N5XCG6VF.js → chunk-FRALT7ER.js} +1 -1
- package/dist/chunks/{chunk-NVKL7ONR.js → chunk-YVRQTI7B.js} +842 -4
- package/dist/components/artwork/NeonWaves/neon-renderer.d.ts +60 -0
- package/dist/core/border-worker.d.ts +7 -0
- package/dist/core.js +1 -1
- package/dist/forms.js +2 -2
- package/dist/index.js +34 -98
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ import "@neo-ui-kit/react/styles.css";
|
|
|
25
25
|
To test repository changes before publishing, run `npm run package` from the repository root and install the resulting archive in a separate application:
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
npm install /path/to/adui/release/neo-ui-kit-react-1.3.
|
|
28
|
+
npm install /path/to/adui/release/neo-ui-kit-react-1.3.7.tgz
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
Maintainers publish new versions from `Pro100Dimka/adui` using the `release.yml` GitHub Actions workflow, a matching `v<version>` tag, and the `npm-publication` environment. npm trusts its OIDC identity; no `NPM_TOKEN` is required. The workflow checks the project and packed consumer before publishing the tested archive. Published `1.0.0` cannot be overwritten: code and README changes in npm require a new package version. See the [repository release instructions](https://github.com/Pro100Dimka/adui#npm-пакет).
|
|
@@ -9,6 +9,822 @@ import {
|
|
|
9
9
|
useMotion
|
|
10
10
|
} from "./chunk-FCOU3ODR.js";
|
|
11
11
|
|
|
12
|
+
// src/core/border-worker.js
|
|
13
|
+
function renderBorders() {
|
|
14
|
+
const scenes = /* @__PURE__ */ new Map();
|
|
15
|
+
let frame = null, fps = 30, last2 = -Infinity;
|
|
16
|
+
const release = (scene) => {
|
|
17
|
+
for (const layer of scene.layers) {
|
|
18
|
+
layer.mask.close();
|
|
19
|
+
layer.texture.close();
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
const draw = (scene) => {
|
|
23
|
+
const { ctx, width, height, points, length, radius } = scene;
|
|
24
|
+
ctx.clearRect(0, 0, width, height);
|
|
25
|
+
for (const layer of scene.layers) {
|
|
26
|
+
const paint = layer.ctx;
|
|
27
|
+
paint.globalCompositeOperation = "source-over";
|
|
28
|
+
paint.clearRect(0, 0, width, height);
|
|
29
|
+
for (const light of scene.lights) {
|
|
30
|
+
const index = (light.phase + scene.elapsed * light.speed / length) % 1 * 1024;
|
|
31
|
+
const lo = Math.floor(index), hi = (lo + 1) % 1024, weight = index - lo;
|
|
32
|
+
const x = points[lo * 2] * (1 - weight) + points[hi * 2] * weight;
|
|
33
|
+
const y = points[lo * 2 + 1] * (1 - weight) + points[hi * 2 + 1] * weight;
|
|
34
|
+
paint.drawImage(layer.texture, x - radius + 16, y - radius + 16, radius * 2, radius * 2);
|
|
35
|
+
}
|
|
36
|
+
paint.globalCompositeOperation = "destination-in";
|
|
37
|
+
paint.drawImage(layer.mask, 0, 0, width, height);
|
|
38
|
+
ctx.globalAlpha = layer.opacity;
|
|
39
|
+
ctx.drawImage(layer.buffer, 0, 0, width, height);
|
|
40
|
+
}
|
|
41
|
+
ctx.globalAlpha = 1;
|
|
42
|
+
};
|
|
43
|
+
const schedule2 = () => {
|
|
44
|
+
if (frame === null && [...scenes.values()].some((scene) => scene.visible))
|
|
45
|
+
frame = requestAnimationFrame(tick2);
|
|
46
|
+
};
|
|
47
|
+
function tick2(now) {
|
|
48
|
+
frame = null;
|
|
49
|
+
if (now - last2 >= 1e3 / fps - 0.5) {
|
|
50
|
+
for (const scene of scenes.values()) {
|
|
51
|
+
if (!scene.visible) continue;
|
|
52
|
+
if (scene.previous !== null) scene.elapsed += Math.min(0.1, Math.max(0, (now - scene.previous) / 1e3));
|
|
53
|
+
scene.previous = now;
|
|
54
|
+
draw(scene);
|
|
55
|
+
}
|
|
56
|
+
last2 = now;
|
|
57
|
+
}
|
|
58
|
+
schedule2();
|
|
59
|
+
}
|
|
60
|
+
onmessage = ({ data }) => {
|
|
61
|
+
const scene = scenes.get(data.id);
|
|
62
|
+
if (data.type === "rate") fps = data.fps;
|
|
63
|
+
else if (data.type === "remove") {
|
|
64
|
+
if (scene) release(scene);
|
|
65
|
+
scenes.delete(data.id);
|
|
66
|
+
} else if (data.type === "visible") {
|
|
67
|
+
if (scene) {
|
|
68
|
+
scene.visible = data.visible;
|
|
69
|
+
scene.previous = null;
|
|
70
|
+
}
|
|
71
|
+
} else if (data.type === "update") {
|
|
72
|
+
if (scene) release(scene);
|
|
73
|
+
const next = { ...data, canvas: scene?.canvas ?? data.canvas, elapsed: scene?.elapsed ?? data.elapsed, previous: null };
|
|
74
|
+
next.canvas.width = Math.ceil(data.width * data.dpr);
|
|
75
|
+
next.canvas.height = Math.ceil(data.height * data.dpr);
|
|
76
|
+
next.ctx = next.canvas.getContext("2d");
|
|
77
|
+
next.ctx.setTransform(data.dpr, 0, 0, data.dpr, 0, 0);
|
|
78
|
+
for (const layer of next.layers) {
|
|
79
|
+
layer.buffer = new OffscreenCanvas(next.canvas.width, next.canvas.height);
|
|
80
|
+
layer.ctx = layer.buffer.getContext("2d");
|
|
81
|
+
layer.ctx.setTransform(data.dpr, 0, 0, data.dpr, 0, 0);
|
|
82
|
+
}
|
|
83
|
+
scenes.set(data.id, next);
|
|
84
|
+
draw(next);
|
|
85
|
+
postMessage({ id: data.id, elapsed: next.elapsed, revision: data.revision });
|
|
86
|
+
}
|
|
87
|
+
schedule2();
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
var worker = null;
|
|
91
|
+
var workerUrl = null;
|
|
92
|
+
var serial = 0;
|
|
93
|
+
var unavailable = false;
|
|
94
|
+
var frameRate = 30;
|
|
95
|
+
var clients = /* @__PURE__ */ new Map();
|
|
96
|
+
var visibilityChanged = () => {
|
|
97
|
+
for (const client of clients.values()) client.visibility();
|
|
98
|
+
};
|
|
99
|
+
var resized = () => {
|
|
100
|
+
for (const client of clients.values()) client.update();
|
|
101
|
+
};
|
|
102
|
+
function setBorderFrameRate(fps) {
|
|
103
|
+
frameRate = fps;
|
|
104
|
+
worker?.postMessage({ type: "rate", fps });
|
|
105
|
+
}
|
|
106
|
+
function stopWorker() {
|
|
107
|
+
worker?.terminate();
|
|
108
|
+
if (workerUrl) URL.revokeObjectURL(workerUrl);
|
|
109
|
+
worker = workerUrl = null;
|
|
110
|
+
document.removeEventListener("visibilitychange", visibilityChanged);
|
|
111
|
+
window.removeEventListener("resize", resized);
|
|
112
|
+
}
|
|
113
|
+
function startWorker() {
|
|
114
|
+
if (worker) return worker;
|
|
115
|
+
try {
|
|
116
|
+
workerUrl = URL.createObjectURL(new Blob([`(${renderBorders.toString()})()`], { type: "text/javascript" }));
|
|
117
|
+
worker = new Worker(workerUrl);
|
|
118
|
+
} catch {
|
|
119
|
+
unavailable = true;
|
|
120
|
+
stopWorker();
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
worker.onmessage = ({ data }) => clients.get(data.id)?.ready(data);
|
|
124
|
+
worker.onerror = () => {
|
|
125
|
+
unavailable = true;
|
|
126
|
+
const pending = [...clients.values()];
|
|
127
|
+
stopWorker();
|
|
128
|
+
for (const client of pending) client.fail();
|
|
129
|
+
};
|
|
130
|
+
worker.postMessage({ type: "rate", fps: frameRate });
|
|
131
|
+
document.addEventListener("visibilitychange", visibilityChanged);
|
|
132
|
+
window.addEventListener("resize", resized);
|
|
133
|
+
return worker;
|
|
134
|
+
}
|
|
135
|
+
function createBorderWorker(item) {
|
|
136
|
+
if (unavailable || typeof Worker === "undefined" || typeof OffscreenCanvas === "undefined" || typeof createImageBitmap === "undefined" || typeof HTMLCanvasElement === "undefined" || !HTMLCanvasElement.prototype.transferControlToOffscreen || typeof IntersectionObserver === "undefined" || typeof MutationObserver === "undefined") return null;
|
|
137
|
+
const thread2 = startWorker();
|
|
138
|
+
if (!thread2) return null;
|
|
139
|
+
const id = ++serial, host = item.element;
|
|
140
|
+
const groups = [...item.overlay.querySelectorAll(".ad-border-aura, .ad-border-core")];
|
|
141
|
+
const originalVisibility = groups.map((group) => group.style.visibility);
|
|
142
|
+
const canvas = document.createElement("canvas");
|
|
143
|
+
canvas.style.cssText = "position:absolute;left:-16px;top:-16px;pointer-events:none;visibility:hidden";
|
|
144
|
+
item.overlay.append(canvas);
|
|
145
|
+
let revision = 0, disposed = false, queued = false, signature = "", transferred = false;
|
|
146
|
+
let inView = false, visible = false, elapsed = item.elapsed, since = performance.now();
|
|
147
|
+
const renderer = { ready: false, update: queue, dispose };
|
|
148
|
+
const visibility = () => {
|
|
149
|
+
const motion = host.closest("[data-ad-motion]")?.dataset.adMotion !== "off";
|
|
150
|
+
const next = inView && motion && !document.hidden && !host.closest("[data-ad-offscreen], [data-ad-paused]");
|
|
151
|
+
canvas.style.display = motion ? "" : "none";
|
|
152
|
+
if (next === visible) return;
|
|
153
|
+
if (visible && renderer.ready) elapsed += (performance.now() - since) / 1e3;
|
|
154
|
+
since = performance.now();
|
|
155
|
+
visible = next;
|
|
156
|
+
thread2.postMessage({ type: "visible", id, visible });
|
|
157
|
+
};
|
|
158
|
+
const observer = new IntersectionObserver((entries) => {
|
|
159
|
+
inView = entries[0].isIntersecting;
|
|
160
|
+
visibility();
|
|
161
|
+
}, { rootMargin: "16px" });
|
|
162
|
+
observer.observe(host);
|
|
163
|
+
const tokens = new MutationObserver((records) => {
|
|
164
|
+
visibility();
|
|
165
|
+
if (records.some((record) => ["style", "class", "data-ad-theme", "data-ad-color-scheme"].includes(record.attributeName))) queue();
|
|
166
|
+
});
|
|
167
|
+
for (let node = host; node; node = node.parentElement)
|
|
168
|
+
tokens.observe(node, { attributes: true, attributeFilter: ["style", "class", "data-ad-theme", "data-ad-color-scheme", "data-ad-motion", "data-ad-offscreen", "data-ad-paused"] });
|
|
169
|
+
clients.set(id, {
|
|
170
|
+
visibility,
|
|
171
|
+
update: queue,
|
|
172
|
+
ready(data) {
|
|
173
|
+
if (disposed || data.revision !== revision) return;
|
|
174
|
+
elapsed = data.elapsed;
|
|
175
|
+
since = performance.now();
|
|
176
|
+
renderer.ready = true;
|
|
177
|
+
groups.forEach((group) => {
|
|
178
|
+
group.style.visibility = "hidden";
|
|
179
|
+
});
|
|
180
|
+
canvas.style.visibility = "";
|
|
181
|
+
visibility();
|
|
182
|
+
},
|
|
183
|
+
fail() {
|
|
184
|
+
item.elapsed = elapsed + (visible && renderer.ready ? (performance.now() - since) / 1e3 : 0);
|
|
185
|
+
item.previousTime = null;
|
|
186
|
+
dispose();
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
function dispose() {
|
|
190
|
+
if (disposed) return;
|
|
191
|
+
disposed = true;
|
|
192
|
+
renderer.ready = false;
|
|
193
|
+
revision++;
|
|
194
|
+
observer.disconnect();
|
|
195
|
+
tokens.disconnect();
|
|
196
|
+
groups.forEach((group, index) => {
|
|
197
|
+
group.style.visibility = originalVisibility[index];
|
|
198
|
+
});
|
|
199
|
+
canvas.remove();
|
|
200
|
+
clients.delete(id);
|
|
201
|
+
if (worker === thread2) thread2.postMessage({ type: "remove", id });
|
|
202
|
+
if (!clients.size) stopWorker();
|
|
203
|
+
}
|
|
204
|
+
function queue() {
|
|
205
|
+
if (disposed || queued) return;
|
|
206
|
+
queued = true;
|
|
207
|
+
queueMicrotask(() => {
|
|
208
|
+
queued = false;
|
|
209
|
+
if (!disposed) void update();
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
async function update() {
|
|
213
|
+
const dpr = devicePixelRatio || 1;
|
|
214
|
+
const width = item.overlay.clientWidth + 32, height = item.overlay.clientHeight + 32;
|
|
215
|
+
const radius = item.lights[0].radius;
|
|
216
|
+
const styles = groups.map((group) => ({
|
|
217
|
+
mask: group.style.maskImage,
|
|
218
|
+
gradient: getComputedStyle(group.firstElementChild).backgroundImage,
|
|
219
|
+
opacity: Number(getComputedStyle(group).opacity)
|
|
220
|
+
}));
|
|
221
|
+
const key = JSON.stringify([item.geometry, dpr, styles]);
|
|
222
|
+
if (!item.length || key === signature) return;
|
|
223
|
+
signature = key;
|
|
224
|
+
const current = ++revision, images = [];
|
|
225
|
+
try {
|
|
226
|
+
const layers = [];
|
|
227
|
+
for (const style of styles) {
|
|
228
|
+
const mask = new Image();
|
|
229
|
+
mask.src = JSON.parse(style.mask.slice(4, -1));
|
|
230
|
+
await mask.decode();
|
|
231
|
+
const maskCanvas = document.createElement("canvas");
|
|
232
|
+
maskCanvas.width = Math.ceil(width * dpr);
|
|
233
|
+
maskCanvas.height = Math.ceil(height * dpr);
|
|
234
|
+
maskCanvas.getContext("2d").drawImage(mask, 0, 0, maskCanvas.width, maskCanvas.height);
|
|
235
|
+
const bitmap = await createImageBitmap(maskCanvas);
|
|
236
|
+
images.push(bitmap);
|
|
237
|
+
const texture = document.createElement("canvas");
|
|
238
|
+
texture.width = texture.height = Math.ceil(radius * 2 * dpr);
|
|
239
|
+
const ctx = texture.getContext("2d");
|
|
240
|
+
ctx.scale(dpr, dpr);
|
|
241
|
+
const gradient = ctx.createRadialGradient(radius, radius, 0, radius, radius, radius);
|
|
242
|
+
for (const stop of style.gradient.slice(style.gradient.indexOf(",") + 1, -1).split(/,\s*(?![^()]*\))/)) {
|
|
243
|
+
const match = stop.trim().match(/^(.*)\s+([\d.]+)%$/);
|
|
244
|
+
if (!match) throw new Error("Invalid border gradient");
|
|
245
|
+
gradient.addColorStop(Number(match[2]) / 100, match[1]);
|
|
246
|
+
}
|
|
247
|
+
ctx.fillStyle = gradient;
|
|
248
|
+
ctx.fillRect(0, 0, radius * 2, radius * 2);
|
|
249
|
+
const spot = await createImageBitmap(texture);
|
|
250
|
+
images.push(spot);
|
|
251
|
+
layers.push({ mask: bitmap, texture: spot, opacity: style.opacity });
|
|
252
|
+
}
|
|
253
|
+
if (disposed || current !== revision) {
|
|
254
|
+
images.forEach((image) => image.close());
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
const points = new Float32Array(2048);
|
|
258
|
+
for (let index = 0; index < 1024; index++) {
|
|
259
|
+
const point = item.contour.point(index / 1024);
|
|
260
|
+
points[index * 2] = point.x;
|
|
261
|
+
points[index * 2 + 1] = point.y;
|
|
262
|
+
}
|
|
263
|
+
canvas.style.width = `${width}px`;
|
|
264
|
+
canvas.style.height = `${height}px`;
|
|
265
|
+
const surface = transferred ? void 0 : canvas.transferControlToOffscreen();
|
|
266
|
+
transferred = true;
|
|
267
|
+
thread2.postMessage({
|
|
268
|
+
type: "update",
|
|
269
|
+
id,
|
|
270
|
+
revision: current,
|
|
271
|
+
canvas: surface,
|
|
272
|
+
width,
|
|
273
|
+
height,
|
|
274
|
+
dpr,
|
|
275
|
+
radius,
|
|
276
|
+
lights: item.lights.map(({ phase, speed }) => ({ phase, speed })),
|
|
277
|
+
points,
|
|
278
|
+
length: item.length,
|
|
279
|
+
layers,
|
|
280
|
+
elapsed: item.elapsed,
|
|
281
|
+
visible
|
|
282
|
+
}, [...images, points.buffer, ...surface ? [surface] : []]);
|
|
283
|
+
} catch {
|
|
284
|
+
images.forEach((image) => image.close());
|
|
285
|
+
if (!disposed) clients.get(id)?.fail();
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
visibility();
|
|
289
|
+
queue();
|
|
290
|
+
return renderer;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// src/components/artwork/NeonWaves/neon-renderer.js
|
|
294
|
+
function createNeonGeometry() {
|
|
295
|
+
const W = 600;
|
|
296
|
+
const H = 120;
|
|
297
|
+
const SKYLINE = [
|
|
298
|
+
[0, 0.93],
|
|
299
|
+
[0.16, 0.86],
|
|
300
|
+
[0.3, 0.82],
|
|
301
|
+
[0.42, 0.72],
|
|
302
|
+
[0.55, 0.64],
|
|
303
|
+
[0.64, 0.7],
|
|
304
|
+
[0.74, 0.52],
|
|
305
|
+
[0.84, 0.1],
|
|
306
|
+
[0.9, 0.56],
|
|
307
|
+
[0.95, 0.46],
|
|
308
|
+
[1, 0.08]
|
|
309
|
+
];
|
|
310
|
+
const skyline = (x) => {
|
|
311
|
+
const i = Math.max(0, SKYLINE.findIndex(([at]) => at >= x) - 1);
|
|
312
|
+
const [x0, y0] = SKYLINE[i];
|
|
313
|
+
const [x1, y1] = SKYLINE[Math.min(SKYLINE.length - 1, i + 1)];
|
|
314
|
+
const k = x1 === x0 ? 0 : (x - x0) / (x1 - x0);
|
|
315
|
+
return y0 + (y1 - y0) * (1 - Math.cos(k * Math.PI)) / 2;
|
|
316
|
+
};
|
|
317
|
+
const SAMPLES = 36;
|
|
318
|
+
const toPath = (curve) => {
|
|
319
|
+
let d = `M${curve[0].toFixed(2)} ${curve[1].toFixed(2)}`;
|
|
320
|
+
for (let i = 2; i < curve.length; i += 6)
|
|
321
|
+
d += `C${curve.slice(i, i + 6).map((n) => n.toFixed(2)).join(" ")}`;
|
|
322
|
+
return d;
|
|
323
|
+
};
|
|
324
|
+
const smoothTo = (curve, c2x, c2y, x, y) => {
|
|
325
|
+
const n = curve.length;
|
|
326
|
+
curve.push(
|
|
327
|
+
2 * curve[n - 2] - curve[n - 4],
|
|
328
|
+
2 * curve[n - 1] - curve[n - 3],
|
|
329
|
+
c2x,
|
|
330
|
+
c2y,
|
|
331
|
+
x,
|
|
332
|
+
y
|
|
333
|
+
);
|
|
334
|
+
};
|
|
335
|
+
const smooth = (xs, ys) => {
|
|
336
|
+
const curve = [xs[0], ys[0]];
|
|
337
|
+
for (let i = 0; i < xs.length - 1; i += 1) {
|
|
338
|
+
const x0 = xs[i - 1] ?? xs[i], y0 = ys[i - 1] ?? ys[i];
|
|
339
|
+
const x1 = xs[i], y1 = ys[i], x2 = xs[i + 1], y2 = ys[i + 1];
|
|
340
|
+
const x3 = xs[i + 2] ?? x2, y3 = ys[i + 2] ?? y2;
|
|
341
|
+
curve.push(
|
|
342
|
+
x1 + (x2 - x0) / 6,
|
|
343
|
+
y1 + (y2 - y0) / 6,
|
|
344
|
+
x2 - (x3 - x1) / 6,
|
|
345
|
+
y2 - (y3 - y1) / 6,
|
|
346
|
+
x2,
|
|
347
|
+
y2
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
return curve;
|
|
351
|
+
};
|
|
352
|
+
const ridgeStrand = (t, drift) => {
|
|
353
|
+
const xs = [];
|
|
354
|
+
const ys = [];
|
|
355
|
+
for (let i = 0; i <= SAMPLES; i += 1) {
|
|
356
|
+
const x = i / SAMPLES;
|
|
357
|
+
const base = skyline(x);
|
|
358
|
+
const spread = H * (0.06 + 0.26 * base);
|
|
359
|
+
const ripple = Math.sin(x * 8 + drift + t * 7) * H * (0.03 + 0.05 * base) + Math.sin(x * 21 - drift * 1.3 + t * 11) * H * 0.014;
|
|
360
|
+
xs.push(x * (W + 20) - 10);
|
|
361
|
+
ys.push(base * H + (t - 0.5) * spread + ripple);
|
|
362
|
+
}
|
|
363
|
+
return smooth(xs, ys);
|
|
364
|
+
};
|
|
365
|
+
const twistStrand = (t, drift, main) => {
|
|
366
|
+
const a = Math.sin(drift + t * 1.4) * H * 0.095;
|
|
367
|
+
const b = Math.cos(drift * 0.8 + t * 1.8) * H * 0.08;
|
|
368
|
+
if (!main) {
|
|
369
|
+
const curve2 = [
|
|
370
|
+
-12,
|
|
371
|
+
H * (0.9 + t * 0.12) + b,
|
|
372
|
+
W * 0.21,
|
|
373
|
+
H * 0.98 + a,
|
|
374
|
+
W * 0.33,
|
|
375
|
+
H * 0.24 + t * H * 0.2 + a,
|
|
376
|
+
W * 0.52,
|
|
377
|
+
H * 0.75 + t * H * 0.25 + b
|
|
378
|
+
];
|
|
379
|
+
smoothTo(
|
|
380
|
+
curve2,
|
|
381
|
+
W * 0.82,
|
|
382
|
+
H * 0.38 + t * H * 0.27 + a,
|
|
383
|
+
W + 8,
|
|
384
|
+
H * (0.48 + t * 0.5) + b
|
|
385
|
+
);
|
|
386
|
+
return curve2;
|
|
387
|
+
}
|
|
388
|
+
const curve = [
|
|
389
|
+
-12,
|
|
390
|
+
H * (0.38 + t * 0.58) + a,
|
|
391
|
+
W * 0.2,
|
|
392
|
+
H * 1.28 - t * H * 0.27 + a,
|
|
393
|
+
W * 0.32,
|
|
394
|
+
H * 0.34 + t * H * 0.21 + b,
|
|
395
|
+
W * 0.46,
|
|
396
|
+
H * 0.62 + t * H * 0.12
|
|
397
|
+
];
|
|
398
|
+
smoothTo(
|
|
399
|
+
curve,
|
|
400
|
+
W * 0.67,
|
|
401
|
+
H * 1.14 - t * H * 0.09 + a,
|
|
402
|
+
W * 0.8,
|
|
403
|
+
H * 0.69 - t * H * 0.22 + b
|
|
404
|
+
);
|
|
405
|
+
smoothTo(
|
|
406
|
+
curve,
|
|
407
|
+
W * 0.94,
|
|
408
|
+
H * 0.43 - t * H * 0.44 + a,
|
|
409
|
+
W + 8,
|
|
410
|
+
H * 0.21 + t * H * 0.45
|
|
411
|
+
);
|
|
412
|
+
return curve;
|
|
413
|
+
};
|
|
414
|
+
const STEPS = 16;
|
|
415
|
+
const measure = (curve) => {
|
|
416
|
+
const xs = [curve[0]], ys = [curve[1]], lengths = [0];
|
|
417
|
+
for (let i = 2; i < curve.length; i += 6) {
|
|
418
|
+
const x0 = curve[i - 2], y0 = curve[i - 1];
|
|
419
|
+
const [x1, y1, x2, y2, x3, y3] = curve.slice(i, i + 6);
|
|
420
|
+
for (let k = 1; k <= STEPS; k += 1) {
|
|
421
|
+
const u = k / STEPS, v = 1 - u;
|
|
422
|
+
const x = v * v * v * x0 + 3 * v * v * u * x1 + 3 * v * u * u * x2 + u * u * u * x3;
|
|
423
|
+
const y = v * v * v * y0 + 3 * v * v * u * y1 + 3 * v * u * u * y2 + u * u * u * y3;
|
|
424
|
+
lengths.push(
|
|
425
|
+
lengths[lengths.length - 1] + Math.hypot(x - xs[xs.length - 1], y - ys[ys.length - 1])
|
|
426
|
+
);
|
|
427
|
+
xs.push(x);
|
|
428
|
+
ys.push(y);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
return { xs, ys, lengths, total: lengths[lengths.length - 1] };
|
|
432
|
+
};
|
|
433
|
+
const pointAt = (track, fraction) => {
|
|
434
|
+
const distance = Math.min(1, Math.max(0, fraction)) * track.total;
|
|
435
|
+
let low = 0, high = track.lengths.length - 1;
|
|
436
|
+
while (high - low > 1) {
|
|
437
|
+
const middle = low + high >> 1;
|
|
438
|
+
if (track.lengths[middle] < distance) low = middle;
|
|
439
|
+
else high = middle;
|
|
440
|
+
}
|
|
441
|
+
const span = track.lengths[high] - track.lengths[low] || 1;
|
|
442
|
+
const k = (distance - track.lengths[low]) / span;
|
|
443
|
+
return {
|
|
444
|
+
x: track.xs[low] + (track.xs[high] - track.xs[low]) * k,
|
|
445
|
+
y: track.ys[low] + (track.ys[high] - track.ys[low]) * k
|
|
446
|
+
};
|
|
447
|
+
};
|
|
448
|
+
const COMET_LAP = 6;
|
|
449
|
+
const COMET_DASH = 0.016;
|
|
450
|
+
const COMET_WIDTH = 1.6;
|
|
451
|
+
const cometStrand = (i, comets, strands) => Math.min(strands - 1, Math.round((i + 0.5) / comets * (strands - 1)));
|
|
452
|
+
return {
|
|
453
|
+
W,
|
|
454
|
+
H,
|
|
455
|
+
toPath,
|
|
456
|
+
ridgeStrand,
|
|
457
|
+
twistStrand,
|
|
458
|
+
measure,
|
|
459
|
+
pointAt,
|
|
460
|
+
cometStrand,
|
|
461
|
+
COMET_LAP,
|
|
462
|
+
COMET_DASH,
|
|
463
|
+
COMET_WIDTH
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
var neonGeometry = createNeonGeometry();
|
|
467
|
+
function renderNeon(createGeometry) {
|
|
468
|
+
const geometry = createGeometry(), scenes = /* @__PURE__ */ new Map();
|
|
469
|
+
let frame = null, fps = 30, last2 = -Infinity;
|
|
470
|
+
function draw(scene) {
|
|
471
|
+
const { ctx, width, height, padX, padY, sx, sy, options, time, gradient } = scene;
|
|
472
|
+
ctx.clearRect(-padX, -padY, width + padX * 2, height + padY * 2);
|
|
473
|
+
ctx.strokeStyle = gradient;
|
|
474
|
+
const tracks = /* @__PURE__ */ new Map();
|
|
475
|
+
const carried = new Set(
|
|
476
|
+
Array.from(
|
|
477
|
+
{ length: options.comets },
|
|
478
|
+
(_, i) => geometry.cometStrand(i, options.comets, options.strands)
|
|
479
|
+
)
|
|
480
|
+
);
|
|
481
|
+
for (let i = 0; i < options.strands; i++) {
|
|
482
|
+
const t = i / Math.max(1, options.strands - 1), drift = time * 0.42 + options.phase;
|
|
483
|
+
const curve = options.shape === "ridge" ? geometry.ridgeStrand(t, drift) : geometry.twistStrand(t, drift, i < options.strands * 0.68);
|
|
484
|
+
ctx.beginPath();
|
|
485
|
+
ctx.moveTo(curve[0] * sx, curve[1] * sy);
|
|
486
|
+
for (let j = 2; j < curve.length; j += 6)
|
|
487
|
+
ctx.bezierCurveTo(
|
|
488
|
+
curve[j] * sx,
|
|
489
|
+
curve[j + 1] * sy,
|
|
490
|
+
curve[j + 2] * sx,
|
|
491
|
+
curve[j + 3] * sy,
|
|
492
|
+
curve[j + 4] * sx,
|
|
493
|
+
curve[j + 5] * sy
|
|
494
|
+
);
|
|
495
|
+
ctx.lineWidth = i === 5 ? 1 : 0.55;
|
|
496
|
+
ctx.globalAlpha = i === 5 ? 0.95 : 0.52;
|
|
497
|
+
ctx.stroke();
|
|
498
|
+
if (carried.has(i)) tracks.set(i, geometry.measure(curve));
|
|
499
|
+
}
|
|
500
|
+
for (let i = 0; i < options.comets; i++) {
|
|
501
|
+
const track = tracks.get(
|
|
502
|
+
geometry.cometStrand(i, options.comets, options.strands)
|
|
503
|
+
);
|
|
504
|
+
if (!track) continue;
|
|
505
|
+
const start = (time + i * geometry.COMET_LAP / options.comets + 1.8) / geometry.COMET_LAP % 1;
|
|
506
|
+
const tail = geometry.pointAt(track, start), head = geometry.pointAt(track, start + geometry.COMET_DASH);
|
|
507
|
+
const dx = (head.x - tail.x) * sx, dy = (head.y - tail.y) * sy;
|
|
508
|
+
const length = Math.round(Math.hypot(dx, dy) + geometry.COMET_WIDTH);
|
|
509
|
+
let sprite = scene.sprites.get(length);
|
|
510
|
+
if (!sprite) {
|
|
511
|
+
const padding = Math.ceil(
|
|
512
|
+
Math.max(0, ...scene.shadows.map((shadow) => shadow.blur)) * 2 + 2
|
|
513
|
+
);
|
|
514
|
+
const canvas = new OffscreenCanvas(
|
|
515
|
+
Math.ceil((length + padding * 2) * scene.dpr),
|
|
516
|
+
Math.ceil((geometry.COMET_WIDTH + padding * 2) * scene.dpr)
|
|
517
|
+
);
|
|
518
|
+
const paint = canvas.getContext("2d");
|
|
519
|
+
paint.scale(scene.dpr, scene.dpr);
|
|
520
|
+
paint.fillStyle = scene.color;
|
|
521
|
+
for (const shadow of [...scene.shadows].reverse()) {
|
|
522
|
+
paint.shadowColor = shadow.color;
|
|
523
|
+
paint.shadowBlur = shadow.blur * scene.dpr;
|
|
524
|
+
paint.beginPath();
|
|
525
|
+
paint.roundRect(
|
|
526
|
+
padding,
|
|
527
|
+
padding,
|
|
528
|
+
length,
|
|
529
|
+
geometry.COMET_WIDTH,
|
|
530
|
+
geometry.COMET_WIDTH / 2
|
|
531
|
+
);
|
|
532
|
+
paint.fill();
|
|
533
|
+
}
|
|
534
|
+
sprite = { canvas, padding };
|
|
535
|
+
scene.sprites.set(length, sprite);
|
|
536
|
+
}
|
|
537
|
+
const x = (tail.x + head.x) / 2, y = (tail.y + head.y) / 2;
|
|
538
|
+
ctx.save();
|
|
539
|
+
ctx.translate(x * sx, y * sy);
|
|
540
|
+
ctx.rotate(Math.atan2(dy, dx));
|
|
541
|
+
ctx.globalAlpha = Math.min(
|
|
542
|
+
1,
|
|
543
|
+
Math.max(0, (x + 20) / ((geometry.W + 40) * 0.35))
|
|
544
|
+
);
|
|
545
|
+
ctx.drawImage(
|
|
546
|
+
sprite.canvas,
|
|
547
|
+
-length / 2 - sprite.padding,
|
|
548
|
+
-geometry.COMET_WIDTH / 2 - sprite.padding,
|
|
549
|
+
sprite.canvas.width / scene.dpr,
|
|
550
|
+
sprite.canvas.height / scene.dpr
|
|
551
|
+
);
|
|
552
|
+
ctx.restore();
|
|
553
|
+
}
|
|
554
|
+
ctx.globalAlpha = 1;
|
|
555
|
+
}
|
|
556
|
+
function schedule2() {
|
|
557
|
+
if (frame === null && [...scenes.values()].some((scene) => scene.visible))
|
|
558
|
+
frame = requestAnimationFrame(tick2);
|
|
559
|
+
}
|
|
560
|
+
function tick2(now) {
|
|
561
|
+
frame = null;
|
|
562
|
+
if (now - last2 >= 1e3 / fps - 0.5) {
|
|
563
|
+
for (const scene of scenes.values()) {
|
|
564
|
+
if (!scene.visible) continue;
|
|
565
|
+
if (scene.previous !== null)
|
|
566
|
+
scene.time += Math.min(
|
|
567
|
+
0.1,
|
|
568
|
+
Math.max(0, (now - scene.previous) / 1e3)
|
|
569
|
+
);
|
|
570
|
+
scene.previous = now;
|
|
571
|
+
draw(scene);
|
|
572
|
+
}
|
|
573
|
+
last2 = now;
|
|
574
|
+
}
|
|
575
|
+
schedule2();
|
|
576
|
+
}
|
|
577
|
+
onmessage = ({ data }) => {
|
|
578
|
+
const previous = scenes.get(data.id);
|
|
579
|
+
if (data.type === "rate") fps = data.fps;
|
|
580
|
+
else if (data.type === "remove") scenes.delete(data.id);
|
|
581
|
+
else if (data.type === "visible") {
|
|
582
|
+
if (previous) {
|
|
583
|
+
previous.visible = data.visible;
|
|
584
|
+
previous.previous = null;
|
|
585
|
+
}
|
|
586
|
+
} else if (data.type === "update") {
|
|
587
|
+
const scene = {
|
|
588
|
+
...data,
|
|
589
|
+
canvas: previous?.canvas ?? data.canvas,
|
|
590
|
+
time: previous?.time ?? data.time,
|
|
591
|
+
previous: null,
|
|
592
|
+
sprites: /* @__PURE__ */ new Map()
|
|
593
|
+
};
|
|
594
|
+
scene.canvas.width = Math.ceil((data.width + data.padX * 2) * data.dpr);
|
|
595
|
+
scene.canvas.height = Math.ceil((data.height + data.padY * 2) * data.dpr);
|
|
596
|
+
scene.ctx = scene.canvas.getContext("2d");
|
|
597
|
+
scene.ctx.setTransform(
|
|
598
|
+
data.dpr,
|
|
599
|
+
0,
|
|
600
|
+
0,
|
|
601
|
+
data.dpr,
|
|
602
|
+
data.padX * data.dpr,
|
|
603
|
+
data.padY * data.dpr
|
|
604
|
+
);
|
|
605
|
+
scene.sx = data.width / geometry.W;
|
|
606
|
+
scene.sy = data.height / geometry.H;
|
|
607
|
+
const [start, end] = data.options.shape === "ridge" ? [-10, 610] : [-12, 608];
|
|
608
|
+
scene.gradient = scene.ctx.createLinearGradient(
|
|
609
|
+
start * scene.sx,
|
|
610
|
+
0,
|
|
611
|
+
end * scene.sx,
|
|
612
|
+
0
|
|
613
|
+
);
|
|
614
|
+
for (const stop of data.stops)
|
|
615
|
+
scene.gradient.addColorStop(stop.at, stop.color);
|
|
616
|
+
scenes.set(data.id, scene);
|
|
617
|
+
draw(scene);
|
|
618
|
+
postMessage({ id: data.id });
|
|
619
|
+
}
|
|
620
|
+
schedule2();
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
var thread = null;
|
|
624
|
+
var url = null;
|
|
625
|
+
var serial2 = 0;
|
|
626
|
+
var unavailable2 = false;
|
|
627
|
+
var frameRate2 = 30;
|
|
628
|
+
var clients2 = /* @__PURE__ */ new Map();
|
|
629
|
+
var visibilityChanged2 = () => {
|
|
630
|
+
for (const client of clients2.values()) client.visibility();
|
|
631
|
+
};
|
|
632
|
+
var resized2 = () => {
|
|
633
|
+
for (const client of clients2.values()) client.update();
|
|
634
|
+
};
|
|
635
|
+
function setNeonFrameRate(fps) {
|
|
636
|
+
frameRate2 = fps;
|
|
637
|
+
thread?.postMessage({ type: "rate", fps });
|
|
638
|
+
}
|
|
639
|
+
function stopThread() {
|
|
640
|
+
thread?.terminate();
|
|
641
|
+
if (url) URL.revokeObjectURL(url);
|
|
642
|
+
thread = url = null;
|
|
643
|
+
document.removeEventListener("visibilitychange", visibilityChanged2);
|
|
644
|
+
window.removeEventListener("resize", resized2);
|
|
645
|
+
}
|
|
646
|
+
function createNeonRenderer(root, svg, initial) {
|
|
647
|
+
if (unavailable2 || typeof Worker === "undefined" || typeof OffscreenCanvas === "undefined" || typeof HTMLCanvasElement === "undefined" || !HTMLCanvasElement.prototype.transferControlToOffscreen || typeof IntersectionObserver === "undefined" || typeof MutationObserver === "undefined")
|
|
648
|
+
return null;
|
|
649
|
+
if (!thread) {
|
|
650
|
+
try {
|
|
651
|
+
url = URL.createObjectURL(
|
|
652
|
+
new Blob(
|
|
653
|
+
[`(${renderNeon.toString()})(${createNeonGeometry.toString()})`],
|
|
654
|
+
{ type: "text/javascript" }
|
|
655
|
+
)
|
|
656
|
+
);
|
|
657
|
+
thread = new Worker(url);
|
|
658
|
+
} catch {
|
|
659
|
+
unavailable2 = true;
|
|
660
|
+
stopThread();
|
|
661
|
+
return null;
|
|
662
|
+
}
|
|
663
|
+
thread.onmessage = ({ data }) => clients2.get(data.id)?.ready();
|
|
664
|
+
thread.onerror = () => {
|
|
665
|
+
unavailable2 = true;
|
|
666
|
+
const pending = [...clients2.values()];
|
|
667
|
+
stopThread();
|
|
668
|
+
for (const client of pending) client.dispose();
|
|
669
|
+
};
|
|
670
|
+
thread.postMessage({ type: "rate", fps: frameRate2 });
|
|
671
|
+
document.addEventListener("visibilitychange", visibilityChanged2);
|
|
672
|
+
window.addEventListener("resize", resized2);
|
|
673
|
+
}
|
|
674
|
+
const worker2 = thread, id = ++serial2, canvas = document.createElement("canvas");
|
|
675
|
+
canvas.style.cssText = "position:absolute;pointer-events:none;visibility:hidden";
|
|
676
|
+
root.insertBefore(canvas, svg);
|
|
677
|
+
const originalVisibility = svg.style.visibility;
|
|
678
|
+
let options = initial, inView = false, visible = false, disposed = false, transferred = false, queued = false, signature = "";
|
|
679
|
+
let comets = null, cometVisibility = "";
|
|
680
|
+
const renderer = {
|
|
681
|
+
ready: false,
|
|
682
|
+
update(next = options) {
|
|
683
|
+
options = next;
|
|
684
|
+
queue();
|
|
685
|
+
},
|
|
686
|
+
dispose
|
|
687
|
+
};
|
|
688
|
+
const hideOriginal = () => {
|
|
689
|
+
if (!renderer.ready) return;
|
|
690
|
+
svg.style.visibility = "hidden";
|
|
691
|
+
const node = root.querySelector(".ad-neon-waves-comets");
|
|
692
|
+
if (node !== comets) {
|
|
693
|
+
comets = node;
|
|
694
|
+
cometVisibility = node?.style.visibility ?? "";
|
|
695
|
+
}
|
|
696
|
+
if (comets) comets.style.visibility = "hidden";
|
|
697
|
+
};
|
|
698
|
+
const visibility = () => {
|
|
699
|
+
const next = inView && !document.hidden && svg.closest("[data-ad-motion]")?.dataset.adMotion !== "off" && !root.closest("[data-ad-paused], [data-ad-offscreen]");
|
|
700
|
+
if (next !== visible) {
|
|
701
|
+
visible = next;
|
|
702
|
+
worker2.postMessage({ type: "visible", id, visible });
|
|
703
|
+
}
|
|
704
|
+
};
|
|
705
|
+
const intersection = new IntersectionObserver((entries) => {
|
|
706
|
+
inView = entries[0].isIntersecting;
|
|
707
|
+
visibility();
|
|
708
|
+
});
|
|
709
|
+
intersection.observe(root);
|
|
710
|
+
const tokens = new MutationObserver((records) => {
|
|
711
|
+
visibility();
|
|
712
|
+
if (records.some(
|
|
713
|
+
(record) => ["style", "class", "data-ad-theme", "data-ad-color-scheme"].includes(
|
|
714
|
+
record.attributeName
|
|
715
|
+
)
|
|
716
|
+
))
|
|
717
|
+
queue();
|
|
718
|
+
});
|
|
719
|
+
for (let node = root; node; node = node.parentElement)
|
|
720
|
+
tokens.observe(node, {
|
|
721
|
+
attributes: true,
|
|
722
|
+
attributeFilter: [
|
|
723
|
+
"style",
|
|
724
|
+
"class",
|
|
725
|
+
"data-ad-theme",
|
|
726
|
+
"data-ad-color-scheme",
|
|
727
|
+
"data-ad-paused",
|
|
728
|
+
"data-ad-offscreen",
|
|
729
|
+
"data-ad-motion"
|
|
730
|
+
]
|
|
731
|
+
});
|
|
732
|
+
tokens.observe(svg, {
|
|
733
|
+
attributes: true,
|
|
734
|
+
attributeFilter: ["data-ad-motion", "data-ad-offscreen"]
|
|
735
|
+
});
|
|
736
|
+
clients2.set(id, {
|
|
737
|
+
visibility,
|
|
738
|
+
update: queue,
|
|
739
|
+
dispose,
|
|
740
|
+
ready() {
|
|
741
|
+
renderer.ready = true;
|
|
742
|
+
hideOriginal();
|
|
743
|
+
canvas.style.visibility = "";
|
|
744
|
+
}
|
|
745
|
+
});
|
|
746
|
+
function dispose() {
|
|
747
|
+
if (disposed) return;
|
|
748
|
+
disposed = true;
|
|
749
|
+
renderer.ready = false;
|
|
750
|
+
intersection.disconnect();
|
|
751
|
+
tokens.disconnect();
|
|
752
|
+
svg.style.visibility = originalVisibility;
|
|
753
|
+
if (comets) comets.style.visibility = cometVisibility;
|
|
754
|
+
canvas.remove();
|
|
755
|
+
clients2.delete(id);
|
|
756
|
+
if (thread === worker2) worker2.postMessage({ type: "remove", id });
|
|
757
|
+
if (!clients2.size) stopThread();
|
|
758
|
+
}
|
|
759
|
+
function queue() {
|
|
760
|
+
if (queued || disposed) return;
|
|
761
|
+
queued = true;
|
|
762
|
+
queueMicrotask(() => {
|
|
763
|
+
queued = false;
|
|
764
|
+
if (!disposed) update();
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
function update() {
|
|
768
|
+
try {
|
|
769
|
+
hideOriginal();
|
|
770
|
+
visibility();
|
|
771
|
+
const width = root.clientWidth, height = root.clientHeight, dpr = devicePixelRatio || 1;
|
|
772
|
+
if (!width || !height) return;
|
|
773
|
+
const padX = width / 30 + 2, padY = height / 2 + 2;
|
|
774
|
+
const stops = [...svg.querySelectorAll("stop")].map((stop) => {
|
|
775
|
+
const style2 = getComputedStyle(stop);
|
|
776
|
+
return {
|
|
777
|
+
at: Number(stop.getAttribute("offset") || 0),
|
|
778
|
+
color: `color-mix(in srgb, ${style2.stopColor} ${Number(style2.stopOpacity) * 100}%, transparent)`
|
|
779
|
+
};
|
|
780
|
+
});
|
|
781
|
+
const comet = root.querySelector(".ad-neon-waves-comet"), style = comet && getComputedStyle(comet);
|
|
782
|
+
const shadows = !style ? [] : style.boxShadow.split(/,\s*(?![^()]*\))/).map((shadow) => {
|
|
783
|
+
const values = shadow.match(
|
|
784
|
+
/^(.*?)\s+[-\d.]+px\s+[-\d.]+px\s+([\d.]+)px(?:\s+[-\d.]+px)?$/
|
|
785
|
+
);
|
|
786
|
+
if (!values) throw new Error("Invalid comet shadow");
|
|
787
|
+
return { color: values[1], blur: Number(values[2]) };
|
|
788
|
+
});
|
|
789
|
+
const config = {
|
|
790
|
+
width,
|
|
791
|
+
height,
|
|
792
|
+
dpr,
|
|
793
|
+
padX,
|
|
794
|
+
padY,
|
|
795
|
+
stops,
|
|
796
|
+
shadows,
|
|
797
|
+
color: style?.backgroundColor,
|
|
798
|
+
options: { ...options, comets: comet ? options.comets : 0 }
|
|
799
|
+
};
|
|
800
|
+
const key = JSON.stringify(config);
|
|
801
|
+
if (key === signature) return;
|
|
802
|
+
signature = key;
|
|
803
|
+
canvas.style.left = `${-padX}px`;
|
|
804
|
+
canvas.style.top = `${-padY}px`;
|
|
805
|
+
canvas.style.width = `${width + 2 * padX}px`;
|
|
806
|
+
canvas.style.height = `${height + 2 * padY}px`;
|
|
807
|
+
const surface = transferred ? void 0 : canvas.transferControlToOffscreen();
|
|
808
|
+
transferred = true;
|
|
809
|
+
worker2.postMessage(
|
|
810
|
+
{
|
|
811
|
+
type: "update",
|
|
812
|
+
id,
|
|
813
|
+
canvas: surface,
|
|
814
|
+
...config,
|
|
815
|
+
visible,
|
|
816
|
+
time: options.time
|
|
817
|
+
},
|
|
818
|
+
surface ? [surface] : []
|
|
819
|
+
);
|
|
820
|
+
} catch {
|
|
821
|
+
dispose();
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
queue();
|
|
825
|
+
return renderer;
|
|
826
|
+
}
|
|
827
|
+
|
|
12
828
|
// src/core/motion-engine.js
|
|
13
829
|
var uid = 0;
|
|
14
830
|
var U = {
|
|
@@ -27,8 +843,20 @@ var timer = null;
|
|
|
27
843
|
var last = 0;
|
|
28
844
|
var weakDevice = typeof navigator !== "undefined" && ((navigator.hardwareConcurrency || 8) <= 4 || (navigator.deviceMemory || 8) <= 4);
|
|
29
845
|
var FRAME = 1e3 / (weakDevice ? 20 : 30);
|
|
846
|
+
setBorderFrameRate(1e3 / FRAME);
|
|
847
|
+
setNeonFrameRate(1e3 / FRAME);
|
|
30
848
|
U.setMotionFrameRate = (fps) => {
|
|
31
849
|
FRAME = 1e3 / Math.max(1, Math.min(120, fps));
|
|
850
|
+
setBorderFrameRate(1e3 / FRAME);
|
|
851
|
+
setNeonFrameRate(1e3 / FRAME);
|
|
852
|
+
const now = performance.now();
|
|
853
|
+
for (const animation of looping) {
|
|
854
|
+
animation.__adStart = now - (animation.currentTime || 0);
|
|
855
|
+
if (FRAME > 1e3 / 60) animation.pause();
|
|
856
|
+
}
|
|
857
|
+
if (timer !== null) clearTimeout(timer);
|
|
858
|
+
timer = null;
|
|
859
|
+
refreshMotion();
|
|
32
860
|
};
|
|
33
861
|
var looping = /* @__PURE__ */ new Set();
|
|
34
862
|
var pendingAnimations = /* @__PURE__ */ new Set();
|
|
@@ -60,7 +888,7 @@ function scan(now, animations = pendingAnimations) {
|
|
|
60
888
|
for (const animation of animations)
|
|
61
889
|
if (!looping.has(animation) && animation.playState === "running" && isLoop(animation)) {
|
|
62
890
|
animation.__adStart = now - (animation.currentTime || 0);
|
|
63
|
-
animation.pause();
|
|
891
|
+
if (FRAME > 1e3 / 60) animation.pause();
|
|
64
892
|
looping.add(animation);
|
|
65
893
|
}
|
|
66
894
|
pendingAnimations.clear();
|
|
@@ -74,6 +902,7 @@ function scan(now, animations = pendingAnimations) {
|
|
|
74
902
|
}
|
|
75
903
|
const hidden = document.hidden || target.closest("[data-ad-offscreen], [data-ad-paused]");
|
|
76
904
|
if (hidden) {
|
|
905
|
+
if (FRAME <= 1e3 / 60 && animation.playState === "running") animation.pause();
|
|
77
906
|
animation.__adHeld = true;
|
|
78
907
|
continue;
|
|
79
908
|
}
|
|
@@ -81,6 +910,7 @@ function scan(now, animations = pendingAnimations) {
|
|
|
81
910
|
animation.__adStart = now - (animation.currentTime || 0);
|
|
82
911
|
animation.__adHeld = false;
|
|
83
912
|
}
|
|
913
|
+
if (FRAME <= 1e3 / 60 && animation.playState === "paused") animation.play();
|
|
84
914
|
active.push(animation);
|
|
85
915
|
}
|
|
86
916
|
}
|
|
@@ -109,7 +939,8 @@ function tick(now) {
|
|
|
109
939
|
item.sync();
|
|
110
940
|
}
|
|
111
941
|
if (now - last >= FRAME - 6) {
|
|
112
|
-
|
|
942
|
+
if (FRAME > 1e3 / 60)
|
|
943
|
+
for (const animation of active) animation.currentTime = now - animation.__adStart;
|
|
113
944
|
for (const scope of running) scope.tick(now);
|
|
114
945
|
for (const listener of tickers) listener(now);
|
|
115
946
|
last = now;
|
|
@@ -122,7 +953,7 @@ function tick(now) {
|
|
|
122
953
|
}
|
|
123
954
|
}
|
|
124
955
|
function hasVisibleWork() {
|
|
125
|
-
if (needsScan || tickers.size || active.length) return true;
|
|
956
|
+
if (needsScan || tickers.size || active.length && FRAME > 1e3 / 60) return true;
|
|
126
957
|
for (const item of measurements)
|
|
127
958
|
if (item.element.isConnected && item.element._adInView !== false) return true;
|
|
128
959
|
for (const scope of running)
|
|
@@ -432,7 +1263,7 @@ U.attachBorder = (element, { shell = false, round = false, scope, defer = false
|
|
|
432
1263
|
previousInlinePosition
|
|
433
1264
|
};
|
|
434
1265
|
item.paint = (time) => {
|
|
435
|
-
if (!item.length) return;
|
|
1266
|
+
if (!item.length || item.worker?.ready) return;
|
|
436
1267
|
if (item.previousTime !== null)
|
|
437
1268
|
item.elapsed += Math.min(0.1, Math.max(0, time - item.previousTime));
|
|
438
1269
|
item.previousTime = time;
|
|
@@ -488,6 +1319,10 @@ U.attachBorder = (element, { shell = false, round = false, scope, defer = false
|
|
|
488
1319
|
}
|
|
489
1320
|
}
|
|
490
1321
|
item.paint(scope?.time || 0);
|
|
1322
|
+
if (scope) {
|
|
1323
|
+
item.worker ??= createBorderWorker(item);
|
|
1324
|
+
item.worker?.update();
|
|
1325
|
+
}
|
|
491
1326
|
};
|
|
492
1327
|
const queueMeasurement = () => {
|
|
493
1328
|
if (item.destroyed) return;
|
|
@@ -504,6 +1339,7 @@ U.attachBorder = (element, { shell = false, round = false, scope, defer = false
|
|
|
504
1339
|
measurements.delete(item);
|
|
505
1340
|
unsubscribe?.();
|
|
506
1341
|
item.observer.disconnect();
|
|
1342
|
+
item.worker?.dispose();
|
|
507
1343
|
overlay.remove();
|
|
508
1344
|
if (item.patchedPosition) element.style.position = item.previousInlinePosition;
|
|
509
1345
|
borders.delete(element);
|
|
@@ -857,6 +1693,8 @@ var ThemeProvider = ({
|
|
|
857
1693
|
};
|
|
858
1694
|
|
|
859
1695
|
export {
|
|
1696
|
+
neonGeometry,
|
|
1697
|
+
createNeonRenderer,
|
|
860
1698
|
refreshMotion,
|
|
861
1699
|
setMotionFrameRate,
|
|
862
1700
|
subscribeTick,
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export function setNeonFrameRate(fps: any): void;
|
|
2
|
+
export function createNeonRenderer(root: any, svg: any, initial: any): {
|
|
3
|
+
ready: boolean;
|
|
4
|
+
update(next?: any): void;
|
|
5
|
+
dispose: () => void;
|
|
6
|
+
} | null;
|
|
7
|
+
export function createNeonGeometry(): {
|
|
8
|
+
W: number;
|
|
9
|
+
H: number;
|
|
10
|
+
toPath: (curve: any) => string;
|
|
11
|
+
ridgeStrand: (t: any, drift: any) => any[];
|
|
12
|
+
twistStrand: (t: any, drift: any, main: any) => number[];
|
|
13
|
+
measure: (curve: any) => {
|
|
14
|
+
xs: any[];
|
|
15
|
+
ys: any[];
|
|
16
|
+
lengths: number[];
|
|
17
|
+
total: number;
|
|
18
|
+
};
|
|
19
|
+
pointAt: (track: any, fraction: any) => {
|
|
20
|
+
x: any;
|
|
21
|
+
y: any;
|
|
22
|
+
};
|
|
23
|
+
cometStrand: (i: any, comets: any, strands: any) => number;
|
|
24
|
+
COMET_LAP: number;
|
|
25
|
+
COMET_DASH: number;
|
|
26
|
+
COMET_WIDTH: number;
|
|
27
|
+
};
|
|
28
|
+
export namespace neonGeometry {
|
|
29
|
+
export { W };
|
|
30
|
+
export { H };
|
|
31
|
+
export { toPath };
|
|
32
|
+
export { ridgeStrand };
|
|
33
|
+
export { twistStrand };
|
|
34
|
+
export { measure };
|
|
35
|
+
export { pointAt };
|
|
36
|
+
export { cometStrand };
|
|
37
|
+
export { COMET_LAP };
|
|
38
|
+
export { COMET_DASH };
|
|
39
|
+
export { COMET_WIDTH };
|
|
40
|
+
}
|
|
41
|
+
declare const W: 600;
|
|
42
|
+
declare const H: 120;
|
|
43
|
+
declare function toPath(curve: any): string;
|
|
44
|
+
declare function ridgeStrand(t: any, drift: any): any[];
|
|
45
|
+
declare function twistStrand(t: any, drift: any, main: any): number[];
|
|
46
|
+
declare function measure(curve: any): {
|
|
47
|
+
xs: any[];
|
|
48
|
+
ys: any[];
|
|
49
|
+
lengths: number[];
|
|
50
|
+
total: number;
|
|
51
|
+
};
|
|
52
|
+
declare function pointAt(track: any, fraction: any): {
|
|
53
|
+
x: any;
|
|
54
|
+
y: any;
|
|
55
|
+
};
|
|
56
|
+
declare function cometStrand(i: any, comets: any, strands: any): number;
|
|
57
|
+
declare const COMET_LAP: 6;
|
|
58
|
+
declare const COMET_DASH: 0.016;
|
|
59
|
+
declare const COMET_WIDTH: 1.6;
|
|
60
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export function setBorderFrameRate(fps: any): void;
|
|
2
|
+
/** The SVG/CSS border remains intact until its replacement has painted, and is the fallback. */
|
|
3
|
+
export function createBorderWorker(item: any): {
|
|
4
|
+
ready: boolean;
|
|
5
|
+
update: () => void;
|
|
6
|
+
dispose: () => void;
|
|
7
|
+
} | null;
|
package/dist/core.js
CHANGED
package/dist/forms.js
CHANGED
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
defaultFieldRegistry,
|
|
5
5
|
useForm,
|
|
6
6
|
useFormContext
|
|
7
|
-
} from "./chunks/chunk-
|
|
8
|
-
import "./chunks/chunk-
|
|
7
|
+
} from "./chunks/chunk-FRALT7ER.js";
|
|
8
|
+
import "./chunks/chunk-YVRQTI7B.js";
|
|
9
9
|
import "./chunks/chunk-BJSFN52W.js";
|
|
10
10
|
import "./chunks/chunk-FCOU3ODR.js";
|
|
11
11
|
export {
|
package/dist/index.js
CHANGED
|
@@ -61,10 +61,12 @@ import {
|
|
|
61
61
|
useSvgId,
|
|
62
62
|
variantMaterial,
|
|
63
63
|
vectorElement
|
|
64
|
-
} from "./chunks/chunk-
|
|
64
|
+
} from "./chunks/chunk-FRALT7ER.js";
|
|
65
65
|
import {
|
|
66
66
|
ThemeProvider,
|
|
67
|
+
createNeonRenderer,
|
|
67
68
|
getMotionStats,
|
|
69
|
+
neonGeometry,
|
|
68
70
|
refreshMotion,
|
|
69
71
|
setMotionFrameRate,
|
|
70
72
|
subscribeTick,
|
|
@@ -76,7 +78,7 @@ import {
|
|
|
76
78
|
useTabShape,
|
|
77
79
|
useThemePalette,
|
|
78
80
|
useTick
|
|
79
|
-
} from "./chunks/chunk-
|
|
81
|
+
} from "./chunks/chunk-YVRQTI7B.js";
|
|
80
82
|
import {
|
|
81
83
|
LocaleProvider,
|
|
82
84
|
addMessages,
|
|
@@ -3885,99 +3887,19 @@ function Planet({ children, ...p }) {
|
|
|
3885
3887
|
// src/components/artwork/NeonWaves/NeonWaves.tsx
|
|
3886
3888
|
import { useEffect as useEffect7, useMemo as useMemo3, useRef as useRef22 } from "react";
|
|
3887
3889
|
import { jsx as jsx39, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
3888
|
-
var
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
for (let i = 2; i < curve.length; i += 6)
|
|
3902
|
-
d += `C${curve.slice(i, i + 6).map((n) => n.toFixed(2)).join(" ")}`;
|
|
3903
|
-
return d;
|
|
3904
|
-
};
|
|
3905
|
-
var smoothTo = (curve, c2x, c2y, x, y) => {
|
|
3906
|
-
const n = curve.length;
|
|
3907
|
-
curve.push(2 * curve[n - 2] - curve[n - 4], 2 * curve[n - 1] - curve[n - 3], c2x, c2y, x, y);
|
|
3908
|
-
};
|
|
3909
|
-
var smooth = (xs, ys) => {
|
|
3910
|
-
const curve = [xs[0], ys[0]];
|
|
3911
|
-
for (let i = 0; i < xs.length - 1; i += 1) {
|
|
3912
|
-
const x0 = xs[i - 1] ?? xs[i], y0 = ys[i - 1] ?? ys[i];
|
|
3913
|
-
const x1 = xs[i], y1 = ys[i], x2 = xs[i + 1], y2 = ys[i + 1];
|
|
3914
|
-
const x3 = xs[i + 2] ?? x2, y3 = ys[i + 2] ?? y2;
|
|
3915
|
-
curve.push(x1 + (x2 - x0) / 6, y1 + (y2 - y0) / 6, x2 - (x3 - x1) / 6, y2 - (y3 - y1) / 6, x2, y2);
|
|
3916
|
-
}
|
|
3917
|
-
return curve;
|
|
3918
|
-
};
|
|
3919
|
-
var ridgeStrand = (t, drift) => {
|
|
3920
|
-
const xs = [];
|
|
3921
|
-
const ys = [];
|
|
3922
|
-
for (let i = 0; i <= SAMPLES; i += 1) {
|
|
3923
|
-
const x = i / SAMPLES;
|
|
3924
|
-
const base = skyline(x);
|
|
3925
|
-
const spread = H3 * (0.06 + 0.26 * base);
|
|
3926
|
-
const ripple2 = Math.sin(x * 8 + drift + t * 7) * H3 * (0.03 + 0.05 * base) + Math.sin(x * 21 - drift * 1.3 + t * 11) * H3 * 0.014;
|
|
3927
|
-
xs.push(x * (W3 + 20) - 10);
|
|
3928
|
-
ys.push(base * H3 + (t - 0.5) * spread + ripple2);
|
|
3929
|
-
}
|
|
3930
|
-
return smooth(xs, ys);
|
|
3931
|
-
};
|
|
3932
|
-
var twistStrand = (t, drift, main) => {
|
|
3933
|
-
const a = Math.sin(drift + t * 1.4) * H3 * 0.095;
|
|
3934
|
-
const b = Math.cos(drift * 0.8 + t * 1.8) * H3 * 0.08;
|
|
3935
|
-
if (!main) {
|
|
3936
|
-
const curve2 = [-12, H3 * (0.9 + t * 0.12) + b, W3 * 0.21, H3 * 0.98 + a, W3 * 0.33, H3 * 0.24 + t * H3 * 0.2 + a, W3 * 0.52, H3 * 0.75 + t * H3 * 0.25 + b];
|
|
3937
|
-
smoothTo(curve2, W3 * 0.82, H3 * 0.38 + t * H3 * 0.27 + a, W3 + 8, H3 * (0.48 + t * 0.5) + b);
|
|
3938
|
-
return curve2;
|
|
3939
|
-
}
|
|
3940
|
-
const curve = [-12, H3 * (0.38 + t * 0.58) + a, W3 * 0.2, H3 * 1.28 - t * H3 * 0.27 + a, W3 * 0.32, H3 * 0.34 + t * H3 * 0.21 + b, W3 * 0.46, H3 * 0.62 + t * H3 * 0.12];
|
|
3941
|
-
smoothTo(curve, W3 * 0.67, H3 * 1.14 - t * H3 * 0.09 + a, W3 * 0.8, H3 * 0.69 - t * H3 * 0.22 + b);
|
|
3942
|
-
smoothTo(curve, W3 * 0.94, H3 * 0.43 - t * H3 * 0.44 + a, W3 + 8, H3 * 0.21 + t * H3 * 0.45);
|
|
3943
|
-
return curve;
|
|
3944
|
-
};
|
|
3945
|
-
var STEPS = 16;
|
|
3946
|
-
var measure = (curve) => {
|
|
3947
|
-
const xs = [curve[0]], ys = [curve[1]], lengths = [0];
|
|
3948
|
-
for (let i = 2; i < curve.length; i += 6) {
|
|
3949
|
-
const x0 = curve[i - 2], y0 = curve[i - 1];
|
|
3950
|
-
const [x1, y1, x2, y2, x3, y3] = curve.slice(i, i + 6);
|
|
3951
|
-
for (let k = 1; k <= STEPS; k += 1) {
|
|
3952
|
-
const u = k / STEPS, v = 1 - u;
|
|
3953
|
-
const x = v * v * v * x0 + 3 * v * v * u * x1 + 3 * v * u * u * x2 + u * u * u * x3;
|
|
3954
|
-
const y = v * v * v * y0 + 3 * v * v * u * y1 + 3 * v * u * u * y2 + u * u * u * y3;
|
|
3955
|
-
lengths.push(lengths[lengths.length - 1] + Math.hypot(x - xs[xs.length - 1], y - ys[ys.length - 1]));
|
|
3956
|
-
xs.push(x);
|
|
3957
|
-
ys.push(y);
|
|
3958
|
-
}
|
|
3959
|
-
}
|
|
3960
|
-
return { xs, ys, lengths, total: lengths[lengths.length - 1] };
|
|
3961
|
-
};
|
|
3962
|
-
var pointAt = (track, fraction) => {
|
|
3963
|
-
const distance = Math.min(1, Math.max(0, fraction)) * track.total;
|
|
3964
|
-
let low = 0, high = track.lengths.length - 1;
|
|
3965
|
-
while (high - low > 1) {
|
|
3966
|
-
const middle = low + high >> 1;
|
|
3967
|
-
if (track.lengths[middle] < distance) low = middle;
|
|
3968
|
-
else high = middle;
|
|
3969
|
-
}
|
|
3970
|
-
const span = track.lengths[high] - track.lengths[low] || 1;
|
|
3971
|
-
const k = (distance - track.lengths[low]) / span;
|
|
3972
|
-
return {
|
|
3973
|
-
x: track.xs[low] + (track.xs[high] - track.xs[low]) * k,
|
|
3974
|
-
y: track.ys[low] + (track.ys[high] - track.ys[low]) * k
|
|
3975
|
-
};
|
|
3976
|
-
};
|
|
3977
|
-
var COMET_LAP = 6;
|
|
3978
|
-
var COMET_DASH = 0.016;
|
|
3979
|
-
var COMET_WIDTH = 1.6;
|
|
3980
|
-
var cometStrand = (i, comets, strands) => Math.min(strands - 1, Math.round((i + 0.5) / comets * (strands - 1)));
|
|
3890
|
+
var {
|
|
3891
|
+
W: W3,
|
|
3892
|
+
H: H3,
|
|
3893
|
+
toPath,
|
|
3894
|
+
ridgeStrand,
|
|
3895
|
+
twistStrand,
|
|
3896
|
+
measure,
|
|
3897
|
+
pointAt,
|
|
3898
|
+
cometStrand,
|
|
3899
|
+
COMET_LAP,
|
|
3900
|
+
COMET_DASH,
|
|
3901
|
+
COMET_WIDTH
|
|
3902
|
+
} = neonGeometry;
|
|
3981
3903
|
function NeonWaves({
|
|
3982
3904
|
strands = 22,
|
|
3983
3905
|
stars = true,
|
|
@@ -3995,6 +3917,7 @@ function NeonWaves({
|
|
|
3995
3917
|
const cometElements = useRef22(null);
|
|
3996
3918
|
const size = useRef22({ width: 0, height: 0 });
|
|
3997
3919
|
const lastTime = useRef22(0);
|
|
3920
|
+
const renderer = useRef22(null);
|
|
3998
3921
|
const motion = useMotion();
|
|
3999
3922
|
const id = useSvgId();
|
|
4000
3923
|
const dots = useMemo3(() => {
|
|
@@ -4014,14 +3937,27 @@ function NeonWaves({
|
|
|
4014
3937
|
const observer = createResizeObserver(([entry]) => {
|
|
4015
3938
|
if (!entry) return;
|
|
4016
3939
|
size.current = { width: entry.contentRect.width, height: entry.contentRect.height };
|
|
3940
|
+
renderer.current?.update();
|
|
4017
3941
|
painter.current(lastTime.current);
|
|
4018
3942
|
});
|
|
4019
3943
|
observer.observe(root);
|
|
4020
3944
|
return () => observer.disconnect();
|
|
4021
3945
|
}, []);
|
|
3946
|
+
useEffect7(() => {
|
|
3947
|
+
if (!rootRef.current || !ref.current) return;
|
|
3948
|
+
renderer.current = createNeonRenderer(rootRef.current, ref.current, { strands, phase, shape, comets, time: lastTime.current });
|
|
3949
|
+
return () => {
|
|
3950
|
+
renderer.current?.dispose();
|
|
3951
|
+
renderer.current = null;
|
|
3952
|
+
};
|
|
3953
|
+
}, []);
|
|
3954
|
+
useEffect7(() => {
|
|
3955
|
+
renderer.current?.update({ strands, phase, shape, comets, time: lastTime.current });
|
|
3956
|
+
}, [strands, phase, shape, comets, motion]);
|
|
4022
3957
|
usePauseOffscreen(ref);
|
|
4023
3958
|
const paint = (time) => {
|
|
4024
3959
|
lastTime.current = time;
|
|
3960
|
+
if (renderer.current?.ready) return;
|
|
4025
3961
|
if (lastDraw.current < 0 || time - lastDraw.current >= 1 / 16) {
|
|
4026
3962
|
lastDraw.current = time;
|
|
4027
3963
|
const node = ref.current;
|
|
@@ -6056,11 +5992,11 @@ function PlaybackTrack({ audio, playing, position: controlledPosition, disabled,
|
|
|
6056
5992
|
// src/components/media/LevelMeter/LevelMeter.tsx
|
|
6057
5993
|
import { useEffect as useEffect13, useRef as useRef28 } from "react";
|
|
6058
5994
|
import { jsx as jsx48, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
6059
|
-
var
|
|
5995
|
+
var SAMPLES = 64;
|
|
6060
5996
|
var WIDTH = 256;
|
|
6061
5997
|
var HEIGHT = 24;
|
|
6062
5998
|
var MID2 = HEIGHT / 2;
|
|
6063
|
-
var STEP = WIDTH / (
|
|
5999
|
+
var STEP = WIDTH / (SAMPLES - 1);
|
|
6064
6000
|
var SAMPLE_MS = 28;
|
|
6065
6001
|
var wavePath2 = (samples) => {
|
|
6066
6002
|
const point = (i, level, side) => `${(i * STEP).toFixed(2)} ${(MID2 + side * (1 + level ** 0.68 * (MID2 - 3))).toFixed(2)}`;
|
|
@@ -6095,7 +6031,7 @@ function LevelMeter({
|
|
|
6095
6031
|
useEffect13(() => {
|
|
6096
6032
|
const shape = path.current;
|
|
6097
6033
|
if (!shape) return;
|
|
6098
|
-
const samples = Array.from({ length:
|
|
6034
|
+
const samples = Array.from({ length: SAMPLES + 1 }, () => 0);
|
|
6099
6035
|
shape.setAttribute("d", wavePath2(samples));
|
|
6100
6036
|
wake.current = () => void 0;
|
|
6101
6037
|
if (!active) return;
|