@shopify/klint 0.0.97 → 0.2.0

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.
@@ -1,1140 +0,0 @@
1
- // src/plugins/Color.tsx
2
- var Color = class {
3
- constructor() {
4
- // context: KlintContexts;
5
- /**
6
- * Array of predefined colors in the Klint color palette
7
- */
8
- this.colors = [
9
- "#E84D37",
10
- // coral
11
- "#7F4C2F",
12
- // brown
13
- "#EDBC2F",
14
- // mustard
15
- "#BF3034",
16
- // crimson
17
- "#18599D",
18
- // navy
19
- "#45A7C6",
20
- // sky
21
- "#8CB151",
22
- // olive
23
- "#252120",
24
- // charcoal
25
- "#ECA088",
26
- // peach
27
- "#C9B1B8",
28
- // rose
29
- "#8F3064",
30
- // plum
31
- "#7B8870",
32
- // sage
33
- "#C0C180",
34
- // drab
35
- "#4B423D",
36
- // taupe
37
- "#1A2A65",
38
- // midnight
39
- "#EAA550",
40
- // golden
41
- "#F17B04",
42
- // orange
43
- "#404757"
44
- // slate
45
- ];
46
- }
47
- // /**
48
- // * Creates a new Color instance
49
- // * @param ctx - The Klint context
50
- // */
51
- // constructor(ctx: KlintContexts) {
52
- // this.context = ctx;
53
- // }
54
- get coral() {
55
- return this.colors[0];
56
- }
57
- get brown() {
58
- return this.colors[1];
59
- }
60
- get mustard() {
61
- return this.colors[2];
62
- }
63
- get crimson() {
64
- return this.colors[3];
65
- }
66
- get navy() {
67
- return this.colors[4];
68
- }
69
- get sky() {
70
- return this.colors[5];
71
- }
72
- get olive() {
73
- return this.colors[6];
74
- }
75
- get charcoal() {
76
- return this.colors[7];
77
- }
78
- get peach() {
79
- return this.colors[8];
80
- }
81
- get rose() {
82
- return this.colors[9];
83
- }
84
- get plum() {
85
- return this.colors[10];
86
- }
87
- get sage() {
88
- return this.colors[11];
89
- }
90
- get drab() {
91
- return this.colors[12];
92
- }
93
- get taupe() {
94
- return this.colors[13];
95
- }
96
- get midnight() {
97
- return this.colors[14];
98
- }
99
- get golden() {
100
- return this.colors[15];
101
- }
102
- get orange() {
103
- return this.colors[16];
104
- }
105
- get slate() {
106
- return this.colors[17];
107
- }
108
- /**
109
- * Ensures a color string has a # prefix
110
- * @param color - Color string in hex format (with or without #)
111
- * @returns Hex color string with # prefix
112
- */
113
- hex(color) {
114
- return color.startsWith("#") ? color : `#${color}`;
115
- }
116
- /**
117
- * Creates an RGB color string
118
- * @param r - Red component (0-255)
119
- * @param g - Green component (0-255)
120
- * @param b - Blue component (0-255)
121
- * @returns RGB color string
122
- */
123
- rgb(r, g, b) {
124
- return `rgb(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)})`;
125
- }
126
- /**
127
- * Creates an RGBA color string
128
- * @param r - Red component (0-255)
129
- * @param g - Green component (0-255)
130
- * @param b - Blue component (0-255)
131
- * @param alpha - Alpha/opacity value (0-1)
132
- * @returns RGBA color string
133
- */
134
- rgba(r, g, b, alpha) {
135
- return `rgba(${Math.round(r)}, ${Math.round(g)}, ${Math.round(
136
- b
137
- )}, ${alpha})`;
138
- }
139
- /**
140
- * Creates a grayscale color
141
- * @param value - Gray value (0-255)
142
- * @param alpha - Optional alpha/opacity value (0-1)
143
- * @returns RGB or RGBA grayscale color string
144
- */
145
- gray(value, alpha) {
146
- return alpha !== void 0 ? `rgba(${Math.round(value)}, ${Math.round(value)}, ${Math.round(
147
- value
148
- )}, ${alpha})` : `rgb(${Math.round(value)}, ${Math.round(value)}, ${Math.round(value)})`;
149
- }
150
- /**
151
- * Creates an HSL color string
152
- * @param h - Hue (0-360)
153
- * @param s - Saturation percentage (0-100)
154
- * @param l - Lightness percentage (0-100)
155
- * @returns HSL color string
156
- */
157
- hsl(h, s, l) {
158
- return `hsl(${h % 360}, ${Math.max(0, s)}%, ${Math.max(0, l)}%)`;
159
- }
160
- /**
161
- * Creates an HSLA color string
162
- * @param h - Hue (0-360)
163
- * @param s - Saturation percentage (0-100)
164
- * @param l - Lightness percentage (0-100)
165
- * @param alpha - Alpha/opacity value (0-1)
166
- * @returns HSLA color string
167
- */
168
- hsla(h, s, l, alpha) {
169
- return `hsla(${h % 360}, ${Math.max(0, s)}%, ${Math.max(0, l)}%, ${alpha})`;
170
- }
171
- /**
172
- * Creates an LCH color string
173
- * @param l - Lightness percentage (0-100)
174
- * @param c - Chroma value
175
- * @param h - Hue (0-360)
176
- * @returns LCH color string
177
- */
178
- lch(l, c, h) {
179
- return `lch(${l}% ${c} ${h})`;
180
- }
181
- /**
182
- * Creates an LCH color string with alpha
183
- * @param l - Lightness percentage (0-100)
184
- * @param c - Chroma value
185
- * @param h - Hue (0-360)
186
- * @param alpha - Alpha/opacity value (0-1)
187
- * @returns LCH color string with alpha
188
- */
189
- lcha(l, c, h, alpha) {
190
- return `lch(${l}% ${c} ${h} / ${alpha})`;
191
- }
192
- /**
193
- * Creates a LAB color string
194
- * @param l - Lightness percentage (0-100)
195
- * @param a - A-axis value (green to red)
196
- * @param b - B-axis value (blue to yellow)
197
- * @returns LAB color string
198
- */
199
- lab(l, a, b) {
200
- return `lab(${l}% ${a} ${b})`;
201
- }
202
- /**
203
- * Creates a LAB color string with alpha
204
- * @param l - Lightness percentage (0-100)
205
- * @param a - A-axis value (green to red)
206
- * @param b - B-axis value (blue to yellow)
207
- * @param alpha - Alpha/opacity value (0-1)
208
- * @returns LAB color string with alpha
209
- */
210
- laba(l, a, b, alpha) {
211
- return `lab(${l}% ${a} ${b} / ${alpha})`;
212
- }
213
- /**
214
- * Creates an OKLCH color string
215
- * @param l - Lightness value (0-1)
216
- * @param c - Chroma value
217
- * @param h - Hue (0-360)
218
- * @returns OKLCH color string
219
- */
220
- oklch(l, c, h) {
221
- return `oklch(${l} ${c} ${h})`;
222
- }
223
- /**
224
- * Creates an OKLCH color string with alpha
225
- * @param l - Lightness value (0-1)
226
- * @param c - Chroma value
227
- * @param h - Hue (0-360)
228
- * @param alpha - Alpha/opacity value (0-1)
229
- * @returns OKLCH color string with alpha
230
- */
231
- oklcha(l, c, h, alpha) {
232
- return `oklch(${l} ${c} ${h} / ${alpha})`;
233
- }
234
- /**
235
- * Creates an OKLAB color string
236
- * @param l - Lightness value (0-1)
237
- * @param a - A-axis value (green to red)
238
- * @param b - B-axis value (blue to yellow)
239
- * @returns OKLAB color string
240
- */
241
- oklab(l, a, b) {
242
- return `oklab(${l} ${a} ${b})`;
243
- }
244
- /**
245
- * Creates an OKLAB color string with alpha
246
- * @param l - Lightness value (0-1)
247
- * @param a - A-axis value (green to red)
248
- * @param b - B-axis value (blue to yellow)
249
- * @param alpha - Alpha/opacity value (0-1)
250
- * @returns OKLAB color string with alpha
251
- */
252
- oklaba(l, a, b, alpha) {
253
- return `oklab(${l} ${a} ${b} / ${alpha})`;
254
- }
255
- /**
256
- * Blends two colors using CSS color-mix
257
- * @param colorA - First color
258
- * @param colorB - Second color
259
- * @param factor - Blend factor (0-1) where 0 is colorA and 1 is colorB
260
- * @param colorMode - Color space to blend in (e.g., "oklch", "hsl")
261
- * @returns Blended color string
262
- */
263
- blendColors(colorA, colorB, factor, colorMode = "oklch") {
264
- const t = Math.max(0, Math.min(1, factor)) * 100;
265
- return `color-mix(in ${colorMode}, ${colorA}, ${colorB} ${t}%)`;
266
- }
267
- /**
268
- * Creates a palette of colors based on a single base color
269
- * @param baseColor - The base color to create palette from
270
- * @param steps - Number of steps in each direction (lighter/darker)
271
- * @returns Array of color strings forming a palette
272
- */
273
- createPalette(baseColor, steps = 9) {
274
- const palette = [];
275
- for (let i = 1; i < steps; i++) {
276
- const factor = i / steps;
277
- palette.unshift(this.blendColors(baseColor, "#ffffff", factor, "oklch"));
278
- }
279
- palette.push(baseColor);
280
- for (let i = 1; i < steps; i++) {
281
- const factor = i / steps;
282
- palette.push(this.blendColors(baseColor, "#000000", factor, "oklch"));
283
- }
284
- return palette;
285
- }
286
- /**
287
- * Creates a complementary color (opposite on the color wheel)
288
- * @param color - Base color
289
- * @returns Complementary color string
290
- */
291
- complementary(color) {
292
- return this.blendColors(color, "hsl(180deg 100% 50%)", 1, "hsl");
293
- }
294
- /**
295
- * Creates analogous colors (adjacent on the color wheel)
296
- * @param color - Base color
297
- * @param angle - Angle of separation in degrees
298
- * @returns Tuple of two analogous color strings
299
- */
300
- analogous(color, angle = 30) {
301
- return [
302
- this.blendColors(color, `hsl(${-angle}deg 100% 50%)`, 1, "hsl"),
303
- this.blendColors(color, `hsl(${angle}deg 100% 50%)`, 1, "hsl")
304
- ];
305
- }
306
- /**
307
- * Creates a triadic color scheme (three colors evenly spaced on the color wheel)
308
- * @param color - Base color
309
- * @returns Tuple of two additional colors to form a triadic scheme
310
- */
311
- triadic(color) {
312
- return [
313
- this.blendColors(color, "hsl(120deg 100% 50%)", 1, "hsl"),
314
- this.blendColors(color, "hsl(240deg 100% 50%)", 1, "hsl")
315
- ];
316
- }
317
- /**
318
- * Increases the saturation of a color
319
- * @param color - Base color
320
- * @param amount - Amount to saturate (percentage)
321
- * @returns Saturated color string
322
- */
323
- saturate(color, amount) {
324
- return this.blendColors(
325
- color,
326
- "hsl(0deg 100% 50% / 0%)",
327
- amount / 100,
328
- "hsl"
329
- );
330
- }
331
- /**
332
- * Lightens a color by mixing with white
333
- * @param color - Base color
334
- * @param amount - Amount to lighten (percentage)
335
- * @returns Lightened color string
336
- */
337
- lighten(color, amount) {
338
- return this.blendColors(color, "white", amount / 100, "hsl");
339
- }
340
- /**
341
- * Darkens a color by mixing with black
342
- * @param color - Base color
343
- * @param amount - Amount to darken (percentage)
344
- * @returns Darkened color string
345
- */
346
- darken(color, amount) {
347
- return this.blendColors(color, "black", amount / 100, "hsl");
348
- }
349
- };
350
- var Color_default = Color;
351
-
352
- // src/plugins/Easing.tsx
353
- var Easing = class {
354
- constructor(ctx) {
355
- this.normalize = (val) => {
356
- return val * 0.5 + 0.5;
357
- };
358
- this.expand = (val) => {
359
- return val * 2 - 1;
360
- };
361
- this.inout = (val, power = 2) => {
362
- const m = val - 1;
363
- const t = val * 2;
364
- if (t < 1) {
365
- return val * Math.pow(t, power - 1);
366
- }
367
- return power % 2 === 0 ? 1 - Math.pow(m, power) * Math.pow(2, power - 1) : 1 + Math.pow(m, power) * Math.pow(2, power - 1);
368
- };
369
- this.in = (val, power = 2) => {
370
- return Math.pow(val, power);
371
- };
372
- this.out = (val, power = 2) => {
373
- const m = val - 1;
374
- return power % 2 === 0 ? 1 - Math.pow(m, power) : 1 + Math.pow(m, power);
375
- };
376
- this.overshootIn = (val) => {
377
- const k = 1.70158;
378
- return val * val * (val * (k + 1) - k);
379
- };
380
- this.overshootOut = (val) => {
381
- const m = val - 1;
382
- const k = 1.70158;
383
- return 1 + m * m * (m * (k + 1) + k);
384
- };
385
- this.overshootInOut = (val) => {
386
- const m = val - 1;
387
- const t = val * 2;
388
- const k = 1.70158 * 1.525;
389
- if (val < 0.5) return val * t * (t * (k + 1) - k);
390
- return 1 + 2 * m * m * (2 * m * (k + 1) + k);
391
- };
392
- this.bounceOut = (val) => {
393
- const r = 1 / 2.75;
394
- const k1 = r;
395
- const k2 = 2 * r;
396
- const k3 = 1.5 * r;
397
- const k4 = 2.5 * r;
398
- const k5 = 2.25 * r;
399
- const k6 = 2.625 * r;
400
- const k0 = 7.5625;
401
- let t;
402
- if (val < k1) {
403
- return k0 * val * val;
404
- } else if (val < k2) {
405
- t = val - k3;
406
- return k0 * t * t + 0.75;
407
- } else if (val < k4) {
408
- t = val - k5;
409
- return k0 * t * t + 0.9375;
410
- }
411
- t = val - k6;
412
- return k0 * t * t + 0.984375;
413
- };
414
- this.bounceIn = (val) => {
415
- return 1 - this.bounceOut(1 - val);
416
- };
417
- this.bounceInOut = (val) => {
418
- const t = val * 2;
419
- if (t < 1) return 0.5 - 0.5 * this.bounceOut(1 - t);
420
- return 0.5 + 0.5 * this.bounceOut(t - 1);
421
- };
422
- this.elasticIn = (val) => {
423
- const m = val - 1;
424
- return -Math.pow(2, 10 * m) * Math.sin((m * 40 - 3) * Math.PI / 6);
425
- };
426
- this.elasticOut = (val) => {
427
- return 1 + Math.pow(2, 10 * -val) * Math.sin((-val * 40 - 3) * Math.PI / 6);
428
- };
429
- this.elasticInOut = (val) => {
430
- const s = 2 * val - 1;
431
- const k = (80 * s - 9) * Math.PI / 18;
432
- if (s < 0) return -0.5 * Math.pow(2, 10 * s) * Math.sin(k);
433
- return 1 + 0.5 * Math.pow(2, -10 * s) * Math.sin(k);
434
- };
435
- this.smoothstep = (val, x0 = 0, x1 = 1) => {
436
- let p = (val - x0) / (x1 - x0);
437
- p = p < 0 ? 0 : p > 1 ? 1 : p;
438
- return p * p * (3 - 2 * p);
439
- };
440
- this.log = () => {
441
- console.log(this);
442
- };
443
- this.context = ctx;
444
- }
445
- };
446
- var Easing_default = Easing;
447
-
448
- // src/plugins/SVGfont.tsx
449
- var SVGfont = class {
450
- constructor(context) {
451
- this.context = context;
452
- this.font = "";
453
- this.SCALE = 1;
454
- this.targetXHeight = 256;
455
- this.metrics = {
456
- fontFamily: "",
457
- fontWeight: "",
458
- unitsPerEm: 0,
459
- ascent: 0,
460
- descent: 0,
461
- xHeight: 0,
462
- capHeight: 0
463
- };
464
- this.glyphs = /* @__PURE__ */ new Map();
465
- this.context = context;
466
- }
467
- parse(font, desiredXHeight = 256) {
468
- const parser = new DOMParser();
469
- const doc = parser.parseFromString(font, "text/xml");
470
- const fontFace = doc.querySelector("font-face");
471
- if (fontFace) {
472
- this.metrics.fontFamily = fontFace.getAttribute("font-family") || "";
473
- this.metrics.fontWeight = fontFace.getAttribute("font-weight") || "";
474
- this.metrics.unitsPerEm = parseInt(
475
- fontFace.getAttribute("units-per-em") || "0"
476
- );
477
- this.metrics.ascent = parseInt(fontFace.getAttribute("ascent") || "0");
478
- this.metrics.descent = parseInt(fontFace.getAttribute("descent") || "0");
479
- this.metrics.xHeight = parseInt(fontFace.getAttribute("x-height") || "0");
480
- this.metrics.capHeight = parseInt(
481
- fontFace.getAttribute("cap-height") || "0"
482
- );
483
- }
484
- this.targetXHeight = desiredXHeight;
485
- this.SCALE = this.targetXHeight / this.metrics.xHeight;
486
- const glyphElements = doc.querySelectorAll("glyph");
487
- const basicCharRegex = /^[\w]$/;
488
- const commonGlyphNames = /* @__PURE__ */ new Set([
489
- "space",
490
- "period",
491
- "comma",
492
- "hyphen",
493
- "exclam",
494
- "question",
495
- "slash",
496
- "less",
497
- "greater",
498
- "parenleft",
499
- "parenright",
500
- "braceleft",
501
- "braceright",
502
- "bracketleft",
503
- "bracketright"
504
- ]);
505
- glyphElements.forEach((glyph) => {
506
- const character = glyph.getAttribute("glyph-name");
507
- const unicode = glyph.getAttribute("unicode");
508
- if (!character || !unicode || !basicCharRegex.test(character) && !commonGlyphNames.has(character) && character.length > 1)
509
- return;
510
- const horizAdvX = parseInt(glyph.getAttribute("horiz-adv-x") || "0");
511
- let pathData = glyph.getAttribute("d");
512
- if (pathData) {
513
- pathData = pathData.replace(
514
- /[-+]?\d*\.?\d+/g,
515
- (match) => (parseFloat(match) * this.SCALE).toString()
516
- );
517
- }
518
- const glyphData = {
519
- name: character,
520
- unicode,
521
- horizAdvX: horizAdvX * this.SCALE,
522
- d: pathData || void 0
523
- };
524
- this.glyphs.set(unicode, glyphData);
525
- });
526
- if (!this.glyphs.has(" ")) {
527
- this.glyphs.set(" ", {
528
- name: "space",
529
- unicode: " ",
530
- horizAdvX: this.metrics.unitsPerEm * this.SCALE * 0.25,
531
- // typical space width
532
- d: void 0
533
- });
534
- }
535
- }
536
- toJSON() {
537
- return {
538
- metrics: this.metrics,
539
- glyphs: Array.from(this.glyphs.entries()).reduce((obj, [key, value]) => {
540
- obj[key] = value;
541
- return obj;
542
- }, {})
543
- };
544
- }
545
- getPoints(text, options) {
546
- const {
547
- factor,
548
- align = "left",
549
- center = "alphabetic",
550
- letterSpacing = 0
551
- } = options;
552
- const points = [];
553
- const svgns = "http://www.w3.org/2000/svg";
554
- const svg = document.createElementNS(svgns, "svg");
555
- const path = document.createElementNS(svgns, "path");
556
- svg.appendChild(path);
557
- let totalWidth = 0;
558
- const chars = text.split("");
559
- chars.forEach((char, i) => {
560
- const glyph = this.glyphs.get(char);
561
- if (glyph) {
562
- totalWidth += glyph.horizAdvX;
563
- if (i < chars.length - 1) totalWidth += letterSpacing;
564
- }
565
- });
566
- let currentX = 0;
567
- if (align === "center") {
568
- currentX = -totalWidth / 2;
569
- } else if (align === "right") {
570
- currentX = -totalWidth;
571
- }
572
- console.log(this.SCALE);
573
- let yOffset = 0;
574
- switch (center) {
575
- case "middle":
576
- yOffset = -((this.metrics.ascent - this.metrics.descent) / 2) * this.SCALE * 0.5;
577
- break;
578
- case "top":
579
- yOffset = this.metrics.ascent * this.SCALE;
580
- break;
581
- case "alphabetic":
582
- default:
583
- yOffset = 0;
584
- break;
585
- }
586
- for (const char of chars) {
587
- const glyph = this.glyphs.get(char);
588
- if (!glyph) continue;
589
- if (!glyph.d) {
590
- currentX += glyph.horizAdvX + letterSpacing;
591
- continue;
592
- }
593
- path.setAttribute("d", glyph.d);
594
- const subpaths = glyph.d.split(/(?=[Mm])/);
595
- const glyphContours = [];
596
- for (const subpath of subpaths) {
597
- if (!subpath.trim()) continue;
598
- path.setAttribute("d", subpath);
599
- const pathLength = path.getTotalLength();
600
- const numPoints = Math.max(10, Math.floor(pathLength * factor));
601
- const contourPoints = [];
602
- const step = pathLength / (numPoints - 1);
603
- for (let i = 0; i < numPoints; i++) {
604
- const point = path.getPointAtLength(i * step);
605
- contourPoints.push({
606
- x: point.x + currentX,
607
- y: -(point.y + yOffset)
608
- // Apply vertical offset
609
- });
610
- }
611
- if (subpath.toLowerCase().includes("z")) {
612
- contourPoints.push({ ...contourPoints[0] });
613
- }
614
- glyphContours.push(contourPoints);
615
- }
616
- glyphContours.sort((a, b) => b.length - a.length);
617
- for (let i = 1; i < glyphContours.length; i++) {
618
- glyphContours[i].reverse();
619
- }
620
- points.push(glyphContours);
621
- currentX += glyph.horizAdvX + letterSpacing;
622
- }
623
- svg.remove();
624
- return points;
625
- }
626
- flatten(points, displacement) {
627
- return points.flatMap(
628
- (glyph) => glyph.flatMap(
629
- (contour, contourIndex) => contour.map((point) => {
630
- if (displacement) {
631
- return displacement({
632
- point,
633
- position: point,
634
- groupIndex: contourIndex,
635
- letterSpacing: 0
636
- });
637
- }
638
- return point;
639
- })
640
- )
641
- );
642
- }
643
- draw(points, displacement) {
644
- for (const glyph of points) {
645
- this.context.beginShape();
646
- glyph.forEach((contour, contourIndex) => {
647
- if (contourIndex !== 0) {
648
- this.context.beginContour();
649
- }
650
- contour.forEach((point) => {
651
- if (displacement) {
652
- const { x, y } = displacement({
653
- point,
654
- position: point,
655
- groupIndex: contourIndex,
656
- letterSpacing: 0
657
- // You can add letter spacing logic here
658
- });
659
- this.context.vertex(x, y);
660
- } else {
661
- this.context.vertex(point.x, point.y);
662
- }
663
- });
664
- if (contourIndex !== 0) {
665
- this.context.endContour();
666
- }
667
- });
668
- this.context.endShape(true);
669
- }
670
- }
671
- };
672
- var SVGfont_default = SVGfont;
673
-
674
- // src/plugins/State.tsx
675
- var State = class {
676
- constructor() {
677
- this.store = /* @__PURE__ */ new Map();
678
- }
679
- set(key, value, callback) {
680
- this.store.set(key, value);
681
- callback?.(key, value);
682
- }
683
- get(key, callback) {
684
- const value = this.store.get(key);
685
- callback?.(key, value);
686
- return value;
687
- }
688
- has(key) {
689
- return this.store.has(key);
690
- }
691
- delete(key, callback) {
692
- this.store.delete(key);
693
- callback?.(key);
694
- }
695
- log() {
696
- return this.store;
697
- }
698
- };
699
- var State_default = State;
700
-
701
- // src/plugins/Vector.tsx
702
- var Vector = class _Vector {
703
- /**
704
- * Creates a new Vector
705
- * @param x - X-coordinate (default: 0)
706
- * @param y - Y-coordinate (default: 0)
707
- */
708
- constructor(x = 0, y = 0) {
709
- this.x = x;
710
- this.y = y;
711
- }
712
- /**
713
- * Adds another vector to this vector
714
- * @param v - Vector to add
715
- * @returns This vector after addition
716
- */
717
- add(v) {
718
- this.x += v.x;
719
- this.y += v.y;
720
- return this;
721
- }
722
- /**
723
- * Subtracts another vector from this vector
724
- * @param v - Vector to subtract
725
- * @returns This vector after subtraction
726
- */
727
- sub(v) {
728
- this.x -= v.x;
729
- this.y -= v.y;
730
- return this;
731
- }
732
- /**
733
- * Multiplies this vector by a scalar
734
- * @param n - Scalar to multiply by
735
- * @returns This vector after multiplication
736
- */
737
- mult(n) {
738
- this.x *= n;
739
- this.y *= n;
740
- return this;
741
- }
742
- /**
743
- * Divides this vector by a scalar
744
- * @param n - Scalar to divide by
745
- * @returns This vector after division
746
- */
747
- div(n) {
748
- this.x /= n;
749
- this.y /= n;
750
- return this;
751
- }
752
- // to do : project, perp, slerp
753
- /**
754
- * Rotates this vector by an angle
755
- * @param angle - Angle in radians
756
- * @returns This vector after rotation
757
- */
758
- rotate(angle) {
759
- const cos = Math.cos(angle);
760
- const sin = Math.sin(angle);
761
- const x = this.x * cos - this.y * sin;
762
- const y = this.x * sin + this.y * cos;
763
- this.x = x;
764
- this.y = y;
765
- return this;
766
- }
767
- /**
768
- * Calculates the magnitude (length) of this vector
769
- * @returns The magnitude of the vector
770
- */
771
- mag() {
772
- return Math.sqrt(this.x * this.x + this.y * this.y);
773
- }
774
- /**
775
- * Alias for mag() - calculates the length of this vector
776
- * @returns The length of the vector
777
- */
778
- length() {
779
- return this.mag();
780
- }
781
- /**
782
- * Calculates the dot product of this vector with another vector
783
- * @param v - The other vector
784
- * @returns The dot product
785
- */
786
- dot(v) {
787
- return this.x * v.x + this.y * v.y;
788
- }
789
- /**
790
- * Calculates the distance between this vector and another vector
791
- * @param v - The other vector
792
- * @returns The distance between the vectors
793
- */
794
- dist(v) {
795
- return Math.hypot(this.x - v.x, this.y - v.y);
796
- }
797
- /**
798
- * Calculates the angle of this vector
799
- * @returns The angle in radians
800
- */
801
- angle() {
802
- return Math.atan2(-this.x, -this.y) + Math.PI;
803
- }
804
- /**
805
- * Creates a copy of this vector
806
- * @returns A new Vector with the same coordinates
807
- */
808
- copy() {
809
- return new _Vector(this.x, this.y);
810
- }
811
- /**
812
- * Normalizes this vector (sets its magnitude to 1)
813
- * @returns This vector after normalization
814
- */
815
- normalize() {
816
- const m = this.mag();
817
- return m !== 0 ? this.div(m) : this;
818
- }
819
- /**
820
- * Sets the coordinates of this vector
821
- * @param x - New X-coordinate
822
- * @param y - New Y-coordinate
823
- * @returns This vector after setting coordinates
824
- */
825
- set(x, y) {
826
- this.x = x;
827
- this.y = y;
828
- return this;
829
- }
830
- /**
831
- * Creates a new vector at a specified angle and distance from a center point
832
- * @param center - The center point vector
833
- * @param a - The angle in radians
834
- * @param r - The radius (distance from center)
835
- * @returns A new Vector at the calculated position
836
- */
837
- static fromAngle(center, a, r) {
838
- const x = Math.cos(a) * r + center.x;
839
- const y = Math.sin(a) * r + center.y;
840
- return new _Vector(x, y);
841
- }
842
- };
843
- var Vector_default = Vector;
844
-
845
- // src/plugins/Time.tsx
846
- var Time = class {
847
- constructor(ctx) {
848
- this.timelines = /* @__PURE__ */ new Map();
849
- this.currentTimeline = "default";
850
- this.DEFAULT_DURATION = 8 * 60;
851
- this.staggers = [];
852
- this.context = ctx;
853
- this.timelines.set("default", {
854
- progress: 0,
855
- duration: this.DEFAULT_DURATION
856
- });
857
- }
858
- timeline(key) {
859
- if (!this.timelines.has(key)) {
860
- this.timelines.set(key, { progress: 0, duration: this.DEFAULT_DURATION });
861
- }
862
- this.currentTimeline = key;
863
- return this;
864
- }
865
- use(progress) {
866
- const timeline = this.timelines.get(this.currentTimeline);
867
- if (timeline.duration <= 0) {
868
- timeline.progress = 0;
869
- return this;
870
- }
871
- timeline.progress = timeline.duration === 1 ? Math.min(progress, 1) : progress / timeline.duration % 1;
872
- return this;
873
- }
874
- for(duration) {
875
- const timeline = this.timelines.get(this.currentTimeline);
876
- timeline.duration = duration;
877
- return this;
878
- }
879
- stagger(num, offset = 0, callback) {
880
- const timeline = this.timelines.get(this.currentTimeline);
881
- const totalduration = this.context.remap(
882
- timeline.progress,
883
- 0,
884
- 1,
885
- 0,
886
- 1 + offset
887
- );
888
- for (let i = 0; i < num; i++) {
889
- const id = 1 - i / (num - 1);
890
- const progress = this.context.constrain(
891
- totalduration - id * offset,
892
- 0,
893
- 1
894
- );
895
- if (!callback) {
896
- if (this.staggers[i]) {
897
- this.staggers[i].progress = progress;
898
- } else {
899
- this.staggers[i] = { progress, id };
900
- }
901
- } else {
902
- callback?.(progress, id, num);
903
- }
904
- }
905
- return callback ? this : this.staggers;
906
- }
907
- between(from = 0, to = 1, callback) {
908
- const timeline = this.timelines.get(this.currentTimeline);
909
- const localProgress = this.context.remap(
910
- timeline.progress,
911
- Math.max(0, from),
912
- Math.min(1, to),
913
- 0,
914
- 1
915
- );
916
- callback(localProgress);
917
- return this;
918
- }
919
- progress() {
920
- return this.timelines.get(this.currentTimeline)?.progress || 0;
921
- }
922
- };
923
- var Time_default = Time;
924
-
925
- // src/plugins/Text.tsx
926
- var Text = class {
927
- constructor(ctx) {
928
- this.findTextSize = (text, dist, estimate, direction = "x") => {
929
- let low = 1;
930
- let high = estimate || this.context.__textSize * 2;
931
- let lastValidSize = low;
932
- for (let i = 0; i < 16; i++) {
933
- const mid = Math.floor((low + high) / 2);
934
- this.context.__textSize = mid;
935
- const bounds = this.textBounds(text);
936
- const size = direction === "x" ? bounds.width : bounds.height;
937
- if (size === dist) {
938
- return mid;
939
- } else if (size < dist) {
940
- lastValidSize = mid;
941
- low = mid + 1;
942
- } else {
943
- high = mid - 1;
944
- }
945
- }
946
- return lastValidSize;
947
- };
948
- this.getTextMetrics = (text) => {
949
- const ctx = this.context;
950
- const metrics = ctx.measureText(text);
951
- return {
952
- width: metrics.width,
953
- height: metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent,
954
- baseline: metrics.actualBoundingBoxAscent
955
- };
956
- };
957
- this.splitTo = (text, kind, options = {}) => {
958
- const ctx = this.context;
959
- const {
960
- maxWidth = 0,
961
- lineSpacing = 0,
962
- letterSpacing = 0,
963
- wordSpacing = 0
964
- } = options;
965
- ctx.computeFont();
966
- if (maxWidth < this.textBounds(" ").width * 2 && maxWidth !== 0) {
967
- return [];
968
- }
969
- const lines = text.split("\n");
970
- const lineHeights = lines.map((line) => this.getTextMetrics(line).height);
971
- const totalHeight = lineHeights.reduce((sum, height) => sum + height, 0) + (lines.length - 1) * (lineSpacing || 0);
972
- let y = ctx.textBaseline === "middle" ? -totalHeight / 2 : 0;
973
- return lines.flatMap((lineText, lineIndex) => {
974
- const words = lineText.split(" ");
975
- const currentLine = {
976
- text: "",
977
- width: 0,
978
- letters: []
979
- };
980
- const totalWidth = this.getTextMetrics(lineText).width;
981
- let startX = 0;
982
- switch (ctx.textAlign) {
983
- case "center":
984
- startX = -totalWidth / 2;
985
- break;
986
- case "right":
987
- startX = -totalWidth;
988
- break;
989
- }
990
- let x = startX;
991
- let letterIndex = 0;
992
- let wordIndex = 0;
993
- const lineLetters = words.flatMap((word) => {
994
- const letters = [];
995
- for (const char of word) {
996
- const charMetrics = this.getTextMetrics(char);
997
- x += charMetrics.width / 2;
998
- const letterData = {
999
- char,
1000
- x,
1001
- y: y + (ctx.textBaseline === "middle" ? lineHeights[lineIndex] / 2 : 0),
1002
- metrics: charMetrics,
1003
- ...kind === "all" && {
1004
- letterIndex,
1005
- wordIndex,
1006
- lineIndex
1007
- }
1008
- };
1009
- letters.push(letterData);
1010
- currentLine.text += char;
1011
- x += charMetrics.width / 2 + letterSpacing;
1012
- letterIndex++;
1013
- }
1014
- if (wordIndex < words.length - 1) {
1015
- const spaceMetrics = this.getTextMetrics(" ");
1016
- x += spaceMetrics.width + wordSpacing;
1017
- letters.push({
1018
- char: " ",
1019
- x,
1020
- y,
1021
- metrics: spaceMetrics,
1022
- ...kind === "all" && {
1023
- letterIndex,
1024
- wordIndex,
1025
- lineIndex
1026
- }
1027
- });
1028
- currentLine.text += " ";
1029
- letterIndex++;
1030
- }
1031
- wordIndex++;
1032
- return letters;
1033
- });
1034
- const lineHeight = lineHeights[lineIndex];
1035
- y += lineHeight + lineSpacing;
1036
- return lineLetters;
1037
- });
1038
- };
1039
- this.circularText = (text, radius = 100, fill = "fill", offset = 0, arc = Math.PI * 2) => {
1040
- const totalAngle = Math.min(Math.max(arc, 0), Math.PI * 2);
1041
- if (fill === "fill") {
1042
- const chars = text.split("");
1043
- const anglePerChar = totalAngle / (chars.length + 1);
1044
- chars.forEach((char, i) => {
1045
- const angle = anglePerChar * i + offset;
1046
- const x = Math.cos(angle) * radius;
1047
- const y = Math.sin(angle) * radius;
1048
- this.context.push();
1049
- this.context.textAlign = "center";
1050
- this.context.translate(x, y);
1051
- this.context.rotate(angle + Math.PI / 2);
1052
- this.context.text(char, 0, 0);
1053
- this.context.pop();
1054
- });
1055
- } else if (fill === "kerned") {
1056
- let currentAngle = offset;
1057
- text.split("").forEach((char) => {
1058
- const charWidth = this.textBounds(char).width;
1059
- currentAngle += charWidth / radius * 0.5;
1060
- const angle = currentAngle;
1061
- const x = Math.cos(angle) * radius;
1062
- const y = Math.sin(angle) * radius;
1063
- this.context.push();
1064
- this.context.textAlign = "center";
1065
- this.context.translate(x, y);
1066
- this.context.rotate(angle + Math.PI / 2);
1067
- this.context.text(char, 0, 0);
1068
- this.context.pop();
1069
- currentAngle += charWidth / radius * 0.5;
1070
- });
1071
- } else if (fill === "words") {
1072
- const words = text.split(" ");
1073
- const wordMetrics = words.map((word) => ({
1074
- word,
1075
- width: this.textBounds(word).width
1076
- }));
1077
- const spaceCount = words.length;
1078
- const totalWordWidth = wordMetrics.reduce((sum, m) => sum + m.width, 0);
1079
- const spaceAngle = (totalAngle - totalWordWidth / radius) / spaceCount;
1080
- let currentAngle = offset;
1081
- wordMetrics.forEach(({ word }, i) => {
1082
- word.split("").forEach((char) => {
1083
- const charWidth = this.textBounds(char).width;
1084
- currentAngle += charWidth / radius * 0.5;
1085
- const x = Math.cos(currentAngle) * radius;
1086
- const y = Math.sin(currentAngle) * radius;
1087
- this.context.push();
1088
- this.context.textAlign = "center";
1089
- this.context.translate(x, y);
1090
- this.context.rotate(currentAngle + Math.PI / 2);
1091
- this.context.text(char, 0, 0);
1092
- this.context.pop();
1093
- currentAngle += charWidth / radius * 0.5;
1094
- });
1095
- if (i < words.length - 1) {
1096
- currentAngle += spaceAngle;
1097
- }
1098
- });
1099
- }
1100
- };
1101
- this.textBounds = (text) => {
1102
- if (this.context.font !== this.context.__computedTextFont) {
1103
- this.context.font = this.context.__computedTextFont;
1104
- }
1105
- const metrics = this.context.measureText(text);
1106
- return {
1107
- x: metrics.actualBoundingBoxLeft * -1,
1108
- y: metrics.actualBoundingBoxAscent * -1,
1109
- width: metrics.width,
1110
- height: metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent
1111
- };
1112
- };
1113
- this.log = () => {
1114
- console.log(this.context);
1115
- };
1116
- this.context = ctx;
1117
- }
1118
- };
1119
- var Text_default = Text;
1120
-
1121
- // src/plugins/Thing.tsx
1122
- var Thing = class {
1123
- constructor(ctx) {
1124
- this.context = ctx;
1125
- }
1126
- log() {
1127
- console.log(this.context);
1128
- }
1129
- };
1130
- var Thing_default = Thing;
1131
- export {
1132
- Color_default as Color,
1133
- Easing_default as Easing,
1134
- SVGfont_default as SVGfont,
1135
- State_default as State,
1136
- Text_default as Text,
1137
- Thing_default as Thing,
1138
- Time_default as Time,
1139
- Vector_default as Vector
1140
- };