loopwind 0.20.2 → 0.21.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.
Files changed (34) hide show
  1. package/_dsgn/templates/dashed-stroke-test/template.tsx +73 -0
  2. package/_dsgn/templates/path-follow-test/template.tsx +176 -0
  3. package/_dsgn/templates/path-simple-test/template.tsx +98 -0
  4. package/_dsgn/templates/stroke-dash-test/meta.json +12 -0
  5. package/_dsgn/templates/stroke-dash-test/template.tsx +53 -0
  6. package/dist/lib/path-helpers.d.ts +71 -0
  7. package/dist/lib/path-helpers.d.ts.map +1 -0
  8. package/dist/lib/path-helpers.js +118 -0
  9. package/dist/lib/path-helpers.js.map +1 -0
  10. package/dist/lib/renderer.d.ts.map +1 -1
  11. package/dist/lib/renderer.js +59 -4
  12. package/dist/lib/renderer.js.map +1 -1
  13. package/dist/lib/tailwind.d.ts.map +1 -1
  14. package/dist/lib/tailwind.js +191 -6
  15. package/dist/lib/tailwind.js.map +1 -1
  16. package/dist/lib/template-validator.d.ts.map +1 -1
  17. package/dist/lib/template-validator.js +19 -5
  18. package/dist/lib/template-validator.js.map +1 -1
  19. package/dist/lib/text-helpers.d.ts +52 -0
  20. package/dist/lib/text-helpers.d.ts.map +1 -0
  21. package/dist/lib/text-helpers.js +74 -0
  22. package/dist/lib/text-helpers.js.map +1 -0
  23. package/dist/lib/utils.d.ts +0 -4
  24. package/dist/lib/utils.d.ts.map +1 -1
  25. package/dist/lib/utils.js +33 -0
  26. package/dist/lib/utils.js.map +1 -1
  27. package/dist/types/template.d.ts +121 -0
  28. package/dist/types/template.d.ts.map +1 -1
  29. package/package.json +1 -1
  30. package/website/.astro/content.db +0 -0
  31. package/website/.astro/integrations/astro_db/db.d.ts +15 -0
  32. package/website/astro.config.mjs +2 -1
  33. package/website/package-lock.json +1090 -122
  34. package/website/package.json +14 -0
@@ -0,0 +1,73 @@
1
+ export const meta = {
2
+ name: "dashed-stroke-test",
3
+ description: "Animated dashed stroke patterns",
4
+ type: "video",
5
+ size: {
6
+ width: 1920,
7
+ height: 1080
8
+ },
9
+ props: {},
10
+ video: {
11
+ duration: 4,
12
+ fps: 30
13
+ }
14
+ };
15
+
16
+ export default function DashedStrokeTest({ tw, progress, frame }) {
17
+ // Calculate animated dash offset for marching ants effect
18
+ // Loop every 1 second (30 frames)
19
+ const dashOffset = -(frame % 30) * 2;
20
+
21
+ return (
22
+ <div style={tw('flex items-center justify-center w-full h-full bg-gray-900')}>
23
+ <svg width="800" height="600" viewBox="0 0 800 600">
24
+ {/* Marching ants around a rectangle */}
25
+ <rect
26
+ x="100"
27
+ y="100"
28
+ width="600"
29
+ height="400"
30
+ fill="none"
31
+ stroke="#3b82f6"
32
+ strokeWidth={4}
33
+ strokeDasharray="10 5"
34
+ strokeDashoffset={dashOffset}
35
+ />
36
+
37
+ {/* Animated dashed circle */}
38
+ <circle
39
+ cx="400"
40
+ cy="300"
41
+ r="150"
42
+ fill="none"
43
+ stroke="#10b981"
44
+ strokeWidth={6}
45
+ strokeDasharray="20 10"
46
+ strokeDashoffset={dashOffset * 1.5}
47
+ />
48
+
49
+ {/* Wavy path with animated dashes */}
50
+ <path
51
+ d="M 50 300 Q 150 200 250 300 T 450 300 T 650 300 T 850 300"
52
+ fill="none"
53
+ stroke="#f59e0b"
54
+ strokeWidth={5}
55
+ strokeDasharray="15 8"
56
+ strokeDashoffset={dashOffset * 0.8}
57
+ />
58
+
59
+ {/* Small circle with fast animation */}
60
+ <circle
61
+ cx="400"
62
+ cy="300"
63
+ r="80"
64
+ fill="none"
65
+ stroke="#ec4899"
66
+ strokeWidth={3}
67
+ strokeDasharray="5 3"
68
+ strokeDashoffset={dashOffset * 2}
69
+ />
70
+ </svg>
71
+ </div>
72
+ );
73
+ }
@@ -0,0 +1,176 @@
1
+ import React from 'react';
2
+
3
+ export const meta = {
4
+ name: "path-follow-test",
5
+ description: "Animate elements along SVG paths with rotation",
6
+ type: "video",
7
+ size: {
8
+ width: 1920,
9
+ height: 1080
10
+ },
11
+ props: {},
12
+ video: {
13
+ duration: 4,
14
+ fps: 30
15
+ }
16
+ };
17
+
18
+ // Calculate position on quadratic Bezier curve
19
+ function pointOnQuadraticBezier(p0, p1, p2, t) {
20
+ const x = (1 - t) * (1 - t) * p0.x + 2 * (1 - t) * t * p1.x + t * t * p2.x;
21
+ const y = (1 - t) * (1 - t) * p0.y + 2 * (1 - t) * t * p1.y + t * t * p2.y;
22
+ return { x, y };
23
+ }
24
+
25
+ // Calculate angle on quadratic Bezier curve
26
+ function angleOnQuadraticBezier(p0, p1, p2, t) {
27
+ const dx = 2 * (1 - t) * (p1.x - p0.x) + 2 * t * (p2.x - p1.x);
28
+ const dy = 2 * (1 - t) * (p1.y - p0.y) + 2 * t * (p2.y - p1.y);
29
+ return Math.atan2(dy, dx) * (180 / Math.PI);
30
+ }
31
+
32
+ // Calculate position on cubic Bezier curve
33
+ function pointOnCubicBezier(p0, p1, p2, p3, t) {
34
+ const mt = 1 - t;
35
+ const mt2 = mt * mt;
36
+ const mt3 = mt2 * mt;
37
+ const t2 = t * t;
38
+ const t3 = t2 * t;
39
+
40
+ const x = mt3 * p0.x + 3 * mt2 * t * p1.x + 3 * mt * t2 * p2.x + t3 * p3.x;
41
+ const y = mt3 * p0.y + 3 * mt2 * t * p1.y + 3 * mt * t2 * p2.y + t3 * p3.y;
42
+ return { x, y };
43
+ }
44
+
45
+ // Calculate angle on cubic Bezier curve
46
+ function angleOnCubicBezier(p0, p1, p2, p3, t) {
47
+ const mt = 1 - t;
48
+ const mt2 = mt * mt;
49
+ const t2 = t * t;
50
+
51
+ const dx = -3 * mt2 * p0.x + 3 * mt2 * p1.x - 6 * mt * t * p1.x - 3 * t2 * p2.x + 6 * mt * t * p2.x + 3 * t2 * p3.x;
52
+ const dy = -3 * mt2 * p0.y + 3 * mt2 * p1.y - 6 * mt * t * p1.y - 3 * t2 * p2.y + 6 * mt * t * p2.y + 3 * t2 * p3.y;
53
+ return Math.atan2(dy, dx) * (180 / Math.PI);
54
+ }
55
+
56
+ // Calculate position on circle
57
+ function pointOnCircle(cx, cy, radius, angleRadians) {
58
+ return {
59
+ x: cx + radius * Math.cos(angleRadians),
60
+ y: cy + radius * Math.sin(angleRadians)
61
+ };
62
+ }
63
+
64
+ export default function PathFollowTest({ tw, progress }) {
65
+ // Quadratic Bezier path (top curve)
66
+ const quad = {
67
+ p0: { x: 200, y: 400 },
68
+ p1: { x: 960, y: 150 },
69
+ p2: { x: 1720, y: 400 }
70
+ };
71
+ const quadPos = pointOnQuadraticBezier(quad.p0, quad.p1, quad.p2, progress);
72
+ const quadAngle = angleOnQuadraticBezier(quad.p0, quad.p1, quad.p2, progress);
73
+
74
+ // Cubic Bezier path (S curve)
75
+ const cubic = {
76
+ p0: { x: 200, y: 700 },
77
+ p1: { x: 600, y: 500 },
78
+ p2: { x: 1320, y: 900 },
79
+ p3: { x: 1720, y: 700 }
80
+ };
81
+ const cubicPos = pointOnCubicBezier(cubic.p0, cubic.p1, cubic.p2, cubic.p3, progress);
82
+ const cubicAngle = angleOnCubicBezier(cubic.p0, cubic.p1, cubic.p2, cubic.p3, progress);
83
+
84
+ // Circle path
85
+ const circle = { cx: 960, cy: 540, radius: 250 };
86
+ const circleAngle = progress * Math.PI * 2;
87
+ const circlePos = pointOnCircle(circle.cx, circle.cy, circle.radius, circleAngle);
88
+ const circleTangentAngle = (circleAngle * 180 / Math.PI) + 90;
89
+
90
+ return (
91
+ <div style={{ display: 'flex', ...tw('relative w-full h-full bg-gradient-to-br from-purple-900 to-blue-900') }}>
92
+ <svg
93
+ width="1920"
94
+ height="1080"
95
+ viewBox="0 0 1920 1080"
96
+ style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }}
97
+ >
98
+ {/* Draw the paths (semi-transparent) */}
99
+ <path
100
+ d={`M ${quad.p0.x} ${quad.p0.y} Q ${quad.p1.x} ${quad.p1.y} ${quad.p2.x} ${quad.p2.y}`}
101
+ stroke="rgba(255,255,255,0.3)"
102
+ strokeWidth={2}
103
+ fill="none"
104
+ strokeDasharray="5 5"
105
+ />
106
+
107
+ <path
108
+ d={`M ${cubic.p0.x} ${cubic.p0.y} C ${cubic.p1.x} ${cubic.p1.y} ${cubic.p2.x} ${cubic.p2.y} ${cubic.p3.x} ${cubic.p3.y}`}
109
+ stroke="rgba(255,255,255,0.3)"
110
+ strokeWidth={2}
111
+ fill="none"
112
+ strokeDasharray="5 5"
113
+ />
114
+
115
+ <circle
116
+ cx={circle.cx}
117
+ cy={circle.cy}
118
+ r={circle.radius}
119
+ stroke="rgba(255,255,255,0.3)"
120
+ strokeWidth={2}
121
+ fill="none"
122
+ strokeDasharray="5 5"
123
+ />
124
+ </svg>
125
+
126
+ {/* Rocket on quadratic bezier */}
127
+ <div
128
+ style={{
129
+ position: "absolute",
130
+ left: quadPos.x,
131
+ top: quadPos.y,
132
+ transform: `translate(-50%, -50%) rotate(${quadAngle}deg)`,
133
+ fontSize: '48px'
134
+ }}
135
+ >
136
+ 🚀
137
+ </div>
138
+
139
+ {/* Car on cubic bezier */}
140
+ <div
141
+ style={{
142
+ position: "absolute",
143
+ left: cubicPos.x,
144
+ top: cubicPos.y,
145
+ transform: `translate(-50%, -50%) rotate(${cubicAngle}deg)`,
146
+ fontSize: '48px'
147
+ }}
148
+ >
149
+ 🏎️
150
+ </div>
151
+
152
+ {/* Airplane on circle */}
153
+ <div
154
+ style={{
155
+ position: "absolute",
156
+ left: circlePos.x,
157
+ top: circlePos.y,
158
+ transform: `translate(-50%, -50%) rotate(${circleTangentAngle}deg)`,
159
+ fontSize: '48px'
160
+ }}
161
+ >
162
+ ✈️
163
+ </div>
164
+
165
+ {/* Text labels */}
166
+ <div style={tw('flex flex-col absolute top-8 left-8')}>
167
+ <h1 style={tw('text-4xl font-bold text-white mb-2')}>
168
+ Path Following Animation
169
+ </h1>
170
+ <p style={tw('text-xl text-white/80')}>
171
+ Progress: {Math.round(progress * 100)}%
172
+ </p>
173
+ </div>
174
+ </div>
175
+ );
176
+ }
@@ -0,0 +1,98 @@
1
+ import React from 'react';
2
+
3
+ export const meta = {
4
+ name: "path-simple-test",
5
+ description: "Simple path following with helpers",
6
+ type: "video",
7
+ size: {
8
+ width: 1920,
9
+ height: 1080
10
+ },
11
+ props: {},
12
+ video: {
13
+ duration: 4,
14
+ fps: 30
15
+ }
16
+ };
17
+
18
+ export default function PathSimpleTest({ tw, progress, path }) {
19
+ // Follow a quadratic curve - just define the points!
20
+ const rocket = path.followQuadratic(
21
+ { x: 200, y: 400 }, // Start
22
+ { x: 960, y: 150 }, // Control
23
+ { x: 1720, y: 400 }, // End
24
+ progress
25
+ );
26
+
27
+ // Follow a cubic Bezier S-curve
28
+ const car = path.followCubic(
29
+ { x: 200, y: 700 }, // Start
30
+ { x: 600, y: 500 }, // Control 1
31
+ { x: 1320, y: 900 }, // Control 2
32
+ { x: 1720, y: 700 }, // End
33
+ progress
34
+ );
35
+
36
+ // Follow a circle
37
+ const plane = path.followCircle(960, 540, 250, progress);
38
+
39
+ return (
40
+ <div style={{ display: 'flex', ...tw('relative w-full h-full bg-gradient-to-br from-purple-900 to-blue-900') }}>
41
+ {/* Draw the paths */}
42
+ <svg width="1920" height="1080" viewBox="0 0 1920 1080" style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }}>
43
+ <path d="M 200 400 Q 960 150 1720 400" stroke="rgba(255,255,255,0.3)" strokeWidth={2} fill="none" strokeDasharray="5 5" />
44
+ <path d="M 200 700 C 600 500 1320 900 1720 700" stroke="rgba(255,255,255,0.3)" strokeWidth={2} fill="none" strokeDasharray="5 5" />
45
+ <circle cx="960" cy="540" r="250" stroke="rgba(255,255,255,0.3)" strokeWidth={2} fill="none" strokeDasharray="5 5" />
46
+ </svg>
47
+
48
+ {/* Rocket */}
49
+ <div
50
+ style={{
51
+ position: "absolute",
52
+ left: rocket.x,
53
+ top: rocket.y,
54
+ transform: `translate(-50%, -50%) rotate(${rocket.angle}deg)`,
55
+ fontSize: '48px'
56
+ }}
57
+ >
58
+ 🚀
59
+ </div>
60
+
61
+ {/* Car */}
62
+ <div
63
+ style={{
64
+ position: "absolute",
65
+ left: car.x,
66
+ top: car.y,
67
+ transform: `translate(-50%, -50%) rotate(${car.angle}deg)`,
68
+ fontSize: '48px'
69
+ }}
70
+ >
71
+ 🏎️
72
+ </div>
73
+
74
+ {/* Airplane */}
75
+ <div
76
+ style={{
77
+ position: "absolute",
78
+ left: plane.x,
79
+ top: plane.y,
80
+ transform: `translate(-50%, -50%) rotate(${plane.angle}deg)`,
81
+ fontSize: '48px'
82
+ }}
83
+ >
84
+ ✈️
85
+ </div>
86
+
87
+ {/* Title */}
88
+ <div style={tw('flex flex-col absolute top-8 left-8')}>
89
+ <h1 style={tw('text-4xl font-bold text-white mb-2')}>
90
+ Simple Path Following
91
+ </h1>
92
+ <p style={tw('text-xl text-white/80')}>
93
+ Progress: {Math.round(progress * 100)}%
94
+ </p>
95
+ </div>
96
+ </div>
97
+ );
98
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "stroke-dash-test",
3
+ "description": "Test SVG stroke-dash animations",
4
+ "type": "video",
5
+ "props": {},
6
+ "video": {
7
+ "duration": 4000,
8
+ "fps": 30,
9
+ "width": 1920,
10
+ "height": 1080
11
+ }
12
+ }
@@ -0,0 +1,53 @@
1
+ export const meta = {
2
+ name: "stroke-dash-test",
3
+ description: "Test SVG stroke-dash animations",
4
+ type: "video",
5
+ size: {
6
+ width: 1920,
7
+ height: 1080
8
+ },
9
+ props: {},
10
+ video: {
11
+ duration: 4,
12
+ fps: 30
13
+ }
14
+ };
15
+
16
+ export default function StrokeDashTest({ tw }) {
17
+ return (
18
+ <div style={tw('flex items-center justify-center w-full h-full bg-gray-900')}>
19
+ <svg width="600" height="400" viewBox="0 0 600 400">
20
+ {/* Draw a checkmark */}
21
+ <path
22
+ d="M100 200 L 200 300 L 400 100"
23
+ stroke="#10b981"
24
+ strokeWidth={8}
25
+ fill="none"
26
+ strokeLinecap="round"
27
+ strokeLinejoin="round"
28
+ style={tw('ease-out enter-stroke-dash-[600]/0/1500')}
29
+ />
30
+
31
+ {/* Draw a circle after checkmark */}
32
+ <circle
33
+ cx="250"
34
+ cy="200"
35
+ r="150"
36
+ stroke="#3b82f6"
37
+ strokeWidth={6}
38
+ fill="none"
39
+ style={tw('ease-out enter-stroke-dash-[942]/1000/1500')}
40
+ />
41
+
42
+ {/* Looping star */}
43
+ <path
44
+ d="M450 50 L470 100 L525 100 L485 130 L505 180 L450 150 L395 180 L415 130 L375 100 L430 100 Z"
45
+ stroke="#f59e0b"
46
+ strokeWidth={4}
47
+ fill="none"
48
+ style={tw('loop-stroke-dash-[400]/3000')}
49
+ />
50
+ </svg>
51
+ </div>
52
+ );
53
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Path following helpers for video animations
3
+ * Returns position and rotation angle for elements following SVG paths
4
+ */
5
+ export interface PathPoint {
6
+ x: number;
7
+ y: number;
8
+ angle: number;
9
+ }
10
+ export interface Point {
11
+ x: number;
12
+ y: number;
13
+ }
14
+ /**
15
+ * Follow a straight line from p0 to p1
16
+ * @param p0 Start point
17
+ * @param p1 End point
18
+ * @param t Progress (0-1)
19
+ * @returns Position and angle
20
+ */
21
+ export declare function followLine(p0: Point, p1: Point, t: number): PathPoint;
22
+ /**
23
+ * Follow a quadratic Bezier curve
24
+ * @param p0 Start point
25
+ * @param p1 Control point
26
+ * @param p2 End point
27
+ * @param t Progress (0-1)
28
+ * @returns Position and angle
29
+ */
30
+ export declare function followQuadratic(p0: Point, p1: Point, p2: Point, t: number): PathPoint;
31
+ /**
32
+ * Follow a cubic Bezier curve
33
+ * @param p0 Start point
34
+ * @param p1 First control point
35
+ * @param p2 Second control point
36
+ * @param p3 End point
37
+ * @param t Progress (0-1)
38
+ * @returns Position and angle
39
+ */
40
+ export declare function followCubic(p0: Point, p1: Point, p2: Point, p3: Point, t: number): PathPoint;
41
+ /**
42
+ * Follow a circular path
43
+ * @param cx Center x
44
+ * @param cy Center y
45
+ * @param radius Circle radius
46
+ * @param t Progress (0-1, completes one full rotation)
47
+ * @returns Position and angle
48
+ */
49
+ export declare function followCircle(cx: number, cy: number, radius: number, t: number): PathPoint;
50
+ /**
51
+ * Follow an elliptical path
52
+ * @param cx Center x
53
+ * @param cy Center y
54
+ * @param rx Horizontal radius
55
+ * @param ry Vertical radius
56
+ * @param t Progress (0-1, completes one full rotation)
57
+ * @returns Position and angle
58
+ */
59
+ export declare function followEllipse(cx: number, cy: number, rx: number, ry: number, t: number): PathPoint;
60
+ /**
61
+ * Follow an arc (portion of a circle)
62
+ * @param cx Center x
63
+ * @param cy Center y
64
+ * @param radius Circle radius
65
+ * @param startAngle Starting angle in degrees
66
+ * @param endAngle Ending angle in degrees
67
+ * @param t Progress (0-1)
68
+ * @returns Position and angle
69
+ */
70
+ export declare function followArc(cx: number, cy: number, radius: number, startAngle: number, endAngle: number, t: number): PathPoint;
71
+ //# sourceMappingURL=path-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-helpers.d.ts","sourceRoot":"","sources":["../../src/lib/path-helpers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,SAAS;IACxB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,KAAK;IACpB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAMrE;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAerF;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAiB5F;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CASzF;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAWlG;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CACvB,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,CAAC,EAAE,MAAM,GACR,SAAS,CAYX"}
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Path following helpers for video animations
3
+ * Returns position and rotation angle for elements following SVG paths
4
+ */
5
+ /**
6
+ * Follow a straight line from p0 to p1
7
+ * @param p0 Start point
8
+ * @param p1 End point
9
+ * @param t Progress (0-1)
10
+ * @returns Position and angle
11
+ */
12
+ export function followLine(p0, p1, t) {
13
+ const x = p0.x + (p1.x - p0.x) * t;
14
+ const y = p0.y + (p1.y - p0.y) * t;
15
+ const angle = Math.atan2(p1.y - p0.y, p1.x - p0.x) * (180 / Math.PI);
16
+ return { x, y, angle };
17
+ }
18
+ /**
19
+ * Follow a quadratic Bezier curve
20
+ * @param p0 Start point
21
+ * @param p1 Control point
22
+ * @param p2 End point
23
+ * @param t Progress (0-1)
24
+ * @returns Position and angle
25
+ */
26
+ export function followQuadratic(p0, p1, p2, t) {
27
+ // Position on curve: (1-t)²·P0 + 2(1-t)t·P1 + t²·P2
28
+ const mt = 1 - t;
29
+ const mt2 = mt * mt;
30
+ const t2 = t * t;
31
+ const x = mt2 * p0.x + 2 * mt * t * p1.x + t2 * p2.x;
32
+ const y = mt2 * p0.y + 2 * mt * t * p1.y + t2 * p2.y;
33
+ // Tangent (derivative): 2(1-t)(P1-P0) + 2t(P2-P1)
34
+ const dx = 2 * mt * (p1.x - p0.x) + 2 * t * (p2.x - p1.x);
35
+ const dy = 2 * mt * (p1.y - p0.y) + 2 * t * (p2.y - p1.y);
36
+ const angle = Math.atan2(dy, dx) * (180 / Math.PI);
37
+ return { x, y, angle };
38
+ }
39
+ /**
40
+ * Follow a cubic Bezier curve
41
+ * @param p0 Start point
42
+ * @param p1 First control point
43
+ * @param p2 Second control point
44
+ * @param p3 End point
45
+ * @param t Progress (0-1)
46
+ * @returns Position and angle
47
+ */
48
+ export function followCubic(p0, p1, p2, p3, t) {
49
+ // Position on curve: (1-t)³·P0 + 3(1-t)²t·P1 + 3(1-t)t²·P2 + t³·P3
50
+ const mt = 1 - t;
51
+ const mt2 = mt * mt;
52
+ const mt3 = mt2 * mt;
53
+ const t2 = t * t;
54
+ const t3 = t2 * t;
55
+ const x = mt3 * p0.x + 3 * mt2 * t * p1.x + 3 * mt * t2 * p2.x + t3 * p3.x;
56
+ const y = mt3 * p0.y + 3 * mt2 * t * p1.y + 3 * mt * t2 * p2.y + t3 * p3.y;
57
+ // Tangent (derivative)
58
+ const dx = -3 * mt2 * p0.x + 3 * mt2 * p1.x - 6 * mt * t * p1.x - 3 * t2 * p2.x + 6 * mt * t * p2.x + 3 * t2 * p3.x;
59
+ const dy = -3 * mt2 * p0.y + 3 * mt2 * p1.y - 6 * mt * t * p1.y - 3 * t2 * p2.y + 6 * mt * t * p2.y + 3 * t2 * p3.y;
60
+ const angle = Math.atan2(dy, dx) * (180 / Math.PI);
61
+ return { x, y, angle };
62
+ }
63
+ /**
64
+ * Follow a circular path
65
+ * @param cx Center x
66
+ * @param cy Center y
67
+ * @param radius Circle radius
68
+ * @param t Progress (0-1, completes one full rotation)
69
+ * @returns Position and angle
70
+ */
71
+ export function followCircle(cx, cy, radius, t) {
72
+ const angleRadians = t * Math.PI * 2;
73
+ const x = cx + radius * Math.cos(angleRadians);
74
+ const y = cy + radius * Math.sin(angleRadians);
75
+ // Tangent is perpendicular to radius (90 degrees ahead)
76
+ const angle = (angleRadians * 180 / Math.PI) + 90;
77
+ return { x, y, angle };
78
+ }
79
+ /**
80
+ * Follow an elliptical path
81
+ * @param cx Center x
82
+ * @param cy Center y
83
+ * @param rx Horizontal radius
84
+ * @param ry Vertical radius
85
+ * @param t Progress (0-1, completes one full rotation)
86
+ * @returns Position and angle
87
+ */
88
+ export function followEllipse(cx, cy, rx, ry, t) {
89
+ const angleRadians = t * Math.PI * 2;
90
+ const x = cx + rx * Math.cos(angleRadians);
91
+ const y = cy + ry * Math.sin(angleRadians);
92
+ // Tangent for ellipse
93
+ const dx = -rx * Math.sin(angleRadians);
94
+ const dy = ry * Math.cos(angleRadians);
95
+ const angle = Math.atan2(dy, dx) * (180 / Math.PI);
96
+ return { x, y, angle };
97
+ }
98
+ /**
99
+ * Follow an arc (portion of a circle)
100
+ * @param cx Center x
101
+ * @param cy Center y
102
+ * @param radius Circle radius
103
+ * @param startAngle Starting angle in degrees
104
+ * @param endAngle Ending angle in degrees
105
+ * @param t Progress (0-1)
106
+ * @returns Position and angle
107
+ */
108
+ export function followArc(cx, cy, radius, startAngle, endAngle, t) {
109
+ const startRad = (startAngle * Math.PI) / 180;
110
+ const endRad = (endAngle * Math.PI) / 180;
111
+ const angleRadians = startRad + (endRad - startRad) * t;
112
+ const x = cx + radius * Math.cos(angleRadians);
113
+ const y = cy + radius * Math.sin(angleRadians);
114
+ // Tangent is perpendicular to radius (90 degrees ahead)
115
+ const angle = (angleRadians * 180 / Math.PI) + 90;
116
+ return { x, y, angle };
117
+ }
118
+ //# sourceMappingURL=path-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-helpers.js","sourceRoot":"","sources":["../../src/lib/path-helpers.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/lib/renderer.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AA6B1D;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAIzC;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,YAAY,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC;IAAE,MAAM,EAAE,GAAG,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC,CAqFhD;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,YAAY,EAAE,MAAM,EACpB,KAAK,GAAE,aAAkB,EACzB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,GAAG,CAAC;IAAC,WAAW,CAAC,EAAE;QAAE,EAAE,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAA;CAAO,GACrH,OAAO,CAAC,MAAM,CAAC,CAwSjB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,YAAY,EAAE,MAAM,EACpB,KAAK,GAAE,aAAkB,EACzB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,GAAG,CAAA;CAAO,GAC9D,OAAO,CAAC,MAAM,CAAC,CAsBjB;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,YAAY,EAAE,MAAM,EACpB,KAAK,GAAE,aAAkB,EACzB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,GAAG,CAAA;CAAO,GAChF,OAAO,CAAC,MAAM,CAAC,CAwBjB;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,YAAY,EAAE,MAAM,EACpB,KAAK,GAAE,aAAkB,EACzB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,GAAG,CAAA;CAAO,GAC7B,OAAO,CAAC,MAAM,CAAC,CAUjB;AAGD;;GAEG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,MAAM,GAAG,MAAM,EACrB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAEf;AAoLD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;IACjD,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,wBAAsB,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,CA8B7E"}
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/lib/renderer.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AA6B1D;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAIzC;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,YAAY,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC;IAAE,MAAM,EAAE,GAAG,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC,CAqFhD;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,YAAY,EAAE,MAAM,EACpB,KAAK,GAAE,aAAkB,EACzB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,GAAG,CAAC;IAAC,WAAW,CAAC,EAAE;QAAE,EAAE,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAA;CAAO,GACrH,OAAO,CAAC,MAAM,CAAC,CA+WjB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,YAAY,EAAE,MAAM,EACpB,KAAK,GAAE,aAAkB,EACzB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,GAAG,CAAA;CAAO,GAC9D,OAAO,CAAC,MAAM,CAAC,CAsBjB;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,YAAY,EAAE,MAAM,EACpB,KAAK,GAAE,aAAkB,EACzB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,GAAG,CAAA;CAAO,GAChF,OAAO,CAAC,MAAM,CAAC,CAwBjB;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,YAAY,EAAE,MAAM,EACpB,KAAK,GAAE,aAAkB,EACzB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,GAAG,CAAA;CAAO,GAC7B,OAAO,CAAC,MAAM,CAAC,CAUjB;AAGD;;GAEG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,MAAM,GAAG,MAAM,EACrB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAEf;AAoLD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;IACjD,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,wBAAsB,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,CA8B7E"}