@bokijonovm/cursorcrew 0.0.0-stage → 0.1.1

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.
@@ -0,0 +1,815 @@
1
+ "use client";
2
+
3
+ // src/timeline.ts
4
+ var EASES = {
5
+ none: (t) => t,
6
+ "power1.in": (t) => t * t,
7
+ "power1.out": (t) => 1 - (1 - t) * (1 - t),
8
+ "power1.inOut": (t) => t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2,
9
+ "power2.in": (t) => t * t * t,
10
+ "power2.out": (t) => 1 - Math.pow(1 - t, 3),
11
+ "power2.inOut": (t) => t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2
12
+ };
13
+ function getEase(name) {
14
+ if (typeof name === "function") return name;
15
+ if (!name) return EASES["power1.out"];
16
+ if (EASES[name]) return EASES[name];
17
+ const m = /^back\.out(?:\(([\d.]+)\))?$/.exec(name);
18
+ if (m) {
19
+ const c1 = m[1] ? +m[1] : 1.70158;
20
+ const c3 = c1 + 1;
21
+ return EASES[name] = (t) => 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2);
22
+ }
23
+ return EASES["power1.out"];
24
+ }
25
+ var RESERVED = /* @__PURE__ */ new Set(["duration", "ease", "immediateRender", "onUpdate", "onComplete", "onStart", "overwrite"]);
26
+ var TRANSFORM = /* @__PURE__ */ new Set(["x", "y", "scale"]);
27
+ var transforms = /* @__PURE__ */ new WeakMap();
28
+ function transformOf(el) {
29
+ let t = transforms.get(el);
30
+ if (!t) transforms.set(el, t = { x: 0, y: 0, scale: 1 });
31
+ return t;
32
+ }
33
+ var isElement = (o) => !!o && o.nodeType === 1;
34
+ function read(target, prop) {
35
+ if (!isElement(target)) return target[prop];
36
+ if (TRANSFORM.has(prop)) return transformOf(target)[prop];
37
+ const cs = getComputedStyle(target);
38
+ if (prop === "autoAlpha") return cs.visibility === "hidden" ? 0 : parseFloat(cs.opacity);
39
+ const v = String(target.style[prop] || cs[prop] || "");
40
+ return /^-?[\d.]+(px)?$/.test(v) ? parseFloat(v) : v;
41
+ }
42
+ function set(target, values) {
43
+ const props = values;
44
+ if (!isElement(target)) {
45
+ for (const k in props) if (!RESERVED.has(k)) target[k] = props[k];
46
+ return;
47
+ }
48
+ const s = target.style;
49
+ let t = null;
50
+ for (const p in props) {
51
+ if (RESERVED.has(p)) continue;
52
+ const v = props[p];
53
+ if (p === "attr") {
54
+ for (const [k, val] of Object.entries(v)) target.setAttribute(k, val);
55
+ } else if (TRANSFORM.has(p)) {
56
+ (t ?? (t = transformOf(target)))[p] = v;
57
+ } else if (p === "autoAlpha") {
58
+ s.opacity = String(v);
59
+ s.visibility = v <= 0 ? "hidden" : "inherit";
60
+ } else if (p === "width" || p === "height") {
61
+ s[p] = typeof v === "number" ? `${v}px` : v;
62
+ } else {
63
+ s[p] = typeof v === "number" ? String(v) : v;
64
+ }
65
+ }
66
+ if (t) s.transform = `translate3d(${t.x}px,${t.y}px,0)${t.scale !== 1 ? ` scale(${t.scale})` : ""}`;
67
+ }
68
+ var NUMBER = /-?\d*\.?\d+(?:e[-+]?\d+)?/gi;
69
+ function interpolator(from, to) {
70
+ if (typeof to === "string" && /^[-+]=/.test(to)) {
71
+ to = (Number(from) || 0) + (to[0] === "-" ? -1 : 1) * parseFloat(to.slice(2));
72
+ }
73
+ if (typeof to === "number") {
74
+ const a = Number(from) || 0;
75
+ const b = to;
76
+ return (e) => a + (b - a) * e;
77
+ }
78
+ if (typeof to === "string" && typeof from === "string") {
79
+ const bn = to.match(NUMBER) ?? [];
80
+ const an = from.match(NUMBER) ?? [];
81
+ if (bn.length && an.length === bn.length) {
82
+ const parts = to.split(NUMBER);
83
+ return (e) => {
84
+ let out = parts[0];
85
+ for (let i = 0; i < bn.length; i++) out += +an[i] + (+bn[i] - +an[i]) * e + parts[i + 1];
86
+ return out;
87
+ };
88
+ }
89
+ }
90
+ return () => to;
91
+ }
92
+ var Timeline = class {
93
+ constructor(opts = {}) {
94
+ this.opts = opts;
95
+ this.kids = [];
96
+ this.t = 0;
97
+ this.end = 0;
98
+ this.ts = 1;
99
+ this.paused = true;
100
+ this.dead = false;
101
+ this.started = false;
102
+ this.completed = false;
103
+ this.raf = 0;
104
+ this.last = 0;
105
+ this.tick = this.tick.bind(this);
106
+ if (!opts.paused) this.play();
107
+ }
108
+ /** Apply `vars` instantly at `position` seconds. */
109
+ set(target, vars, position) {
110
+ return this.add(target, null, { ...vars, duration: 0 }, position);
111
+ }
112
+ /** Tween from the target's current values (read when the tween starts). */
113
+ to(target, vars, position) {
114
+ return this.add(target, null, vars, position);
115
+ }
116
+ /** Tween between explicit values. Renders `from` right away unless `immediateRender: false`. */
117
+ fromTo(target, from, to, position) {
118
+ if (to.immediateRender !== false) set(target, from);
119
+ return this.add(target, from, to, position);
120
+ }
121
+ play() {
122
+ if (this.dead || this.completed) return this;
123
+ this.paused = false;
124
+ if (!this.raf) {
125
+ this.last = performance.now();
126
+ this.raf = requestAnimationFrame(this.tick);
127
+ }
128
+ return this;
129
+ }
130
+ pause() {
131
+ this.paused = true;
132
+ if (this.raf) cancelAnimationFrame(this.raf);
133
+ this.raf = 0;
134
+ return this;
135
+ }
136
+ kill() {
137
+ this.pause();
138
+ this.dead = true;
139
+ this.kids = [];
140
+ return this;
141
+ }
142
+ /** Total length in seconds, before timeScale. */
143
+ duration() {
144
+ return this.end;
145
+ }
146
+ /** Current playhead in seconds. */
147
+ time() {
148
+ return this.t;
149
+ }
150
+ isActive() {
151
+ return !this.paused && !this.dead && !this.completed;
152
+ }
153
+ timeScale(value) {
154
+ if (value === void 0) return this.ts;
155
+ this.ts = value > 0 && Number.isFinite(value) ? value : 1;
156
+ return this;
157
+ }
158
+ progress(value) {
159
+ if (value === void 0) return this.end ? this.t / this.end : 1;
160
+ this.goto(value * this.end);
161
+ return this;
162
+ }
163
+ add(target, from, to, position) {
164
+ const tween = {
165
+ target,
166
+ from,
167
+ to,
168
+ start: position ?? this.end,
169
+ dur: Math.max(0, to.duration ?? 0.5),
170
+ ease: getEase(to.ease),
171
+ fns: null,
172
+ done: false
173
+ };
174
+ let i = this.kids.length;
175
+ while (i > 0 && this.kids[i - 1].start > tween.start) i--;
176
+ this.kids.splice(i, 0, tween);
177
+ this.end = Math.max(this.end, tween.start + tween.dur);
178
+ return this;
179
+ }
180
+ render(time) {
181
+ for (const c of this.kids) {
182
+ if (c.start > time) break;
183
+ if (c.done) continue;
184
+ if (!c.fns) {
185
+ c.fns = {};
186
+ for (const k in c.to) {
187
+ if (RESERVED.has(k)) continue;
188
+ if (k === "attr") {
189
+ const attr = c.to.attr;
190
+ c.fns.attr = () => attr;
191
+ } else {
192
+ c.fns[k] = interpolator(c.from && k in c.from ? c.from[k] : read(c.target, k), c.to[k]);
193
+ }
194
+ }
195
+ }
196
+ const p = c.dur ? Math.min(1, (time - c.start) / c.dur) : 1;
197
+ const e = c.ease(p);
198
+ const props = {};
199
+ for (const f in c.fns) props[f] = c.fns[f](e);
200
+ set(c.target, props);
201
+ c.to.onUpdate?.();
202
+ if (p >= 1) c.done = true;
203
+ }
204
+ }
205
+ goto(time) {
206
+ if (this.dead) return;
207
+ time = Math.max(0, Math.min(time, this.end));
208
+ if (!this.started) {
209
+ this.started = true;
210
+ this.opts.onStart?.();
211
+ }
212
+ this.t = time;
213
+ this.render(time);
214
+ this.opts.onUpdate?.();
215
+ if (time >= this.end && !this.completed) {
216
+ this.completed = true;
217
+ this.pause();
218
+ this.opts.onComplete?.();
219
+ }
220
+ }
221
+ tick(now) {
222
+ this.raf = 0;
223
+ if (this.paused || this.dead) return;
224
+ let dt = (now - this.last) / 1e3;
225
+ this.last = now;
226
+ if (dt > 0.25) dt = 1 / 60;
227
+ this.goto(this.t + dt * this.ts);
228
+ if (!this.paused && !this.dead) this.raf = requestAnimationFrame(this.tick);
229
+ }
230
+ };
231
+
232
+ // src/scan.ts
233
+ var SKIP_TAGS = /* @__PURE__ */ new Set(["SCRIPT", "STYLE", "TEMPLATE", "NOSCRIPT", "LINK", "META", "HEAD", "TITLE", "BR", "WBR", "SOURCE", "TRACK"]);
234
+ var MEDIA_TAGS = /* @__PURE__ */ new Set(["IMG", "SVG", "svg", "VIDEO", "CANVAS", "PICTURE", "IFRAME", "OBJECT", "EMBED"]);
235
+ var CONTROL_TAGS = /* @__PURE__ */ new Set(["INPUT", "TEXTAREA", "SELECT", "PROGRESS", "METER"]);
236
+ var isTransparent = (c) => !c || c === "transparent" || /^rgba?\([^,)]+,[^,)]+,[^,)]+,\s*0*\.?0*%?\s*\)$/.test(c) || /\/\s*0*\.?0*%?\s*\)$/.test(c);
237
+ function paintsSurface(cs) {
238
+ if (!isTransparent(cs.backgroundColor)) return true;
239
+ if (cs.backgroundImage && cs.backgroundImage !== "none") return true;
240
+ if (cs.boxShadow && cs.boxShadow !== "none") return true;
241
+ for (const side of ["Top", "Right", "Bottom", "Left"]) {
242
+ const width = parseFloat(cs[`border${side}Width`]);
243
+ const style = cs[`border${side}Style`];
244
+ if (width > 0 && style !== "none" && style !== "hidden" && !isTransparent(cs[`border${side}Color`])) return true;
245
+ }
246
+ return false;
247
+ }
248
+ function hasOwnText(el) {
249
+ for (const node of Array.from(el.childNodes)) {
250
+ if (node.nodeType === 3 && node.nodeValue && node.nodeValue.trim()) return true;
251
+ }
252
+ return false;
253
+ }
254
+ function onlyInlineDescendants(el) {
255
+ for (const child of Array.from(el.children)) {
256
+ if (child.tagName === "BR") continue;
257
+ if (MEDIA_TAGS.has(child.tagName) || CONTROL_TAGS.has(child.tagName)) return false;
258
+ if (getComputedStyle(child).display !== "inline" || !onlyInlineDescendants(child)) return false;
259
+ }
260
+ return true;
261
+ }
262
+ function isInlineTextBlock(el) {
263
+ if (!el.textContent || !el.textContent.trim()) return false;
264
+ for (const child of Array.from(el.children)) {
265
+ if (SKIP_TAGS.has(child.tagName)) continue;
266
+ if (MEDIA_TAGS.has(child.tagName) || CONTROL_TAGS.has(child.tagName)) return false;
267
+ const display = getComputedStyle(child).display;
268
+ if (display !== "inline" && display !== "contents" || !onlyInlineDescendants(child)) return false;
269
+ }
270
+ return true;
271
+ }
272
+ function labelFor(el, kind) {
273
+ if (kind === "text") {
274
+ const text = (el.textContent || "").replace(/\s+/g, " ").trim();
275
+ return `\u201C${text.length > 18 ? text.slice(0, 17) + "\u2026" : text}\u201D`;
276
+ }
277
+ const tag = el.tagName.toLowerCase();
278
+ if (kind === "media") return tag === "img" || tag === "picture" ? "image" : tag;
279
+ const cls = (el.getAttribute("class") || "").trim().split(/\s+/)[0];
280
+ return cls ? `${tag}.${cls.slice(0, 16)}` : tag;
281
+ }
282
+ function collectTasks(root, origin, maxTasks) {
283
+ const tasks = [];
284
+ const add = (el, kind, hasBox, parent) => {
285
+ const r = el.getBoundingClientRect();
286
+ const rect = { x: r.left - origin.left, y: r.top - origin.top, w: r.width, h: r.height };
287
+ tasks.push({ id: tasks.length, el, kind, hasBox, rect, parent, label: labelFor(el, kind), area: rect.w * rect.h });
288
+ return tasks.length - 1;
289
+ };
290
+ const walk = (el, parent, isRoot) => {
291
+ if (SKIP_TAGS.has(el.tagName)) return;
292
+ const mode = el.getAttribute("data-assemble");
293
+ if (mode === "skip") return;
294
+ const cs = getComputedStyle(el);
295
+ if (cs.display === "none") return;
296
+ const r = el.getBoundingClientRect();
297
+ const visible = r.width >= 2 && r.height >= 2;
298
+ const tag = el.tagName;
299
+ if (visible && !(isRoot && (tag === "BODY" || tag === "HTML"))) {
300
+ if (mode === "block") return void add(el, "block", false, parent);
301
+ if (MEDIA_TAGS.has(tag)) return void add(el, "media", false, parent);
302
+ if (CONTROL_TAGS.has(tag)) return void add(el, "box", true, parent);
303
+ const box = paintsSurface(cs);
304
+ if (hasOwnText(el) || isInlineTextBlock(el)) return void add(el, "text", box, parent);
305
+ if (box) parent = add(el, "box", true, parent);
306
+ }
307
+ for (const child of Array.from(el.children)) walk(child, parent, false);
308
+ };
309
+ walk(root, -1, true);
310
+ if (tasks.length <= maxTasks) return tasks;
311
+ const dropped = /* @__PURE__ */ new Set();
312
+ for (const t of tasks.filter((t2) => t2.parent !== -1).sort((a, b) => a.area - b.area)) {
313
+ if (tasks.length - dropped.size <= maxTasks) break;
314
+ dropped.add(t.id);
315
+ }
316
+ const keptAncestor = (p) => {
317
+ while (p !== -1 && dropped.has(p)) p = tasks[p].parent;
318
+ return p;
319
+ };
320
+ const kept = tasks.filter((t) => !dropped.has(t.id));
321
+ const newIndex = /* @__PURE__ */ new Map();
322
+ kept.forEach((t, i) => newIndex.set(t.id, i));
323
+ for (const t of kept) {
324
+ const p = keptAncestor(t.parent);
325
+ t.parent = p === -1 ? -1 : newIndex.get(p);
326
+ }
327
+ kept.forEach((t, i) => t.id = i);
328
+ return kept;
329
+ }
330
+
331
+ // src/text.ts
332
+ var Segmenter = typeof Intl !== "undefined" ? Intl.Segmenter : void 0;
333
+ var segmenter = Segmenter ? new Segmenter(void 0, { granularity: "grapheme" }) : null;
334
+ var graphemes = (s) => segmenter ? Array.from(segmenter.segment(s), (x) => x.segment) : Array.from(s);
335
+ var WORD_THRESHOLD = 160;
336
+ function splitText(el, mode) {
337
+ const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, {
338
+ acceptNode(node) {
339
+ const parent = node.parentElement;
340
+ if (!parent || parent.closest("script,style,svg,textarea")) return NodeFilter.FILTER_REJECT;
341
+ return node.nodeValue ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
342
+ }
343
+ });
344
+ const nodes = [];
345
+ while (walker.nextNode()) nodes.push(walker.currentNode);
346
+ const length = nodes.reduce((n, t) => n + (t.nodeValue || "").trim().length, 0);
347
+ const byWord = mode === "word" || mode === "auto" && length > WORD_THRESHOLD;
348
+ const chunks = [];
349
+ const replaced = [];
350
+ for (const node of nodes) {
351
+ const value = node.nodeValue || "";
352
+ if (!value.trim()) continue;
353
+ const pieces = byWord ? value.match(/\s+|\S+/g) || [] : graphemes(value);
354
+ const fragment = document.createDocumentFragment();
355
+ const created = [];
356
+ for (const piece of pieces) {
357
+ let out;
358
+ if (!piece.trim()) {
359
+ out = document.createTextNode(piece);
360
+ } else {
361
+ const span = document.createElement("span");
362
+ span.textContent = piece;
363
+ span.style.visibility = "hidden";
364
+ span.setAttribute("data-cc-chunk", "");
365
+ chunks.push(span);
366
+ out = span;
367
+ }
368
+ fragment.appendChild(out);
369
+ created.push(out);
370
+ }
371
+ if (/flex|grid/.test(getComputedStyle(node.parentElement).display)) {
372
+ const item = document.createElement("span");
373
+ item.appendChild(fragment);
374
+ fragment.appendChild(item);
375
+ created.splice(0, created.length, item);
376
+ }
377
+ node.parentNode.insertBefore(fragment, node);
378
+ node.parentNode.removeChild(node);
379
+ replaced.push({ original: node, created });
380
+ }
381
+ let restored = false;
382
+ return {
383
+ chunks,
384
+ restore() {
385
+ if (restored) return;
386
+ restored = true;
387
+ for (const { original, created } of replaced) {
388
+ const first = created[0];
389
+ if (first && first.parentNode) first.parentNode.insertBefore(original, first);
390
+ for (const n of created) n.parentNode?.removeChild(n);
391
+ }
392
+ }
393
+ };
394
+ }
395
+
396
+ // src/overlay.ts
397
+ var DEFAULT_AGENTS = [
398
+ { name: "Atlas", color: "#6d5efc" },
399
+ { name: "Nova", color: "#f2547d" },
400
+ { name: "Echo", color: "#12a8a0" },
401
+ { name: "Pixel", color: "#f08a24" },
402
+ { name: "Orbit", color: "#2f80ed" },
403
+ { name: "Juno", color: "#9b51e0" },
404
+ { name: "Sol", color: "#d4a20b" },
405
+ { name: "Kai", color: "#27ae60" }
406
+ ];
407
+ function resolveAgents(agents) {
408
+ if (Array.isArray(agents) && agents.length) return agents.slice();
409
+ const count = Math.min(24, Math.max(1, typeof agents === "number" ? Math.round(agents) : 5));
410
+ return Array.from({ length: count }, (_, i) => {
411
+ const base = DEFAULT_AGENTS[i % DEFAULT_AGENTS.length];
412
+ return i < DEFAULT_AGENTS.length ? { ...base } : { name: `${base.name} ${Math.floor(i / DEFAULT_AGENTS.length) + 1}`, color: base.color };
413
+ });
414
+ }
415
+ var STYLE_ID = "cursorcrew-css";
416
+ var CSS = `
417
+ [data-assemble-pending]{visibility:hidden}
418
+ .cc-layer{position:absolute;left:0;top:0;overflow:hidden;pointer-events:none}
419
+ .cc-layer *{box-sizing:border-box}
420
+ .cc-agent{position:absolute;left:0;top:0;width:0;height:0;will-change:transform;z-index:3}
421
+ .cc-ic{position:absolute;display:none;overflow:visible;filter:drop-shadow(0 1px 2px rgba(0,0,0,.25))}
422
+ .cc-agent[data-mode=arrow] .cc-arrow,.cc-agent[data-mode=cross] .cc-cross,.cc-agent[data-mode=beam] .cc-beam{display:block}
423
+ .cc-arrow{left:-1px;top:-1px;width:18px;height:22px}
424
+ .cc-cross{left:-9px;top:-9px;width:18px;height:18px}
425
+ .cc-beam{left:-5px;top:-10px;width:10px;height:20px}
426
+ .cc-tag{position:absolute;left:14px;top:18px;display:flex;align-items:center;gap:6px;white-space:nowrap;
427
+ font:600 11px/1 ui-sans-serif,system-ui,-apple-system,"Segoe UI",sans-serif;color:#fff;background:var(--c);
428
+ padding:4px 7px;border-radius:2px 8px 8px 8px;box-shadow:0 2px 6px rgba(0,0,0,.18);letter-spacing:.01em}
429
+ .cc-tag::after{content:attr(data-action);font-weight:500;opacity:.82;max-width:180px;overflow:hidden;text-overflow:ellipsis}
430
+ .cc-tag[data-action=""]::after{display:none}
431
+ .cc-noactions .cc-tag::after{display:none}
432
+ .cc-nolabels .cc-tag{display:none}
433
+ .cc-draw{position:absolute;left:0;top:0;width:0;height:0;visibility:hidden;opacity:0;z-index:1;
434
+ border:1.5px solid var(--c);background:color-mix(in srgb,var(--c) 7%,transparent)}
435
+ .cc-draw[data-kind=text]{border-style:dashed;background:none}
436
+ .cc-draw[data-kind=media],.cc-draw[data-kind=block]{background:repeating-linear-gradient(135deg,
437
+ color-mix(in srgb,var(--c) 14%,transparent) 0 6px,color-mix(in srgb,var(--c) 4%,transparent) 6px 12px)}
438
+ .cc-dim{position:absolute;left:50%;top:100%;transform:translate(-50%,5px);font:600 10px/1 ui-monospace,SFMono-Regular,Menlo,monospace;
439
+ color:#fff;background:var(--c);padding:3px 5px;border-radius:3px;white-space:nowrap}
440
+ .cc-caret{position:absolute;left:0;top:0;width:2px;visibility:hidden;opacity:0;z-index:2;background:var(--c)}
441
+ `;
442
+ function injectStyles() {
443
+ if (document.getElementById(STYLE_ID)) return;
444
+ const style = document.createElement("style");
445
+ style.id = STYLE_ID;
446
+ style.textContent = CSS;
447
+ document.head.appendChild(style);
448
+ }
449
+ function createLayer(zIndex, labels, actions) {
450
+ const layer = document.createElement("div");
451
+ layer.className = "cc-layer" + (labels ? "" : " cc-nolabels") + (actions ? "" : " cc-noactions");
452
+ layer.setAttribute("aria-hidden", "true");
453
+ const doc = document.documentElement;
454
+ layer.style.width = Math.max(doc.scrollWidth, document.body.scrollWidth) + "px";
455
+ layer.style.height = Math.max(doc.scrollHeight, document.body.scrollHeight) + "px";
456
+ layer.style.zIndex = String(zIndex);
457
+ document.body.appendChild(layer);
458
+ return layer;
459
+ }
460
+ var ICONS = '<svg class="cc-ic cc-arrow" viewBox="0 0 18 22"><path d="M1.5 1.5v16.2l4.3-4.1 2.9 6.6 2.7-1.2-2.9-6.5h6z" fill="var(--c)" stroke="#fff" stroke-width="1.5" stroke-linejoin="round"/></svg><svg class="cc-ic cc-cross" viewBox="0 0 18 18"><path d="M9 1v16M1 9h16" stroke="#fff" stroke-width="3.5" stroke-linecap="round"/><path d="M9 1v16M1 9h16" stroke="var(--c)" stroke-width="1.6" stroke-linecap="round"/></svg><svg class="cc-ic cc-beam" viewBox="0 0 10 20"><path d="M2 1.5h6M5 1.5v17M2 18.5h6" stroke="#fff" stroke-width="3.5" stroke-linecap="round"/><path d="M2 1.5h6M5 1.5v17M2 18.5h6" stroke="var(--c)" stroke-width="1.6" stroke-linecap="round"/></svg>';
461
+ function createAgent(layer, config) {
462
+ const el = document.createElement("div");
463
+ el.className = "cc-agent";
464
+ el.dataset.mode = "arrow";
465
+ el.style.setProperty("--c", config.color);
466
+ el.innerHTML = ICONS;
467
+ const tag = document.createElement("div");
468
+ tag.className = "cc-tag";
469
+ tag.textContent = config.name;
470
+ tag.setAttribute("data-action", "");
471
+ el.appendChild(tag);
472
+ const caret = document.createElement("div");
473
+ caret.className = "cc-caret";
474
+ caret.style.setProperty("--c", config.color);
475
+ layer.appendChild(el);
476
+ layer.appendChild(caret);
477
+ return { el, tag, caret, config };
478
+ }
479
+ function createDrawBox(layer, kind, color, withSize) {
480
+ const box = document.createElement("div");
481
+ box.className = "cc-draw";
482
+ box.dataset.kind = kind;
483
+ box.style.setProperty("--c", color);
484
+ let size = null;
485
+ if (withSize) {
486
+ size = document.createElement("div");
487
+ size.className = "cc-dim";
488
+ box.appendChild(size);
489
+ }
490
+ layer.appendChild(box);
491
+ return { box, size };
492
+ }
493
+
494
+ // src/assemble.ts
495
+ var clamp = (v, lo, hi) => Math.min(hi, Math.max(lo, v));
496
+ var distance = (a, b) => Math.hypot(a.x - b.x, a.y - b.y);
497
+ var TIMING = {
498
+ travel: (px) => clamp(0.22 + px / 1700, 0.28, 0.85),
499
+ draw: (area) => clamp(0.32 + Math.sqrt(area) / 1500, 0.38, 0.95),
500
+ frame: (area) => clamp(0.18 + Math.sqrt(area) / 2600, 0.2, 0.45),
501
+ fade: 0.3,
502
+ sweep: 0.6,
503
+ perChar: 0.028,
504
+ perWord: 0.075,
505
+ typeMax: 1.7,
506
+ gap: 0.06
507
+ };
508
+ var RESTORED_PROPS = ["visibility", "opacity", "clip-path", "-webkit-clip-path"];
509
+ var MOVE_EASE = "power2.inOut";
510
+ var LATE = { immediateRender: false };
511
+ function build(root, o) {
512
+ injectStyles();
513
+ const saved = /* @__PURE__ */ new Map();
514
+ const remember = (el) => {
515
+ if (saved.has(el)) return;
516
+ const props = {};
517
+ for (const p of RESTORED_PROPS) props[p] = [el.style.getPropertyValue(p), el.style.getPropertyPriority(p)];
518
+ saved.set(el, { hadStyle: el.hasAttribute("style"), props });
519
+ };
520
+ const layer = createLayer(o.zIndex, o.labels, o.actions);
521
+ const origin = layer.getBoundingClientRect();
522
+ const tasks = collectTasks(root, origin, o.maxTasks);
523
+ const finalOpacity = tasks.map((t) => parseFloat(getComputedStyle(t.el).opacity) || 1);
524
+ remember(root);
525
+ root.style.visibility = "hidden";
526
+ root.removeAttribute("data-assemble-pending");
527
+ const splits = tasks.map((t) => {
528
+ remember(t.el);
529
+ t.el.style.visibility = "hidden";
530
+ return t.kind === "text" ? splitText(t.el, o.typing) : null;
531
+ });
532
+ const agents = resolveAgents(o.agents).map((cfg) => createAgent(layer, cfg));
533
+ const r = root.getBoundingClientRect();
534
+ const top = clamp(r.top, 0, innerHeight);
535
+ const bottom = clamp(r.bottom, 0, innerHeight);
536
+ const left = clamp(r.left, 0, innerWidth);
537
+ const right = clamp(r.right, 0, innerWidth);
538
+ const spawn = { x: (left + right) / 2 - origin.left, y: top + Math.min(120, (bottom - top) * 0.25) - origin.top };
539
+ let resolveFinished;
540
+ const finished = new Promise((res) => resolveFinished = res);
541
+ let tornDown = false;
542
+ const teardown = () => {
543
+ if (tornDown) return;
544
+ tornDown = true;
545
+ tl.kill();
546
+ for (const s of splits) s?.restore();
547
+ saved.forEach((entry, el) => {
548
+ for (const p of RESTORED_PROPS) {
549
+ const [value, priority] = entry.props[p];
550
+ if (value) el.style.setProperty(p, value, priority);
551
+ else el.style.removeProperty(p);
552
+ }
553
+ if (!entry.hadStyle && !el.getAttribute("style")) el.removeAttribute("style");
554
+ });
555
+ layer.remove();
556
+ resolveFinished();
557
+ };
558
+ const tl = new Timeline({
559
+ paused: true,
560
+ onStart: () => o.onStart?.(),
561
+ onUpdate: () => o.onProgress?.(tl.progress()),
562
+ onComplete: () => {
563
+ if (o.cleanup) teardown();
564
+ else resolveFinished();
565
+ o.onComplete?.();
566
+ }
567
+ });
568
+ const state = agents.map((a, n) => {
569
+ const offset = (n - (agents.length - 1) / 2) * 34;
570
+ const pos = { x: spawn.x + offset, y: spawn.y + n % 2 * 18 };
571
+ tl.fromTo(a.el, { x: pos.x, y: pos.y, scale: 0, autoAlpha: 0 }, { scale: 1, autoAlpha: 1, duration: 0.42, ease: "back.out(2)" }, n * 0.07);
572
+ return { pos, free: 0.45 + n * 0.07, last: 0 };
573
+ });
574
+ const say = (i, text, at) => tl.set(agents[i].tag, { attr: { "data-action": text } }, at);
575
+ const cursor = (i, mode, at) => tl.set(agents[i].el, { attr: { "data-mode": mode } }, at);
576
+ const move = (i, to, at, dur) => {
577
+ const from = state[i].pos;
578
+ tl.fromTo(agents[i].el, { x: from.x, y: from.y }, { x: to.x, y: to.y, duration: dur, ease: MOVE_EASE, ...LATE }, at);
579
+ state[i].pos = { ...to };
580
+ };
581
+ const drag = (i, task, kind, at, dur, showSize) => {
582
+ const { box, size } = createDrawBox(layer, kind, agents[i].config.color, showSize);
583
+ const { x, y, w, h } = task.rect;
584
+ set(box, { x, y });
585
+ tl.set(box, { autoAlpha: 1 }, at);
586
+ const vars = { width: w, height: h, duration: dur, ease: MOVE_EASE, ...LATE };
587
+ if (size) {
588
+ vars.onUpdate = () => {
589
+ size.textContent = `${Math.round(parseFloat(box.style.width) || 0)} \xD7 ${Math.round(parseFloat(box.style.height) || 0)}`;
590
+ };
591
+ }
592
+ tl.fromTo(box, { width: 0, height: 0 }, vars, at);
593
+ move(i, { x: x + w, y: y + h }, at, dur);
594
+ return box;
595
+ };
596
+ const fadeIn = (task, at) => {
597
+ tl.set(task.el, { visibility: "visible" }, at);
598
+ tl.fromTo(task.el, { opacity: 0 }, { opacity: finalOpacity[task.id], duration: TIMING.fade, ease: "power1.out", ...LATE }, at);
599
+ };
600
+ const perform = (i, task, at) => {
601
+ let t = at;
602
+ if (task.kind === "media" || task.kind === "block") {
603
+ say(i, `placing ${task.label}`, t);
604
+ cursor(i, "cross", t);
605
+ const dur = TIMING.draw(task.area);
606
+ const box = drag(i, task, task.kind, t, dur, true);
607
+ t += dur;
608
+ tl.set(task.el, { visibility: "visible" }, t);
609
+ tl.fromTo(task.el, { clipPath: "inset(0% 0% 100% 0%)" }, { clipPath: "inset(0% 0% 0% 0%)", duration: TIMING.sweep, ease: "power2.out", ...LATE }, t);
610
+ tl.to(box, { autoAlpha: 0, duration: TIMING.sweep, ...LATE }, t);
611
+ cursor(i, "arrow", t);
612
+ return t + TIMING.sweep * 0.6;
613
+ }
614
+ let frame = null;
615
+ if (task.hasBox) {
616
+ say(i, `drawing ${task.kind === "text" ? task.el.tagName.toLowerCase() : task.label}`, t);
617
+ cursor(i, "cross", t);
618
+ const dur = TIMING.draw(task.area);
619
+ frame = drag(i, task, "box", t, dur, true);
620
+ t += dur;
621
+ fadeIn(task, t);
622
+ tl.to(frame, { autoAlpha: 0, duration: TIMING.fade, ...LATE }, t);
623
+ cursor(i, "arrow", t);
624
+ if (task.kind === "box") return t + TIMING.fade * 0.5;
625
+ t += TIMING.fade * 0.6;
626
+ }
627
+ const chunks = splits[task.id].chunks;
628
+ if (!frame) {
629
+ say(i, "text box", t);
630
+ cursor(i, "cross", t);
631
+ const dur = TIMING.frame(task.area);
632
+ frame = drag(i, task, "text", t, dur, false);
633
+ t += dur;
634
+ tl.set(task.el, { visibility: "visible" }, t);
635
+ }
636
+ if (!chunks.length) return t;
637
+ const ends = chunks.map((c) => {
638
+ const b = c.getBoundingClientRect();
639
+ return { x: b.right - origin.left, y: b.top - origin.top, h: b.height };
640
+ });
641
+ const f = chunks[0].getBoundingClientRect();
642
+ const start = { x: f.left - origin.left, y: f.top - origin.top, h: f.height };
643
+ const handle = (p) => ({ x: p.x + 9, y: p.y + p.h * 0.55 });
644
+ const wordy = chunks.some((c) => /\S\s*\S/.test(c.textContent || ""));
645
+ const typeDur = clamp(chunks.length * (wordy ? TIMING.perWord : TIMING.perChar), 0.2, TIMING.typeMax);
646
+ const reach = 0.22;
647
+ move(i, handle(start), t, reach);
648
+ cursor(i, "beam", t + reach * 0.5);
649
+ t += reach;
650
+ say(i, `typing ${task.label}`, t);
651
+ const caret = agents[i].caret;
652
+ tl.set(caret, { x: start.x, y: start.y, height: start.h, autoAlpha: 1 }, t);
653
+ const counter = { n: 0 };
654
+ let shown = 0;
655
+ const total = chunks.length;
656
+ tl.fromTo(
657
+ counter,
658
+ { n: 0 },
659
+ {
660
+ n: total,
661
+ duration: typeDur,
662
+ ease: "none",
663
+ ...LATE,
664
+ onUpdate: () => {
665
+ const k = Math.min(total, Math.round(counter.n));
666
+ if (k > shown) for (let j = shown; j < k; j++) chunks[j].style.visibility = "";
667
+ else for (let j = k; j < shown; j++) chunks[j].style.visibility = "hidden";
668
+ shown = k;
669
+ const p = k === 0 ? start : ends[k - 1];
670
+ set(caret, { x: p.x, y: p.y, height: p.h });
671
+ set(agents[i].el, handle(p));
672
+ }
673
+ },
674
+ t
675
+ );
676
+ t += typeDur;
677
+ state[i].pos = handle(ends[total - 1]);
678
+ tl.set(caret, { autoAlpha: 0 }, t + 0.12);
679
+ tl.to(frame, { autoAlpha: 0, duration: 0.25, ...LATE }, t);
680
+ cursor(i, "arrow", t + 0.12);
681
+ return t + 0.08;
682
+ };
683
+ const queue = tasks.slice().sort((a, b) => Math.round(a.rect.y / 24) - Math.round(b.rect.y / 24) || a.rect.x - b.rect.x || a.id - b.id);
684
+ const doneAt = new Array(tasks.length).fill(-1);
685
+ while (queue.length) {
686
+ let i = 0;
687
+ for (let k = 1; k < state.length; k++) if (state[k].free < state[i].free) i = k;
688
+ const st = state[i];
689
+ let best = -1;
690
+ let bestScore = Infinity;
691
+ let bestStart = 0;
692
+ let bestTravel = 0;
693
+ let considered = 0;
694
+ for (let j = 0; j < queue.length && considered < 10; j++) {
695
+ const task2 = queue[j];
696
+ if (task2.parent !== -1 && doneAt[task2.parent] < 0) continue;
697
+ const travel = TIMING.travel(distance(st.pos, task2.rect));
698
+ const start = Math.max(st.free + travel, task2.parent === -1 ? 0 : doneAt[task2.parent] + 0.05);
699
+ const score = start + considered * 0.04;
700
+ if (score < bestScore) {
701
+ bestScore = score;
702
+ best = j;
703
+ bestStart = start;
704
+ bestTravel = travel;
705
+ }
706
+ considered++;
707
+ }
708
+ if (best < 0) {
709
+ best = 0;
710
+ bestTravel = TIMING.travel(distance(st.pos, queue[0].rect));
711
+ bestStart = st.free + bestTravel;
712
+ }
713
+ const task = queue.splice(best, 1)[0];
714
+ say(i, `\u2192 ${task.label}`, bestStart - bestTravel);
715
+ move(i, { x: task.rect.x, y: task.rect.y }, bestStart - bestTravel, bestTravel);
716
+ doneAt[task.id] = perform(i, task, bestStart);
717
+ st.free = doneAt[task.id] + TIMING.gap;
718
+ st.last = doneAt[task.id];
719
+ }
720
+ const end = Math.max(0.5, ...doneAt);
721
+ agents.forEach((a, n) => {
722
+ say(n, "done \u2713", state[n].last + 0.05);
723
+ cursor(n, "arrow", state[n].last + 0.05);
724
+ tl.to(a.el, { autoAlpha: 0, scale: 0.6, y: "-=14", duration: 0.35, ease: "power2.in", ...LATE }, end + 0.35 + n * 0.05);
725
+ });
726
+ if (o.duration && o.duration > 0) tl.timeScale(tl.duration() / o.duration);
727
+ else tl.timeScale(o.speed || 1);
728
+ return { tl, finished, teardown };
729
+ }
730
+ var noop = () => {
731
+ };
732
+ function assemble(target, options = {}) {
733
+ const root = typeof target === "string" ? document.querySelector(target) : target;
734
+ if (!root) throw new Error(`cursorcrew: target not found (${String(target)})`);
735
+ const o = {
736
+ agents: 5,
737
+ speed: 1,
738
+ typing: "auto",
739
+ maxTasks: 250,
740
+ cleanup: true,
741
+ zIndex: 2147483e3,
742
+ labels: true,
743
+ actions: true,
744
+ autoplay: true,
745
+ trigger: "immediate",
746
+ reducedMotion: "respect",
747
+ ...options
748
+ };
749
+ if (o.reducedMotion === "respect" && typeof matchMedia !== "undefined" && matchMedia("(prefers-reduced-motion: reduce)").matches) {
750
+ root.removeAttribute("data-assemble-pending");
751
+ if (o.onComplete) queueMicrotask(o.onComplete);
752
+ return {
753
+ timeline: new Timeline({ paused: true }),
754
+ finished: Promise.resolve(),
755
+ play: noop,
756
+ pause: noop,
757
+ finish: noop,
758
+ replay: noop,
759
+ destroy: noop
760
+ };
761
+ }
762
+ let current = build(root, o);
763
+ let observer = null;
764
+ const stopWatching = () => {
765
+ observer?.disconnect();
766
+ observer = null;
767
+ };
768
+ if (o.autoplay) {
769
+ if (o.trigger === "viewport" && root !== document.body && typeof IntersectionObserver !== "undefined") {
770
+ observer = new IntersectionObserver(
771
+ (entries) => {
772
+ if (entries.some((e) => e.isIntersecting)) {
773
+ stopWatching();
774
+ current.tl.play();
775
+ }
776
+ },
777
+ { threshold: 0.15 }
778
+ );
779
+ observer.observe(root);
780
+ } else {
781
+ current.tl.play();
782
+ }
783
+ }
784
+ return {
785
+ get timeline() {
786
+ return current.tl;
787
+ },
788
+ get finished() {
789
+ return current.finished;
790
+ },
791
+ play: () => void current.tl.play(),
792
+ pause: () => void current.tl.pause(),
793
+ finish() {
794
+ stopWatching();
795
+ current.tl.progress(1);
796
+ },
797
+ replay() {
798
+ stopWatching();
799
+ current.teardown();
800
+ current = build(root, o);
801
+ current.tl.play();
802
+ },
803
+ destroy() {
804
+ stopWatching();
805
+ current.teardown();
806
+ }
807
+ };
808
+ }
809
+
810
+ export {
811
+ Timeline,
812
+ DEFAULT_AGENTS,
813
+ assemble
814
+ };
815
+ //# sourceMappingURL=chunk-HQWPI64P.js.map