dingbatch 0.1.0 → 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.
@@ -0,0 +1,1626 @@
1
+ // src/generators/utils/svg.ts
2
+ function wrapPath(path, width, height) {
3
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width} ${height}" width="${width}" height="${height}"><path d="${path}" fill="currentColor"/></svg>`;
4
+ }
5
+ function addSvgFields(result) {
6
+ const viewBox = `0 0 ${result.width} ${result.height}`;
7
+ const svg = wrapPath(result.path, result.width, result.height);
8
+ return { ...result, viewBox, svg };
9
+ }
10
+
11
+ // src/presets/boomerang.ts
12
+ var crescent = {
13
+ style: "crescent",
14
+ armLength: 50,
15
+ bendAngle: 160,
16
+ thickness: 35,
17
+ taper: 0.5,
18
+ tipRoundness: 0.2,
19
+ armCurvature: 0,
20
+ bendSharpness: 0
21
+ };
22
+ var fatMoon = {
23
+ style: "crescent",
24
+ armLength: 45,
25
+ bendAngle: 180,
26
+ thickness: 50,
27
+ taper: 0.3,
28
+ tipRoundness: 0.6,
29
+ armCurvature: 0,
30
+ bendSharpness: 0
31
+ };
32
+ var sharpChevron = {
33
+ style: "chevron",
34
+ armLength: 55,
35
+ bendAngle: 60,
36
+ thickness: 40,
37
+ taper: 1,
38
+ tipRoundness: 0,
39
+ armCurvature: 0,
40
+ bendSharpness: 0
41
+ };
42
+ var thinArc = {
43
+ style: "crescent",
44
+ armLength: 60,
45
+ bendAngle: 140,
46
+ thickness: 20,
47
+ taper: 0.7,
48
+ tipRoundness: 0.1,
49
+ armCurvature: 0,
50
+ bendSharpness: 0
51
+ };
52
+ var horseshoe = {
53
+ style: "horseshoe",
54
+ armLength: 80,
55
+ bendAngle: 50,
56
+ thickness: 18,
57
+ taper: 0.2,
58
+ tipRoundness: 0.3,
59
+ armCurvature: 0.4,
60
+ bendSharpness: 0
61
+ };
62
+
63
+ // src/generators/curved/boomerang.ts
64
+ function boomerangBase(params) {
65
+ const style = params.style || "classic";
66
+ switch (style) {
67
+ case "crescent":
68
+ return generateCrescent(params);
69
+ case "horseshoe":
70
+ return generateHorseshoe(params);
71
+ case "chevron":
72
+ return generateChevron(params);
73
+ case "classic":
74
+ default:
75
+ return generateClassic(params);
76
+ }
77
+ }
78
+ var boomerang = Object.assign(boomerangBase, {
79
+ crescent: (overrides) => boomerangBase({ ...crescent, ...overrides }),
80
+ fatMoon: (overrides) => boomerangBase({ ...fatMoon, ...overrides }),
81
+ sharpChevron: (overrides) => boomerangBase({ ...sharpChevron, ...overrides }),
82
+ thinArc: (overrides) => boomerangBase({ ...thinArc, ...overrides }),
83
+ horseshoe: (overrides) => boomerangBase({ ...horseshoe, ...overrides })
84
+ });
85
+ function generateClassic(params) {
86
+ const {
87
+ armLength,
88
+ bendAngle,
89
+ armCurvature,
90
+ bendSharpness,
91
+ thickness,
92
+ taper,
93
+ tipRoundness,
94
+ armBalance = 1,
95
+ thicknessBalance = 0,
96
+ rotation = 0
97
+ } = params;
98
+ const clampedBendAngle = Math.max(30, Math.min(180, bendAngle));
99
+ const clampedArmCurvature = Math.max(0, Math.min(1, armCurvature));
100
+ const clampedBendSharpness = Math.max(0, Math.min(1, bendSharpness));
101
+ const clampedTaper = Math.max(0, Math.min(1, taper));
102
+ const clampedTipRoundness = Math.max(0, Math.min(1, tipRoundness));
103
+ const clampedArmBalance = Math.max(0.5, Math.min(2, armBalance));
104
+ const clampedThicknessBalance = Math.max(-1, Math.min(1, thicknessBalance));
105
+ const arm1Length = armLength * (2 / (1 + clampedArmBalance));
106
+ const arm2Length = armLength * (2 * clampedArmBalance / (1 + clampedArmBalance));
107
+ const halfAngle = clampedBendAngle / 2 * Math.PI / 180;
108
+ const arm1Dir = { x: -Math.sin(halfAngle), y: -Math.cos(halfAngle) };
109
+ const arm2Dir = { x: Math.sin(halfAngle), y: -Math.cos(halfAngle) };
110
+ const tip1 = { x: arm1Dir.x * arm1Length, y: arm1Dir.y * arm1Length };
111
+ const tip2 = { x: arm2Dir.x * arm2Length, y: arm2Dir.y * arm2Length };
112
+ const bendPoint = { x: 0, y: 0 };
113
+ const numSamples = 20;
114
+ const arm1Spine = generateArmSpine(tip1, bendPoint, arm1Dir, arm1Length, clampedArmCurvature, numSamples);
115
+ const arm2Spine = generateArmSpine(bendPoint, tip2, arm2Dir, arm2Length, clampedArmCurvature, numSamples);
116
+ const minThickness = thickness * clampedTaper;
117
+ function getThicknessAlongArm(t, isArm1) {
118
+ const tipFade = Math.sin(t * Math.PI / 2);
119
+ const baseThickness = minThickness + (thickness - minThickness) * tipFade;
120
+ const balanceFactor = isArm1 ? 1 - clampedThicknessBalance * 0.3 : 1 + clampedThicknessBalance * 0.3;
121
+ return baseThickness * balanceFactor;
122
+ }
123
+ const arm1Outer = [];
124
+ const arm1Inner = [];
125
+ const arm2Outer = [];
126
+ const arm2Inner = [];
127
+ for (let i = 0; i < arm1Spine.length; i++) {
128
+ const t = i / (arm1Spine.length - 1);
129
+ const point = arm1Spine[i];
130
+ const tangent = getSpineTangent(arm1Spine, i);
131
+ const normal = { x: -tangent.y, y: tangent.x };
132
+ const halfThick = getThicknessAlongArm(t, true) / 2;
133
+ arm1Outer.push({ x: point.x + normal.x * halfThick, y: point.y + normal.y * halfThick });
134
+ arm1Inner.push({ x: point.x - normal.x * halfThick, y: point.y - normal.y * halfThick });
135
+ }
136
+ for (let i = 0; i < arm2Spine.length; i++) {
137
+ const t = 1 - i / (arm2Spine.length - 1);
138
+ const point = arm2Spine[i];
139
+ const tangent = getSpineTangent(arm2Spine, i);
140
+ const normal = { x: -tangent.y, y: tangent.x };
141
+ const halfThick = getThicknessAlongArm(t, false) / 2;
142
+ arm2Outer.push({ x: point.x + normal.x * halfThick, y: point.y + normal.y * halfThick });
143
+ arm2Inner.push({ x: point.x - normal.x * halfThick, y: point.y - normal.y * halfThick });
144
+ }
145
+ const pathParts = [];
146
+ pathParts.push(`M ${arm1Outer[0].x.toFixed(2)},${arm1Outer[0].y.toFixed(2)}`);
147
+ const tip1Curve = clampedTipRoundness * thickness * 0.3;
148
+ pathParts.push(`Q ${(tip1.x + arm1Dir.x * tip1Curve).toFixed(2)},${(tip1.y + arm1Dir.y * tip1Curve).toFixed(2)} ${arm1Inner[0].x.toFixed(2)},${arm1Inner[0].y.toFixed(2)}`);
149
+ pathParts.push(smoothCurveThroughPoints(arm1Inner));
150
+ const bendInner2 = arm2Inner[0];
151
+ if (clampedBendSharpness < 0.3) {
152
+ pathParts.push(`L ${bendInner2.x.toFixed(2)},${bendInner2.y.toFixed(2)}`);
153
+ } else {
154
+ const bendInnerOffset = thickness * 0.2 * clampedBendSharpness;
155
+ const bendInnerCtrl = { x: 0, y: bendInnerOffset };
156
+ pathParts.push(`Q ${bendInnerCtrl.x.toFixed(2)},${bendInnerCtrl.y.toFixed(2)} ${bendInner2.x.toFixed(2)},${bendInner2.y.toFixed(2)}`);
157
+ }
158
+ pathParts.push(smoothCurveThroughPoints(arm2Inner));
159
+ const tip2Curve = clampedTipRoundness * thickness * 0.3;
160
+ pathParts.push(`Q ${(tip2.x + arm2Dir.x * tip2Curve).toFixed(2)},${(tip2.y + arm2Dir.y * tip2Curve).toFixed(2)} ${arm2Outer[arm2Outer.length - 1].x.toFixed(2)},${arm2Outer[arm2Outer.length - 1].y.toFixed(2)}`);
161
+ const arm2OuterReversed = [...arm2Outer].reverse();
162
+ pathParts.push(smoothCurveThroughPoints(arm2OuterReversed));
163
+ const bendOuter1 = arm1Outer[arm1Outer.length - 1];
164
+ if (clampedBendSharpness < 0.3) {
165
+ pathParts.push(`L ${bendOuter1.x.toFixed(2)},${bendOuter1.y.toFixed(2)}`);
166
+ } else {
167
+ const bendOuterOffset = -thickness * 0.4 * clampedBendSharpness;
168
+ const bendOuterCtrl = { x: 0, y: bendOuterOffset };
169
+ pathParts.push(`Q ${bendOuterCtrl.x.toFixed(2)},${bendOuterCtrl.y.toFixed(2)} ${bendOuter1.x.toFixed(2)},${bendOuter1.y.toFixed(2)}`);
170
+ }
171
+ const arm1OuterReversed = [...arm1Outer].reverse();
172
+ pathParts.push(smoothCurveThroughPoints(arm1OuterReversed));
173
+ pathParts.push("Z");
174
+ let path = pathParts.join(" ");
175
+ const allPoints = [...arm1Outer, ...arm1Inner, ...arm2Outer, ...arm2Inner];
176
+ let minX = Math.min(...allPoints.map((p) => p.x));
177
+ let maxX = Math.max(...allPoints.map((p) => p.x));
178
+ let minY = Math.min(...allPoints.map((p) => p.y));
179
+ let maxY = Math.max(...allPoints.map((p) => p.y));
180
+ const padding = thickness * 0.3 * clampedTipRoundness;
181
+ minX -= padding;
182
+ maxX += padding;
183
+ minY -= padding;
184
+ const width = maxX - minX;
185
+ const height = maxY - minY;
186
+ path = normalizePath(path, minX, minY);
187
+ if (rotation !== 0) {
188
+ path = rotatePath(path, rotation, width, height);
189
+ }
190
+ return addSvgFields({ path, width, height, centerX: width / 2, centerY: height / 2 });
191
+ }
192
+ function generateCrescent(params) {
193
+ const {
194
+ armLength,
195
+ // Used as arc radius
196
+ bendAngle,
197
+ // Used as arc span (degrees, 30-300)
198
+ thickness,
199
+ taper,
200
+ tipRoundness,
201
+ armBalance = 1,
202
+ // Asymmetric arc thickness along length
203
+ rotation = 0
204
+ } = params;
205
+ const radius = Math.max(20, armLength);
206
+ const arcSpan = Math.max(30, Math.min(300, bendAngle)) * Math.PI / 180;
207
+ const clampedTaper = Math.max(0, Math.min(1, taper));
208
+ const clampedTipRoundness = Math.max(0, Math.min(1, tipRoundness));
209
+ const clampedArmBalance = Math.max(0.5, Math.min(2, armBalance));
210
+ const numSamples = 30;
211
+ const startAngle = -arcSpan / 2;
212
+ const endAngle = arcSpan / 2;
213
+ const spine = [];
214
+ for (let i = 0; i <= numSamples; i++) {
215
+ const t = i / numSamples;
216
+ const angle = startAngle + (endAngle - startAngle) * t;
217
+ spine.push({
218
+ x: Math.sin(angle) * radius,
219
+ y: -Math.cos(angle) * radius + radius
220
+ // Shift so bottom of arc is at y=0
221
+ });
222
+ }
223
+ const minThickness = thickness * clampedTaper;
224
+ function getThicknessAtT(t) {
225
+ const balanceShift = (t - 0.5) * (clampedArmBalance - 1) * 0.5;
226
+ const adjustedT = Math.max(0, Math.min(1, t + balanceShift));
227
+ const adjustedDist = Math.min(adjustedT, 1 - adjustedT) * 2;
228
+ const adjustedFactor = Math.sin(adjustedDist * Math.PI / 2);
229
+ return minThickness + (thickness - minThickness) * adjustedFactor;
230
+ }
231
+ const outer = [];
232
+ const inner = [];
233
+ for (let i = 0; i < spine.length; i++) {
234
+ const t = i / (spine.length - 1);
235
+ const point = spine[i];
236
+ const tangent = getSpineTangent(spine, i);
237
+ const normal = { x: -tangent.y, y: tangent.x };
238
+ const halfThick = getThicknessAtT(t) / 2;
239
+ outer.push({ x: point.x + normal.x * halfThick, y: point.y + normal.y * halfThick });
240
+ inner.push({ x: point.x - normal.x * halfThick, y: point.y - normal.y * halfThick });
241
+ }
242
+ const pathParts = [];
243
+ pathParts.push(`M ${outer[0].x.toFixed(2)},${outer[0].y.toFixed(2)}`);
244
+ const startTipCurve = clampedTipRoundness * thickness * 0.4;
245
+ const startTangent = getSpineTangent(spine, 0);
246
+ pathParts.push(`Q ${(spine[0].x - startTangent.x * startTipCurve).toFixed(2)},${(spine[0].y - startTangent.y * startTipCurve).toFixed(2)} ${inner[0].x.toFixed(2)},${inner[0].y.toFixed(2)}`);
247
+ pathParts.push(smoothCurveThroughPoints(inner));
248
+ const endTipCurve = clampedTipRoundness * thickness * 0.4;
249
+ const endTangent = getSpineTangent(spine, spine.length - 1);
250
+ pathParts.push(`Q ${(spine[spine.length - 1].x + endTangent.x * endTipCurve).toFixed(2)},${(spine[spine.length - 1].y + endTangent.y * endTipCurve).toFixed(2)} ${outer[outer.length - 1].x.toFixed(2)},${outer[outer.length - 1].y.toFixed(2)}`);
251
+ const outerReversed = [...outer].reverse();
252
+ pathParts.push(smoothCurveThroughPoints(outerReversed));
253
+ pathParts.push("Z");
254
+ let path = pathParts.join(" ");
255
+ const allPoints = [...outer, ...inner];
256
+ let minX = Math.min(...allPoints.map((p) => p.x));
257
+ let maxX = Math.max(...allPoints.map((p) => p.x));
258
+ let minY = Math.min(...allPoints.map((p) => p.y));
259
+ let maxY = Math.max(...allPoints.map((p) => p.y));
260
+ const padding = thickness * 0.3 * clampedTipRoundness;
261
+ minX -= padding;
262
+ maxX += padding;
263
+ minY -= padding;
264
+ maxY += padding;
265
+ const width = maxX - minX;
266
+ const height = maxY - minY;
267
+ path = normalizePath(path, minX, minY);
268
+ if (rotation !== 0) {
269
+ path = rotatePath(path, rotation, width, height);
270
+ }
271
+ return addSvgFields({ path, width, height, centerX: width / 2, centerY: height / 2 });
272
+ }
273
+ function generateHorseshoe(params) {
274
+ const {
275
+ armLength,
276
+ // Length of the vertical arms
277
+ bendAngle,
278
+ // Spacing between arms (width at top)
279
+ armCurvature,
280
+ // How curved the bottom connection is
281
+ thickness,
282
+ taper,
283
+ tipRoundness,
284
+ armBalance = 1,
285
+ // Asymmetric arm lengths
286
+ rotation = 0
287
+ } = params;
288
+ const spacing = Math.max(20, bendAngle);
289
+ const clampedArmCurvature = Math.max(0, Math.min(1, armCurvature));
290
+ const clampedTaper = Math.max(0, Math.min(1, taper));
291
+ const clampedTipRoundness = Math.max(0, Math.min(1, tipRoundness));
292
+ const clampedArmBalance = Math.max(0.5, Math.min(2, armBalance));
293
+ const arm1Len = armLength * (2 / (1 + clampedArmBalance));
294
+ const arm2Len = armLength * (2 * clampedArmBalance / (1 + clampedArmBalance));
295
+ const halfSpacing = spacing / 2;
296
+ const halfThick = thickness / 2;
297
+ const tipThick = thickness * clampedTaper / 2;
298
+ const leftOuterX = -halfSpacing - halfThick;
299
+ const leftInnerX = -halfSpacing + halfThick;
300
+ const rightInnerX = halfSpacing - halfThick;
301
+ const rightOuterX = halfSpacing + halfThick;
302
+ const leftTopY = 0;
303
+ const leftBottomY = arm1Len;
304
+ const rightBottomY = arm2Len;
305
+ const rightTopY = 0;
306
+ const bottomY = Math.max(arm1Len, arm2Len);
307
+ const curveDepth = halfSpacing * clampedArmCurvature;
308
+ const pathParts = [];
309
+ const leftTipOuterX = -halfSpacing - tipThick;
310
+ const leftTipInnerX = -halfSpacing + tipThick;
311
+ const rightTipInnerX = halfSpacing - tipThick;
312
+ const rightTipOuterX = halfSpacing + tipThick;
313
+ pathParts.push(`M ${leftTipOuterX.toFixed(2)},${leftTopY.toFixed(2)}`);
314
+ if (clampedTipRoundness > 0) {
315
+ const tipCurve = clampedTipRoundness * thickness * 0.3;
316
+ pathParts.push(`Q ${(-halfSpacing).toFixed(2)},${(leftTopY - tipCurve).toFixed(2)} ${leftTipInnerX.toFixed(2)},${leftTopY.toFixed(2)}`);
317
+ } else {
318
+ pathParts.push(`L ${leftTipInnerX.toFixed(2)},${leftTopY.toFixed(2)}`);
319
+ }
320
+ pathParts.push(`L ${leftInnerX.toFixed(2)},${leftBottomY.toFixed(2)}`);
321
+ if (clampedArmCurvature > 0.1) {
322
+ const innerCtrlY = bottomY + curveDepth;
323
+ pathParts.push(`Q ${0},${innerCtrlY.toFixed(2)} ${rightInnerX.toFixed(2)},${rightBottomY.toFixed(2)}`);
324
+ } else {
325
+ pathParts.push(`L ${rightInnerX.toFixed(2)},${rightBottomY.toFixed(2)}`);
326
+ }
327
+ pathParts.push(`L ${rightTipInnerX.toFixed(2)},${rightTopY.toFixed(2)}`);
328
+ if (clampedTipRoundness > 0) {
329
+ const tipCurve = clampedTipRoundness * thickness * 0.3;
330
+ pathParts.push(`Q ${halfSpacing.toFixed(2)},${(rightTopY - tipCurve).toFixed(2)} ${rightTipOuterX.toFixed(2)},${rightTopY.toFixed(2)}`);
331
+ } else {
332
+ pathParts.push(`L ${rightTipOuterX.toFixed(2)},${rightTopY.toFixed(2)}`);
333
+ }
334
+ pathParts.push(`L ${rightOuterX.toFixed(2)},${rightBottomY.toFixed(2)}`);
335
+ if (clampedArmCurvature > 0.1) {
336
+ const outerCtrlY = bottomY + curveDepth + thickness;
337
+ pathParts.push(`Q ${0},${outerCtrlY.toFixed(2)} ${leftOuterX.toFixed(2)},${leftBottomY.toFixed(2)}`);
338
+ } else {
339
+ pathParts.push(`L ${leftOuterX.toFixed(2)},${leftBottomY.toFixed(2)}`);
340
+ }
341
+ pathParts.push(`L ${leftTipOuterX.toFixed(2)},${leftTopY.toFixed(2)}`);
342
+ pathParts.push("Z");
343
+ let path = pathParts.join(" ");
344
+ const padding = thickness * 0.3;
345
+ let minX = leftOuterX - padding;
346
+ let maxX = rightOuterX + padding;
347
+ let minY = -padding - clampedTipRoundness * thickness * 0.3;
348
+ let maxY = bottomY + curveDepth + thickness + padding;
349
+ const width = maxX - minX;
350
+ const height = maxY - minY;
351
+ path = normalizePath(path, minX, minY);
352
+ if (rotation !== 0) {
353
+ path = rotatePath(path, rotation, width, height);
354
+ }
355
+ return addSvgFields({ path, width, height, centerX: width / 2, centerY: height / 2 });
356
+ }
357
+ function generateChevron(params) {
358
+ const {
359
+ armLength,
360
+ // Length of the arms
361
+ bendAngle,
362
+ // Angle of the V (smaller = sharper point)
363
+ thickness,
364
+ // Controls arm width (proportional)
365
+ taper = 0,
366
+ // 0 = V with cutout, 1 = solid triangle (no cutout)
367
+ tipRoundness = 0,
368
+ // Roundness at the tip
369
+ armBalance = 1,
370
+ // Asymmetric arm lengths
371
+ rotation = 0
372
+ } = params;
373
+ const clampedBendAngle = Math.max(20, Math.min(160, bendAngle));
374
+ const clampedTaper = Math.max(0, Math.min(1, taper));
375
+ const clampedTipRoundness = Math.max(0, Math.min(1, tipRoundness));
376
+ const clampedArmBalance = Math.max(0.5, Math.min(2, armBalance));
377
+ const armWidth = Math.max(armLength * 0.15, thickness * 0.5);
378
+ const cutoutDepth = armLength * 0.6 * (1 - clampedTaper);
379
+ const arm1Len = armLength * (2 / (1 + clampedArmBalance));
380
+ const arm2Len = armLength * (2 * clampedArmBalance / (1 + clampedArmBalance));
381
+ const halfAngle = clampedBendAngle / 2 * Math.PI / 180;
382
+ const tip = { x: 0, y: 0 };
383
+ const arm1End = { x: -Math.sin(halfAngle) * arm1Len, y: -Math.cos(halfAngle) * arm1Len };
384
+ const arm2End = { x: Math.sin(halfAngle) * arm2Len, y: -Math.cos(halfAngle) * arm2Len };
385
+ const arm1Perp = { x: -Math.cos(halfAngle), y: Math.sin(halfAngle) };
386
+ const arm2Perp = { x: Math.cos(halfAngle), y: Math.sin(halfAngle) };
387
+ const arm1OuterCorner = {
388
+ x: arm1End.x + arm1Perp.x * armWidth / 2,
389
+ y: arm1End.y + arm1Perp.y * armWidth / 2
390
+ };
391
+ const arm1InnerCorner = {
392
+ x: arm1End.x - arm1Perp.x * armWidth / 2,
393
+ y: arm1End.y - arm1Perp.y * armWidth / 2
394
+ };
395
+ const arm2OuterCorner = {
396
+ x: arm2End.x + arm2Perp.x * armWidth / 2,
397
+ y: arm2End.y + arm2Perp.y * armWidth / 2
398
+ };
399
+ const arm2InnerCorner = {
400
+ x: arm2End.x - arm2Perp.x * armWidth / 2,
401
+ y: arm2End.y - arm2Perp.y * armWidth / 2
402
+ };
403
+ const innerTip = {
404
+ x: 0,
405
+ y: -cutoutDepth
406
+ };
407
+ const pathParts = [];
408
+ if (clampedTipRoundness > 0) {
409
+ const roundAmount = clampedTipRoundness * armWidth * 0.3;
410
+ const tipStart = {
411
+ x: tip.x + arm1Perp.x * roundAmount,
412
+ y: tip.y + arm1Perp.y * roundAmount - roundAmount * 0.5
413
+ };
414
+ pathParts.push(`M ${tipStart.x.toFixed(2)},${tipStart.y.toFixed(2)}`);
415
+ const tipEnd = {
416
+ x: tip.x + arm2Perp.x * roundAmount,
417
+ y: tip.y + arm2Perp.y * roundAmount - roundAmount * 0.5
418
+ };
419
+ pathParts.push(`Q ${tip.x.toFixed(2)},${tip.y.toFixed(2)} ${tipEnd.x.toFixed(2)},${tipEnd.y.toFixed(2)}`);
420
+ } else {
421
+ pathParts.push(`M ${tip.x.toFixed(2)},${tip.y.toFixed(2)}`);
422
+ }
423
+ pathParts.push(`L ${arm2OuterCorner.x.toFixed(2)},${arm2OuterCorner.y.toFixed(2)}`);
424
+ pathParts.push(`L ${arm2InnerCorner.x.toFixed(2)},${arm2InnerCorner.y.toFixed(2)}`);
425
+ if (cutoutDepth > 5 && clampedTaper < 0.9) {
426
+ pathParts.push(`L ${innerTip.x.toFixed(2)},${innerTip.y.toFixed(2)}`);
427
+ }
428
+ pathParts.push(`L ${arm1InnerCorner.x.toFixed(2)},${arm1InnerCorner.y.toFixed(2)}`);
429
+ pathParts.push(`L ${arm1OuterCorner.x.toFixed(2)},${arm1OuterCorner.y.toFixed(2)}`);
430
+ pathParts.push("Z");
431
+ let path = pathParts.join(" ");
432
+ const allPoints = [tip, arm1End, arm2End, arm1OuterCorner, arm1InnerCorner, arm2OuterCorner, arm2InnerCorner];
433
+ if (cutoutDepth > 5 && clampedTaper < 0.9) {
434
+ allPoints.push(innerTip);
435
+ }
436
+ let minX = Math.min(...allPoints.map((p) => p.x));
437
+ let maxX = Math.max(...allPoints.map((p) => p.x));
438
+ let minY = Math.min(...allPoints.map((p) => p.y));
439
+ let maxY = Math.max(...allPoints.map((p) => p.y));
440
+ const padding = armWidth * 0.2;
441
+ minX -= padding;
442
+ maxX += padding;
443
+ minY -= padding;
444
+ maxY += padding;
445
+ const width = maxX - minX;
446
+ const height = maxY - minY;
447
+ path = normalizePath(path, minX, minY);
448
+ if (rotation !== 0) {
449
+ path = rotatePath(path, rotation, width, height);
450
+ }
451
+ return addSvgFields({ path, width, height, centerX: width / 2, centerY: height / 2 });
452
+ }
453
+ function generateArmSpine(start, end, direction, length, curvature, numSamples) {
454
+ const points = [];
455
+ const perpDir = { x: direction.y, y: -direction.x };
456
+ const bowAmount = length * 0.4 * curvature;
457
+ const midPoint = { x: (start.x + end.x) / 2, y: (start.y + end.y) / 2 };
458
+ const controlPoint = {
459
+ x: midPoint.x + perpDir.x * bowAmount,
460
+ y: midPoint.y + perpDir.y * bowAmount
461
+ };
462
+ for (let i = 0; i <= numSamples; i++) {
463
+ const t = i / numSamples;
464
+ if (curvature < 0.1) {
465
+ points.push({
466
+ x: start.x + (end.x - start.x) * t,
467
+ y: start.y + (end.y - start.y) * t
468
+ });
469
+ } else {
470
+ const mt = 1 - t;
471
+ points.push({
472
+ x: mt * mt * start.x + 2 * mt * t * controlPoint.x + t * t * end.x,
473
+ y: mt * mt * start.y + 2 * mt * t * controlPoint.y + t * t * end.y
474
+ });
475
+ }
476
+ }
477
+ return points;
478
+ }
479
+ function getSpineTangent(spine, index) {
480
+ const prev = spine[Math.max(0, index - 1)];
481
+ const next = spine[Math.min(spine.length - 1, index + 1)];
482
+ const dx = next.x - prev.x;
483
+ const dy = next.y - prev.y;
484
+ const len = Math.sqrt(dx * dx + dy * dy);
485
+ return len > 0 ? { x: dx / len, y: dy / len } : { x: 1, y: 0 };
486
+ }
487
+ function smoothCurveThroughPoints(points) {
488
+ if (points.length < 2) return "";
489
+ const parts = [];
490
+ const tension = 0.3;
491
+ for (let i = 0; i < points.length - 1; i++) {
492
+ const p0 = points[Math.max(0, i - 1)];
493
+ const p1 = points[i];
494
+ const p2 = points[i + 1];
495
+ const p3 = points[Math.min(points.length - 1, i + 2)];
496
+ const cp1x = p1.x + (p2.x - p0.x) * tension;
497
+ const cp1y = p1.y + (p2.y - p0.y) * tension;
498
+ const cp2x = p2.x - (p3.x - p1.x) * tension;
499
+ const cp2y = p2.y - (p3.y - p1.y) * tension;
500
+ parts.push(`C ${cp1x.toFixed(2)},${cp1y.toFixed(2)} ${cp2x.toFixed(2)},${cp2y.toFixed(2)} ${p2.x.toFixed(2)},${p2.y.toFixed(2)}`);
501
+ }
502
+ return parts.join(" ");
503
+ }
504
+ function normalizePath(path, minX, minY) {
505
+ return path.replace(
506
+ /([-\d.]+),([-\d.]+)/g,
507
+ (_, x, y) => `${(parseFloat(x) - minX).toFixed(2)},${(parseFloat(y) - minY).toFixed(2)}`
508
+ );
509
+ }
510
+ function rotatePath(path, rotation, width, height) {
511
+ const rad = rotation * Math.PI / 180;
512
+ const cos = Math.cos(rad);
513
+ const sin = Math.sin(rad);
514
+ const cx = width / 2;
515
+ const cy = height / 2;
516
+ return path.replace(
517
+ /([-\d.]+),([-\d.]+)/g,
518
+ (_, xStr, yStr) => {
519
+ const x = parseFloat(xStr) - cx;
520
+ const y = parseFloat(yStr) - cy;
521
+ const rx = x * cos - y * sin + cx;
522
+ const ry = x * sin + y * cos + cy;
523
+ return `${rx.toFixed(2)},${ry.toFixed(2)}`;
524
+ }
525
+ );
526
+ }
527
+
528
+ // src/generators/curved/blob.ts
529
+ function seededRandom(seed) {
530
+ let s = seed;
531
+ return () => {
532
+ s = (s * 9301 + 49297) % 233280;
533
+ return s / 233280;
534
+ };
535
+ }
536
+ function blob(params) {
537
+ const { radius, pointCount, irregularity, smoothing, seed } = params;
538
+ const random = seededRandom(seed);
539
+ const points = [];
540
+ const angleStep = Math.PI * 2 / pointCount;
541
+ for (let i = 0; i < pointCount; i++) {
542
+ const angle = i * angleStep;
543
+ const variation = 1 + (random() - 0.5) * irregularity;
544
+ const r = radius * variation;
545
+ points.push({
546
+ x: Math.cos(angle) * r + radius,
547
+ y: Math.sin(angle) * r + radius
548
+ });
549
+ }
550
+ const path = buildSmoothPath(points, smoothing);
551
+ return addSvgFields({
552
+ path,
553
+ width: radius * 2,
554
+ height: radius * 2,
555
+ centerX: radius,
556
+ centerY: radius
557
+ });
558
+ }
559
+ function buildSmoothPath(points, smoothing) {
560
+ if (points.length < 3) return "";
561
+ const parts = [];
562
+ parts.push(`M ${points[0].x.toFixed(2)},${points[0].y.toFixed(2)}`);
563
+ for (let i = 0; i < points.length; i++) {
564
+ const p0 = points[(i - 1 + points.length) % points.length];
565
+ const p1 = points[i];
566
+ const p2 = points[(i + 1) % points.length];
567
+ const p3 = points[(i + 2) % points.length];
568
+ const cp1x = p1.x + (p2.x - p0.x) * smoothing * 0.25;
569
+ const cp1y = p1.y + (p2.y - p0.y) * smoothing * 0.25;
570
+ const cp2x = p2.x - (p3.x - p1.x) * smoothing * 0.25;
571
+ const cp2y = p2.y - (p3.y - p1.y) * smoothing * 0.25;
572
+ parts.push(`C ${cp1x.toFixed(2)},${cp1y.toFixed(2)} ${cp2x.toFixed(2)},${cp2y.toFixed(2)} ${p2.x.toFixed(2)},${p2.y.toFixed(2)}`);
573
+ }
574
+ parts.push("Z");
575
+ return parts.join(" ");
576
+ }
577
+
578
+ // src/generators/utils/path.ts
579
+ function degToRad(degrees) {
580
+ return degrees * Math.PI / 180;
581
+ }
582
+ function pointsToPath(points, closed = true) {
583
+ if (points.length === 0) return "";
584
+ const [first, ...rest] = points;
585
+ let path = `M ${first.x},${first.y}`;
586
+ for (const point of rest) {
587
+ path += ` L ${point.x},${point.y}`;
588
+ }
589
+ if (closed) {
590
+ path += " Z";
591
+ }
592
+ return path;
593
+ }
594
+ function circlePath(cx, cy, r) {
595
+ return `M ${cx - r},${cy} A ${r},${r} 0 1,0 ${cx + r},${cy} A ${r},${r} 0 1,0 ${cx - r},${cy}`;
596
+ }
597
+ function ellipsePath(cx, cy, rx, ry) {
598
+ return `M ${cx - rx},${cy} A ${rx},${ry} 0 1,0 ${cx + rx},${cy} A ${rx},${ry} 0 1,0 ${cx - rx},${cy}`;
599
+ }
600
+
601
+ // src/generators/curved/circle.ts
602
+ function circle(params) {
603
+ const { radius } = params;
604
+ return addSvgFields({
605
+ path: circlePath(radius, radius, radius),
606
+ width: radius * 2,
607
+ height: radius * 2,
608
+ centerX: radius,
609
+ centerY: radius
610
+ });
611
+ }
612
+
613
+ // src/generators/curved/kidney.ts
614
+ function kidney(params) {
615
+ const { width, height, concavityDepth, concavityPosition } = params;
616
+ const hw = width / 2;
617
+ const hh = height / 2;
618
+ const concaveX = width * concavityDepth;
619
+ const concaveY = height * concavityPosition;
620
+ const path = [
621
+ `M ${hw},0`,
622
+ // Top right curve
623
+ `C ${width * 0.8},0 ${width},${height * 0.2} ${width},${hh}`,
624
+ // Bottom right curve
625
+ `C ${width},${height * 0.8} ${width * 0.8},${height} ${hw},${height}`,
626
+ // Bottom left curve (going to concave point)
627
+ `C ${width * 0.2},${height} 0,${height * 0.8} ${concaveX},${concaveY + hh * 0.3}`,
628
+ // The concave bite (curves inward)
629
+ `Q ${concaveX + width * 0.1},${concaveY} ${concaveX},${concaveY - hh * 0.3}`,
630
+ // Top left curve (from concave back to top)
631
+ `C 0,${height * 0.2} ${width * 0.2},0 ${hw},0`,
632
+ "Z"
633
+ ].join(" ");
634
+ return addSvgFields({
635
+ path,
636
+ width,
637
+ height,
638
+ centerX: hw,
639
+ centerY: hh
640
+ });
641
+ }
642
+
643
+ // src/generators/curved/moon.ts
644
+ function moon(params) {
645
+ const { outerRadius, innerRadius, innerOffset } = params;
646
+ const size = outerRadius * 2;
647
+ const center = outerRadius;
648
+ const offset = outerRadius * innerOffset;
649
+ const d = offset;
650
+ if (d >= outerRadius + innerRadius || d === 0) {
651
+ const path2 = `M ${center + outerRadius},${center} A ${outerRadius},${outerRadius} 0 1,1 ${center - outerRadius},${center} A ${outerRadius},${outerRadius} 0 1,1 ${center + outerRadius},${center} Z`;
652
+ return addSvgFields({ path: path2, width: size, height: size, centerX: center, centerY: center });
653
+ }
654
+ const r1 = outerRadius;
655
+ const r2 = innerRadius;
656
+ const x = (d * d + r1 * r1 - r2 * r2) / (2 * d);
657
+ const y = Math.sqrt(Math.max(0, r1 * r1 - x * x));
658
+ const ix1 = center + x;
659
+ const iy1 = center - y;
660
+ const iy2 = center + y;
661
+ const path = [
662
+ `M ${ix1.toFixed(2)},${iy1.toFixed(2)}`,
663
+ // Outer arc from top to bottom (going left/counter-clockwise)
664
+ `A ${r1},${r1} 0 1,0 ${ix1.toFixed(2)},${iy2.toFixed(2)}`,
665
+ // Inner arc from bottom to top (going right/clockwise) - note: arc from inner circle
666
+ `A ${r2},${r2} 0 0,0 ${ix1.toFixed(2)},${iy1.toFixed(2)}`,
667
+ "Z"
668
+ ].join(" ");
669
+ return addSvgFields({
670
+ path,
671
+ width: size,
672
+ height: size,
673
+ centerX: center,
674
+ centerY: center
675
+ });
676
+ }
677
+
678
+ // src/generators/curved/oval.ts
679
+ function oval(params) {
680
+ const { width, height } = params;
681
+ const rx = width / 2;
682
+ const ry = height / 2;
683
+ return addSvgFields({
684
+ path: ellipsePath(rx, ry, rx, ry),
685
+ width,
686
+ height,
687
+ centerX: rx,
688
+ centerY: ry
689
+ });
690
+ }
691
+
692
+ // src/generators/curved/semicircle.ts
693
+ function semicircle(params) {
694
+ const { radius, arcAngle, rotation, closed } = params;
695
+ const startAngle = degToRad(rotation - arcAngle / 2);
696
+ const endAngle = degToRad(rotation + arcAngle / 2);
697
+ const startX = Math.cos(startAngle) * radius + radius;
698
+ const startY = Math.sin(startAngle) * radius + radius;
699
+ const endX = Math.cos(endAngle) * radius + radius;
700
+ const endY = Math.sin(endAngle) * radius + radius;
701
+ const largeArc = arcAngle > 180 ? 1 : 0;
702
+ let path;
703
+ if (closed) {
704
+ path = `M ${radius},${radius} L ${startX},${startY} A ${radius},${radius} 0 ${largeArc},1 ${endX},${endY} Z`;
705
+ } else {
706
+ path = `M ${startX},${startY} A ${radius},${radius} 0 ${largeArc},1 ${endX},${endY} Z`;
707
+ }
708
+ return addSvgFields({
709
+ path,
710
+ width: radius * 2,
711
+ height: radius * 2,
712
+ centerX: radius,
713
+ centerY: radius
714
+ });
715
+ }
716
+
717
+ // src/generators/angular/arrow.ts
718
+ function arrow(params) {
719
+ const { length, headWidth, headLength, tailWidth, direction } = params;
720
+ let path;
721
+ let width;
722
+ let height;
723
+ if (tailWidth <= 0) {
724
+ path = buildTriangleArrow(headWidth, headLength, direction);
725
+ if (direction === "up" || direction === "down") {
726
+ width = headWidth;
727
+ height = headLength;
728
+ } else {
729
+ width = headLength;
730
+ height = headWidth;
731
+ }
732
+ } else {
733
+ path = buildFullArrow(length, headWidth, headLength, tailWidth, direction);
734
+ if (direction === "up" || direction === "down") {
735
+ width = headWidth;
736
+ height = length;
737
+ } else {
738
+ width = length;
739
+ height = headWidth;
740
+ }
741
+ }
742
+ return addSvgFields({
743
+ path,
744
+ width,
745
+ height,
746
+ centerX: width / 2,
747
+ centerY: height / 2
748
+ });
749
+ }
750
+ function buildTriangleArrow(headW, headL, dir) {
751
+ const half = headW / 2;
752
+ switch (dir) {
753
+ case "up":
754
+ return `M ${half},0 L ${headW},${headL} L 0,${headL} Z`;
755
+ case "down":
756
+ return `M 0,0 L ${headW},0 L ${half},${headL} Z`;
757
+ case "left":
758
+ return `M 0,${half} L ${headL},0 L ${headL},${headW} Z`;
759
+ case "right":
760
+ return `M 0,0 L ${headL},${half} L 0,${headW} Z`;
761
+ default:
762
+ return buildTriangleArrow(headW, headL, "right");
763
+ }
764
+ }
765
+ function buildFullArrow(len, headW, headL, tailW, dir) {
766
+ const halfHead = headW / 2;
767
+ const halfTail = tailW / 2;
768
+ const tailLen = len - headL;
769
+ switch (dir) {
770
+ case "right":
771
+ return `M 0,${halfHead - halfTail} L ${tailLen},${halfHead - halfTail} L ${tailLen},0 L ${len},${halfHead} L ${tailLen},${headW} L ${tailLen},${halfHead + halfTail} L 0,${halfHead + halfTail} Z`;
772
+ case "left":
773
+ return `M ${len},${halfHead - halfTail} L ${headL},${halfHead - halfTail} L ${headL},0 L 0,${halfHead} L ${headL},${headW} L ${headL},${halfHead + halfTail} L ${len},${halfHead + halfTail} Z`;
774
+ case "up":
775
+ return `M ${halfHead - halfTail},${len} L ${halfHead - halfTail},${headL} L 0,${headL} L ${halfHead},0 L ${headW},${headL} L ${halfHead + halfTail},${headL} L ${halfHead + halfTail},${len} Z`;
776
+ case "down":
777
+ return `M ${halfHead - halfTail},0 L ${halfHead + halfTail},0 L ${halfHead + halfTail},${tailLen} L ${headW},${tailLen} L ${halfHead},${len} L 0,${tailLen} L ${halfHead - halfTail},${tailLen} Z`;
778
+ default:
779
+ return buildFullArrow(len, headW, headL, tailW, "right");
780
+ }
781
+ }
782
+
783
+ // src/generators/angular/bowtie.ts
784
+ function bowtie(params) {
785
+ const { width, height, pinchAmount } = params;
786
+ const halfW = width / 2;
787
+ const halfH = height / 2;
788
+ const pinchGap = halfH * (1 - pinchAmount);
789
+ const path = [
790
+ `M 0,${halfH}`,
791
+ // Left point (middle)
792
+ `L ${halfW},${halfH - pinchGap}`,
793
+ // Top of pinch
794
+ `L ${width},0`,
795
+ // Top right corner
796
+ `L ${width},${height}`,
797
+ // Bottom right corner
798
+ `L ${halfW},${halfH + pinchGap}`,
799
+ // Bottom of pinch
800
+ `L 0,${halfH}`,
801
+ // Back to left (close)
802
+ "Z"
803
+ ].join(" ");
804
+ return addSvgFields({
805
+ path,
806
+ width,
807
+ height,
808
+ centerX: halfW,
809
+ centerY: halfH
810
+ });
811
+ }
812
+
813
+ // src/generators/angular/chevron.ts
814
+ function chevron(params) {
815
+ const { width, height, thickness, direction } = params;
816
+ let path;
817
+ if (thickness <= 0) {
818
+ path = buildSimpleChevron(width, height, direction);
819
+ } else {
820
+ path = buildThickChevron(width, height, thickness, direction);
821
+ }
822
+ return addSvgFields({
823
+ path,
824
+ width,
825
+ height,
826
+ centerX: width / 2,
827
+ centerY: height / 2
828
+ });
829
+ }
830
+ function buildSimpleChevron(w, h, dir) {
831
+ switch (dir) {
832
+ case "up":
833
+ return `M 0,${h} L ${w / 2},0 L ${w},${h}`;
834
+ case "down":
835
+ return `M 0,0 L ${w / 2},${h} L ${w},0`;
836
+ case "left":
837
+ return `M ${w},0 L 0,${h / 2} L ${w},${h}`;
838
+ case "right":
839
+ return `M 0,0 L ${w},${h / 2} L 0,${h}`;
840
+ default:
841
+ return `M 0,${h} L ${w / 2},0 L ${w},${h}`;
842
+ }
843
+ }
844
+ function buildThickChevron(w, h, t, dir) {
845
+ const halfW = w / 2;
846
+ switch (dir) {
847
+ case "up":
848
+ return `M 0,${h} L ${halfW},${t} L ${w},${h} L ${w - t},${h} L ${halfW},${t * 2} L ${t},${h} Z`;
849
+ case "down":
850
+ return `M 0,0 L ${t},0 L ${halfW},${h - t * 2} L ${w - t},0 L ${w},0 L ${halfW},${h} Z`;
851
+ case "left":
852
+ return `M ${w},0 L ${w},${t} L ${t * 2},${h / 2} L ${w},${h - t} L ${w},${h} L 0,${h / 2} Z`;
853
+ case "right":
854
+ return `M 0,0 L ${w},${h / 2} L 0,${h} L 0,${h - t} L ${w - t * 2},${h / 2} L 0,${t} Z`;
855
+ default:
856
+ return buildThickChevron(w, h, t, "up");
857
+ }
858
+ }
859
+
860
+ // src/generators/angular/cross.ts
861
+ function cross(params) {
862
+ const { size, armWidth, armRatio } = params;
863
+ const halfSize = size / 2;
864
+ const halfArm = armWidth / 2;
865
+ const armLength = halfSize * armRatio;
866
+ const path = [
867
+ // Top arm
868
+ `M ${halfSize - halfArm},${halfSize - armLength}`,
869
+ `L ${halfSize + halfArm},${halfSize - armLength}`,
870
+ // Top right corner to right arm
871
+ `L ${halfSize + halfArm},${halfSize - halfArm}`,
872
+ `L ${halfSize + armLength},${halfSize - halfArm}`,
873
+ // Right arm
874
+ `L ${halfSize + armLength},${halfSize + halfArm}`,
875
+ // Bottom right corner
876
+ `L ${halfSize + halfArm},${halfSize + halfArm}`,
877
+ // Bottom arm
878
+ `L ${halfSize + halfArm},${halfSize + armLength}`,
879
+ `L ${halfSize - halfArm},${halfSize + armLength}`,
880
+ // Bottom left corner
881
+ `L ${halfSize - halfArm},${halfSize + halfArm}`,
882
+ // Left arm
883
+ `L ${halfSize - armLength},${halfSize + halfArm}`,
884
+ `L ${halfSize - armLength},${halfSize - halfArm}`,
885
+ // Top left corner back to start
886
+ `L ${halfSize - halfArm},${halfSize - halfArm}`,
887
+ "Z"
888
+ ].join(" ");
889
+ return addSvgFields({
890
+ path,
891
+ width: size,
892
+ height: size,
893
+ centerX: halfSize,
894
+ centerY: halfSize
895
+ });
896
+ }
897
+
898
+ // src/generators/angular/cursor.ts
899
+ function cursor(params) {
900
+ const { width, height } = params;
901
+ const path = [
902
+ `M 0,0`,
903
+ // Top point
904
+ `L ${width},${height * 0.65}`,
905
+ // Right side
906
+ `L ${width * 0.5},${height * 0.55}`,
907
+ // Notch point (inward)
908
+ `L ${width * 0.35},${height}`,
909
+ // Bottom right of stem
910
+ `L 0,${height * 0.75}`,
911
+ // Left edge
912
+ "Z"
913
+ ].join(" ");
914
+ return addSvgFields({
915
+ path,
916
+ width,
917
+ height,
918
+ centerX: width / 3,
919
+ centerY: height / 2
920
+ });
921
+ }
922
+
923
+ // src/generators/angular/diamond.ts
924
+ function diamond(params) {
925
+ const { width, height, bulge, asymmetry = 0 } = params;
926
+ const b = Math.max(0, Math.min(1, bulge));
927
+ const asym = Math.max(-0.5, Math.min(0.5, asymmetry));
928
+ const cx = width / 2;
929
+ const cy = height / 2;
930
+ const top = { x: cx, y: 0 };
931
+ const bottom = { x: cx, y: height };
932
+ const left = { x: 0, y: cy };
933
+ const right = { x: width, y: cy };
934
+ const verticalFactor = 0.4 + b * 0.15;
935
+ const vOffset = cy * verticalFactor;
936
+ const horizontalBulge = b * 0.35;
937
+ const leftBulge = horizontalBulge * (1 - asym);
938
+ const rightBulge = horizontalBulge * (1 + asym);
939
+ const tr1 = { x: cx + cx * 0.2, y: vOffset };
940
+ const tr2 = { x: width + width * rightBulge, y: cy - vOffset };
941
+ const rb1 = { x: width + width * rightBulge, y: cy + vOffset };
942
+ const rb2 = { x: cx + cx * 0.2, y: height - vOffset };
943
+ const bl1 = { x: cx - cx * 0.2, y: height - vOffset };
944
+ const bl2 = { x: -(width * leftBulge), y: cy + vOffset };
945
+ const lt1 = { x: -(width * leftBulge), y: cy - vOffset };
946
+ const lt2 = { x: cx - cx * 0.2, y: vOffset };
947
+ const path = [
948
+ `M ${top.x},${top.y}`,
949
+ // Top to right (upper-right curve)
950
+ `C ${tr1.x},${tr1.y} ${tr2.x},${tr2.y} ${right.x},${right.y}`,
951
+ // Right to bottom (lower-right curve)
952
+ `C ${rb1.x},${rb1.y} ${rb2.x},${rb2.y} ${bottom.x},${bottom.y}`,
953
+ // Bottom to left (lower-left curve)
954
+ `C ${bl1.x},${bl1.y} ${bl2.x},${bl2.y} ${left.x},${left.y}`,
955
+ // Left to top (upper-left curve)
956
+ `C ${lt1.x},${lt1.y} ${lt2.x},${lt2.y} ${top.x},${top.y}`,
957
+ "Z"
958
+ ].join(" ");
959
+ return addSvgFields({
960
+ path,
961
+ width,
962
+ height,
963
+ centerX: cx,
964
+ centerY: cy
965
+ });
966
+ }
967
+
968
+ // src/generators/angular/polygon.ts
969
+ function polygon(params) {
970
+ const { sides, radius, rotation } = params;
971
+ const vertices = [];
972
+ const angleStep = 360 / sides;
973
+ const rotationOffset = rotation - 90;
974
+ for (let i = 0; i < sides; i++) {
975
+ const angle = degToRad(i * angleStep + rotationOffset);
976
+ vertices.push({
977
+ x: Math.cos(angle) * radius + radius,
978
+ y: Math.sin(angle) * radius + radius
979
+ });
980
+ }
981
+ return addSvgFields({
982
+ path: pointsToPath(vertices, true),
983
+ width: radius * 2,
984
+ height: radius * 2,
985
+ centerX: radius,
986
+ centerY: radius
987
+ });
988
+ }
989
+ function hexagon(params) {
990
+ return polygon({ sides: 6, ...params });
991
+ }
992
+ function pentagon(params) {
993
+ return polygon({ sides: 5, ...params });
994
+ }
995
+ function octagon(params) {
996
+ return polygon({ sides: 8, ...params });
997
+ }
998
+
999
+ // src/generators/angular/rectangle.ts
1000
+ function rectangle(params) {
1001
+ const { width, height, cornerRadius } = params;
1002
+ const r = Math.min(cornerRadius, width / 2, height / 2);
1003
+ let path;
1004
+ if (r === 0) {
1005
+ path = `M 0,0 L ${width},0 L ${width},${height} L 0,${height} Z`;
1006
+ } else {
1007
+ path = `M ${r},0 L ${width - r},0 A ${r},${r} 0 0,1 ${width},${r} L ${width},${height - r} A ${r},${r} 0 0,1 ${width - r},${height} L ${r},${height} A ${r},${r} 0 0,1 0,${height - r} L 0,${r} A ${r},${r} 0 0,1 ${r},0 Z`;
1008
+ }
1009
+ return addSvgFields({
1010
+ path,
1011
+ width,
1012
+ height,
1013
+ centerX: width / 2,
1014
+ centerY: height / 2
1015
+ });
1016
+ }
1017
+
1018
+ // src/generators/angular/swallowtail.ts
1019
+ function swallowtail(params) {
1020
+ const { width, height, notchDepth, notchCurvature } = params;
1021
+ const notchX = width * (1 - notchDepth);
1022
+ const halfHeight = height / 2;
1023
+ let path;
1024
+ if (notchCurvature < 0.2) {
1025
+ path = `M 0,0 L ${width},0 L ${notchX},${halfHeight} L ${width},${height} L 0,${height} Z`;
1026
+ } else {
1027
+ const cpX = notchX + (width - notchX) * notchCurvature * 0.5;
1028
+ path = `M 0,0 L ${width},0 Q ${cpX},${halfHeight} ${width},${height} L 0,${height} Z`;
1029
+ }
1030
+ return addSvgFields({
1031
+ path,
1032
+ width,
1033
+ height,
1034
+ centerX: width / 2,
1035
+ centerY: halfHeight
1036
+ });
1037
+ }
1038
+
1039
+ // src/generators/angular/triangle.ts
1040
+ function triangle(params) {
1041
+ const { width, height, skew } = params;
1042
+ const halfWidth = width / 2;
1043
+ const apexX = halfWidth + skew * halfWidth;
1044
+ const path = `M 0,${height} L ${width},${height} L ${apexX},0 Z`;
1045
+ return addSvgFields({
1046
+ path,
1047
+ width,
1048
+ height,
1049
+ centerX: width / 2,
1050
+ centerY: height / 2
1051
+ });
1052
+ }
1053
+
1054
+ // src/generators/radial/atomic.ts
1055
+ function atomic(params) {
1056
+ const { orbitCount, orbitRadius, orbitEccentricity, nucleusSize, orbitThickness } = params;
1057
+ const size = orbitRadius * 2;
1058
+ const center = orbitRadius;
1059
+ const a = orbitRadius;
1060
+ const b = orbitRadius * (1 - orbitEccentricity);
1061
+ const parts = [];
1062
+ if (nucleusSize > 0) {
1063
+ parts.push(`M ${center + nucleusSize},${center} A ${nucleusSize},${nucleusSize} 0 1,1 ${center - nucleusSize},${center} A ${nucleusSize},${nucleusSize} 0 1,1 ${center + nucleusSize},${center}`);
1064
+ }
1065
+ const angleStep = 180 / orbitCount;
1066
+ for (let i = 0; i < orbitCount; i++) {
1067
+ const rotation = i * angleStep;
1068
+ const rotRad = degToRad(rotation);
1069
+ const innerA = Math.max(1, a - orbitThickness);
1070
+ const innerB = Math.max(1, b - orbitThickness);
1071
+ const outerPath = createRotatedEllipse(center, center, a, b, rotRad);
1072
+ if (orbitThickness > 0) {
1073
+ const innerPath = createRotatedEllipse(center, center, innerA, innerB, rotRad, true);
1074
+ parts.push(outerPath + " " + innerPath);
1075
+ } else {
1076
+ parts.push(outerPath);
1077
+ }
1078
+ }
1079
+ return addSvgFields({
1080
+ path: parts.join(" "),
1081
+ width: size,
1082
+ height: size,
1083
+ centerX: center,
1084
+ centerY: center
1085
+ });
1086
+ }
1087
+ function createRotatedEllipse(cx, cy, a, b, rotation, reverse = false) {
1088
+ const cos = Math.cos(rotation);
1089
+ const sin = Math.sin(rotation);
1090
+ const points = [];
1091
+ const segments = 36;
1092
+ for (let i = 0; i < segments; i++) {
1093
+ const t = i / segments * 2 * Math.PI;
1094
+ const ex = a * Math.cos(t);
1095
+ const ey = b * Math.sin(t);
1096
+ const rx = ex * cos - ey * sin;
1097
+ const ry = ex * sin + ey * cos;
1098
+ points.push({ x: cx + rx, y: cy + ry });
1099
+ }
1100
+ if (reverse) {
1101
+ points.reverse();
1102
+ }
1103
+ let path = `M ${points[0].x.toFixed(2)},${points[0].y.toFixed(2)}`;
1104
+ for (let i = 1; i < points.length; i++) {
1105
+ path += ` L ${points[i].x.toFixed(2)},${points[i].y.toFixed(2)}`;
1106
+ }
1107
+ path += " Z";
1108
+ return path;
1109
+ }
1110
+
1111
+ // src/generators/radial/flower.ts
1112
+ function flower(params) {
1113
+ const { petalCount, petalLength, petalWidth, centerSize, petalPointedness } = params;
1114
+ const size = (centerSize + petalLength) * 2;
1115
+ const center = size / 2;
1116
+ const parts = [];
1117
+ const angleStep = 360 / petalCount;
1118
+ for (let i = 0; i < petalCount; i++) {
1119
+ const angle = i * angleStep - 90;
1120
+ const angleRad = degToRad(angle);
1121
+ const halfWidth = petalWidth / 2;
1122
+ const baseAngle1 = degToRad(angle - 15);
1123
+ const baseAngle2 = degToRad(angle + 15);
1124
+ const base1X = center + Math.cos(baseAngle1) * centerSize;
1125
+ const base1Y = center + Math.sin(baseAngle1) * centerSize;
1126
+ const base2X = center + Math.cos(baseAngle2) * centerSize;
1127
+ const base2Y = center + Math.sin(baseAngle2) * centerSize;
1128
+ const tipX = center + Math.cos(angleRad) * (centerSize + petalLength);
1129
+ const tipY = center + Math.sin(angleRad) * (centerSize + petalLength);
1130
+ const perpAngle = angleRad + Math.PI / 2;
1131
+ const midRadius = centerSize + petalLength * 0.5;
1132
+ const cp1X = center + Math.cos(angleRad) * midRadius - Math.cos(perpAngle) * halfWidth;
1133
+ const cp1Y = center + Math.sin(angleRad) * midRadius - Math.sin(perpAngle) * halfWidth;
1134
+ const cp2X = center + Math.cos(angleRad) * midRadius + Math.cos(perpAngle) * halfWidth;
1135
+ const cp2Y = center + Math.sin(angleRad) * midRadius + Math.sin(perpAngle) * halfWidth;
1136
+ if (petalPointedness > 0.5) {
1137
+ parts.push(`M ${base1X.toFixed(2)},${base1Y.toFixed(2)}`);
1138
+ parts.push(`Q ${cp1X.toFixed(2)},${cp1Y.toFixed(2)} ${tipX.toFixed(2)},${tipY.toFixed(2)}`);
1139
+ parts.push(`Q ${cp2X.toFixed(2)},${cp2Y.toFixed(2)} ${base2X.toFixed(2)},${base2Y.toFixed(2)}`);
1140
+ parts.push("Z");
1141
+ } else {
1142
+ parts.push(`M ${base1X.toFixed(2)},${base1Y.toFixed(2)}`);
1143
+ parts.push(`C ${cp1X.toFixed(2)},${cp1Y.toFixed(2)} ${tipX.toFixed(2)},${tipY - halfWidth * 0.5} ${tipX.toFixed(2)},${tipY.toFixed(2)}`);
1144
+ parts.push(`C ${tipX.toFixed(2)},${tipY + halfWidth * 0.5} ${cp2X.toFixed(2)},${cp2Y.toFixed(2)} ${base2X.toFixed(2)},${base2Y.toFixed(2)}`);
1145
+ parts.push("Z");
1146
+ }
1147
+ }
1148
+ if (centerSize > 0) {
1149
+ parts.push(`M ${center + centerSize},${center}`);
1150
+ parts.push(`A ${centerSize},${centerSize} 0 1,1 ${center - centerSize},${center}`);
1151
+ parts.push(`A ${centerSize},${centerSize} 0 1,1 ${center + centerSize},${center}`);
1152
+ }
1153
+ return addSvgFields({
1154
+ path: parts.join(" "),
1155
+ width: size,
1156
+ height: size,
1157
+ centerX: center,
1158
+ centerY: center
1159
+ });
1160
+ }
1161
+
1162
+ // src/generators/radial/spiral.ts
1163
+ function spiral(params) {
1164
+ const { turns, startRadius, expansionRate, thickness, direction } = params;
1165
+ const totalAngle = turns * 360;
1166
+ const steps = Math.ceil(totalAngle / 5);
1167
+ const endRadius = startRadius + turns * expansionRate;
1168
+ const size = (endRadius + thickness) * 2;
1169
+ const center = size / 2;
1170
+ const points = [];
1171
+ for (let i = 0; i <= steps; i++) {
1172
+ const angle = i / steps * totalAngle * direction;
1173
+ const progress = i / steps;
1174
+ const radius = startRadius + progress * turns * expansionRate;
1175
+ const rad = degToRad(angle - 90);
1176
+ points.push({
1177
+ x: center + Math.cos(rad) * radius,
1178
+ y: center + Math.sin(rad) * radius
1179
+ });
1180
+ }
1181
+ let path;
1182
+ if (thickness <= 0) {
1183
+ path = points.map(
1184
+ (p, i) => (i === 0 ? "M" : "L") + ` ${p.x.toFixed(2)},${p.y.toFixed(2)}`
1185
+ ).join(" ");
1186
+ } else {
1187
+ const innerPoints = [];
1188
+ const outerPoints = [];
1189
+ for (let i = 0; i <= steps; i++) {
1190
+ const angle = i / steps * totalAngle * direction;
1191
+ const progress = i / steps;
1192
+ const radius = startRadius + progress * turns * expansionRate;
1193
+ const halfThick = thickness / 2;
1194
+ const rad = degToRad(angle - 90);
1195
+ innerPoints.push({
1196
+ x: center + Math.cos(rad) * (radius - halfThick),
1197
+ y: center + Math.sin(rad) * (radius - halfThick)
1198
+ });
1199
+ outerPoints.push({
1200
+ x: center + Math.cos(rad) * (radius + halfThick),
1201
+ y: center + Math.sin(rad) * (radius + halfThick)
1202
+ });
1203
+ }
1204
+ const outerPath = outerPoints.map(
1205
+ (p, i) => (i === 0 ? "M" : "L") + ` ${p.x.toFixed(2)},${p.y.toFixed(2)}`
1206
+ ).join(" ");
1207
+ const innerPath = innerPoints.reverse().map(
1208
+ (p) => `L ${p.x.toFixed(2)},${p.y.toFixed(2)}`
1209
+ ).join(" ");
1210
+ path = outerPath + " " + innerPath + " Z";
1211
+ }
1212
+ return addSvgFields({
1213
+ path,
1214
+ width: size,
1215
+ height: size,
1216
+ centerX: center,
1217
+ centerY: center
1218
+ });
1219
+ }
1220
+
1221
+ // src/generators/radial/star.ts
1222
+ function star(params) {
1223
+ const { points, rotation } = params;
1224
+ const maxRadius = Math.max(params.innerRadius, params.outerRadius);
1225
+ const minRadius = Math.min(params.innerRadius, params.outerRadius);
1226
+ const outerRadius = maxRadius;
1227
+ const innerRadius = minRadius;
1228
+ const vertices = [];
1229
+ const totalVertices = points * 2;
1230
+ const angleStep = 360 / totalVertices;
1231
+ const rotationRad = degToRad(rotation - 90);
1232
+ for (let i = 0; i < totalVertices; i++) {
1233
+ const angle = degToRad(i * angleStep) + rotationRad;
1234
+ const radius = i % 2 === 0 ? outerRadius : innerRadius;
1235
+ vertices.push({
1236
+ x: Math.cos(angle) * radius,
1237
+ y: Math.sin(angle) * radius
1238
+ });
1239
+ }
1240
+ const offset = outerRadius;
1241
+ const offsetVertices = vertices.map((v) => ({
1242
+ x: v.x + offset,
1243
+ y: v.y + offset
1244
+ }));
1245
+ return addSvgFields({
1246
+ path: pointsToPath(offsetVertices, true),
1247
+ width: outerRadius * 2,
1248
+ height: outerRadius * 2,
1249
+ centerX: offset,
1250
+ centerY: offset
1251
+ });
1252
+ }
1253
+
1254
+ // src/generators/radial/starburst.ts
1255
+ function starburst(params) {
1256
+ const { rayCount, rayThickness, taper } = params;
1257
+ const outerRadius = Math.max(params.innerRadius, params.outerRadius);
1258
+ const innerRadius = Math.min(params.innerRadius, params.outerRadius);
1259
+ let fullPath = "";
1260
+ const angleStep = 360 / rayCount;
1261
+ const effectiveRadius = outerRadius + rayThickness / 2;
1262
+ const offset = effectiveRadius;
1263
+ for (let i = 0; i < rayCount; i++) {
1264
+ const angle = degToRad(i * angleStep - 90);
1265
+ const halfThicknessInner = rayThickness / 2;
1266
+ const halfThicknessOuter = halfThicknessInner * (1 - taper);
1267
+ const perpAngle = angle + Math.PI / 2;
1268
+ const innerLeft = {
1269
+ x: Math.cos(angle) * innerRadius + Math.cos(perpAngle) * halfThicknessInner + offset,
1270
+ y: Math.sin(angle) * innerRadius + Math.sin(perpAngle) * halfThicknessInner + offset
1271
+ };
1272
+ const innerRight = {
1273
+ x: Math.cos(angle) * innerRadius - Math.cos(perpAngle) * halfThicknessInner + offset,
1274
+ y: Math.sin(angle) * innerRadius - Math.sin(perpAngle) * halfThicknessInner + offset
1275
+ };
1276
+ const outerLeft = {
1277
+ x: Math.cos(angle) * outerRadius + Math.cos(perpAngle) * halfThicknessOuter + offset,
1278
+ y: Math.sin(angle) * outerRadius + Math.sin(perpAngle) * halfThicknessOuter + offset
1279
+ };
1280
+ const outerRight = {
1281
+ x: Math.cos(angle) * outerRadius - Math.cos(perpAngle) * halfThicknessOuter + offset,
1282
+ y: Math.sin(angle) * outerRadius - Math.sin(perpAngle) * halfThicknessOuter + offset
1283
+ };
1284
+ fullPath += pointsToPath([innerLeft, outerLeft, outerRight, innerRight], true) + " ";
1285
+ }
1286
+ return addSvgFields({
1287
+ path: fullPath.trim(),
1288
+ width: effectiveRadius * 2,
1289
+ height: effectiveRadius * 2,
1290
+ centerX: offset,
1291
+ centerY: offset
1292
+ });
1293
+ }
1294
+
1295
+ // src/generators/radial/sun.ts
1296
+ function sun(params) {
1297
+ const { discRadius, rayCount, rayLength, rayWidth, rayTaper } = params;
1298
+ const totalRadius = discRadius + rayLength;
1299
+ const effectiveRadius = totalRadius + rayWidth / 2;
1300
+ const size = effectiveRadius * 2;
1301
+ const center = size / 2;
1302
+ const parts = [];
1303
+ const angleStep = 360 / rayCount;
1304
+ for (let i = 0; i < rayCount; i++) {
1305
+ const angle = i * angleStep - 90;
1306
+ const angleRad = degToRad(angle);
1307
+ const halfBase = rayWidth / 2;
1308
+ const halfTip = halfBase * (1 - rayTaper);
1309
+ const perpRad = angleRad + Math.PI / 2;
1310
+ const baseX = center + Math.cos(angleRad) * discRadius;
1311
+ const baseY = center + Math.sin(angleRad) * discRadius;
1312
+ const tipX = center + Math.cos(angleRad) * totalRadius;
1313
+ const tipY = center + Math.sin(angleRad) * totalRadius;
1314
+ const baseLeftX = baseX + Math.cos(perpRad) * halfBase;
1315
+ const baseLeftY = baseY + Math.sin(perpRad) * halfBase;
1316
+ const baseRightX = baseX - Math.cos(perpRad) * halfBase;
1317
+ const baseRightY = baseY - Math.sin(perpRad) * halfBase;
1318
+ const tipLeftX = tipX + Math.cos(perpRad) * halfTip;
1319
+ const tipLeftY = tipY + Math.sin(perpRad) * halfTip;
1320
+ const tipRightX = tipX - Math.cos(perpRad) * halfTip;
1321
+ const tipRightY = tipY - Math.sin(perpRad) * halfTip;
1322
+ if (rayTaper >= 0.95) {
1323
+ parts.push(`M ${baseLeftX.toFixed(2)},${baseLeftY.toFixed(2)} L ${tipX.toFixed(2)},${tipY.toFixed(2)} L ${baseRightX.toFixed(2)},${baseRightY.toFixed(2)} Z`);
1324
+ } else {
1325
+ parts.push(`M ${baseLeftX.toFixed(2)},${baseLeftY.toFixed(2)} L ${tipLeftX.toFixed(2)},${tipLeftY.toFixed(2)} L ${tipRightX.toFixed(2)},${tipRightY.toFixed(2)} L ${baseRightX.toFixed(2)},${baseRightY.toFixed(2)} Z`);
1326
+ }
1327
+ }
1328
+ parts.push(`M ${center + discRadius},${center} A ${discRadius},${discRadius} 0 1,1 ${center - discRadius},${center} A ${discRadius},${discRadius} 0 1,1 ${center + discRadius},${center}`);
1329
+ return addSvgFields({
1330
+ path: parts.join(" "),
1331
+ width: size,
1332
+ height: size,
1333
+ centerX: center,
1334
+ centerY: center
1335
+ });
1336
+ }
1337
+
1338
+ // src/generators/silhouettes/bird.ts
1339
+ var TRACED_PATHS = {
1340
+ // From 0022_004.svg - Bird in flight with spread wings (166x104 viewBox)
1341
+ flying: {
1342
+ path: `M0 0 C3.62 -0.06 7.25 -0.09 10.88 -0.13 C11.89 -0.14 12.9 -0.16 13.95 -0.18 C27.1 -0.26 39.18 2.37 49.25 11.44 C54.47 17.05 57.66 24.18 61 31 C63.61 29.69 63.7 28.62 64.75 25.94 C69.27 15.5 76.68 8 87.25 3.63 C92.1 1.8 96.68 0.88 101.87 0.87 C102.8 0.87 103.74 0.86 104.71 0.86 C106.21 0.86 106.21 0.86 107.73 0.87 C109.29 0.87 109.29 0.87 110.87 0.86 C113.05 0.86 115.22 0.87 117.4 0.87 C120.75 0.88 124.1 0.87 127.45 0.86 C129.57 0.86 131.68 0.87 133.8 0.87 C135.31 0.86 135.31 0.86 136.85 0.86 C138.24 0.87 138.24 0.87 139.65 0.87 C140.88 0.87 140.88 0.87 142.13 0.87 C144 1 144 1 145 2 C145.11 13.16 140.33 22.51 132.81 30.56 C129 34.28 124.75 36.66 120 39 C119.25 39.38 118.5 39.75 117.73 40.14 C117.16 40.42 116.59 40.71 116 41 C118.44 43.87 120.87 45.52 124.19 47.19 C134.06 52.52 140.24 60.7 143.74 71.23 C144.73 74.83 145.34 78.27 145 82 C143.44 83.56 141.94 83.15 139.78 83.18 C138.88 83.19 137.98 83.2 137.05 83.22 C135.58 83.23 135.58 83.23 134.08 83.24 C133.07 83.25 132.06 83.25 131.01 83.26 C128.86 83.28 126.71 83.29 124.56 83.3 C121.31 83.31 118.05 83.36 114.8 83.4 C98.5 83.52 85.63 82.43 73 71 C70.73 68.48 68.83 65.86 67 63 C66.59 62.39 66.18 61.79 65.75 61.16 C64.82 59.79 63.91 58.4 63 57 C62.01 57.5 62.01 57.5 61 58 C61.01 58.72 61.01 59.44 61.02 60.19 C61.04 63.44 61.05 66.69 61.06 69.94 C61.07 71.07 61.08 72.21 61.09 73.38 C61.09 74.46 61.09 75.54 61.1 76.65 C61.1 77.65 61.11 78.65 61.11 79.68 C61 82 61 82 60 83 C49.72 83.86 40.78 79.2 32.94 72.88 C24.73 65.46 20.88 55.86 20 45 C19.95 42.8 19.91 40.61 19.89 38.41 C19.88 37.21 19.86 36.02 19.85 34.78 C19.82 32.31 19.82 29.83 19.83 27.35 C19.69 19.45 18.66 13.79 13 8 C8.7 5.09 3.96 3.49 -1 2 C-0.67 1.34 -0.34 0.68 0 0 Z`,
1343
+ viewBox: { width: 166, height: 104 },
1344
+ translate: { x: 11, y: 10 }
1345
+ },
1346
+ // From 0044_006.svg - Bird perched/sitting (165x181 viewBox)
1347
+ perched: {
1348
+ path: `M0 0 C-1.43 4.39 -3.59 7.07 -6.73 10.42 C-7.22 10.94 -7.7 11.45 -8.19 11.98 C-14.39 18.56 -20.83 24.9 -27.25 31.25 C-37.95 41.82 -37.95 41.82 -48 53 C-49.8 55.01 -51.62 57.01 -53.44 59 C-54.3 59.95 -55.17 60.9 -56.06 61.88 C-56.7 62.58 -57.34 63.28 -58 64 C-57.67 64.66 -57.34 65.32 -57 66 C-53 66.09 -53 66.09 -49 66 C-48.67 65.67 -48.34 65.34 -48 65 C-40.54 64.64 -40.54 64.64 -37 67 C-35.33 66.35 -33.66 65.68 -32 65 C-29.16 64.73 -26.47 64.57 -23.63 64.56 C-22.86 64.56 -22.09 64.55 -21.31 64.55 C-17.21 64.64 -14.31 64.74 -11.06 67.5 C-6.76 71.01 -3.33 70.42 2 70 C5.46 70 7.74 70.83 11 72 C11.97 72.27 11.97 72.27 12.96 72.55 C18.52 74.28 21.97 76.99 25 82 C25.88 85.44 25.88 85.44 26 88 C25.01 88 24.02 88 23 88 C19.17 88.21 16.78 88.36 13.78 90.82 C10.66 96.39 11.84 102.53 12.16 108.75 C12.38 116.09 11.59 122.47 8 129 C6 130.98 3.94 132.66 1.71 134.38 C-0.36 136.07 -0.36 136.07 -1.13 139.75 C-1.28 143.15 -1.28 143.15 1 146 C3.54 147.09 6.02 148.04 8.63 148.94 C14.3 150.97 19.69 153.12 25 156 C23 159 23 159 20.64 159.51 C19.18 159.6 19.18 159.6 17.69 159.69 C16.74 159.75 15.8 159.82 14.82 159.89 C4.07 160.21 -6.42 159.78 -17.13 158.69 C-17.8 158.62 -18.48 158.55 -19.18 158.48 C-50.54 155.31 -92.47 150.85 -115 126 C-119.26 119.07 -120 112.02 -118.42 104.09 C-114.56 89.96 -106.68 77.84 -97 67 C-96.34 66.23 -95.68 65.46 -95 64.67 C-83.8 51.86 -71.76 40 -58 30 C-56.98 29.26 -56.98 29.26 -55.95 28.5 C-11.57 -3.77 -11.57 -3.77 0 0 Z`,
1349
+ viewBox: { width: 165, height: 181 },
1350
+ translate: { x: 130, y: 11 }
1351
+ },
1352
+ // From 0044_014.svg - Simple stylized bird (83x83 viewBox)
1353
+ simple: {
1354
+ path: `M0 0 C4.89 3.46 6.97 7.09 8.56 12.81 C7.9 13.14 7.24 13.47 6.56 13.81 C5.98 13.61 5.41 13.4 4.81 13.19 C1.38 12.61 -0.54 14.05 -3.44 15.81 C-5.72 19.23 -5.65 20.3 -5.53 24.29 C-5.5 25.92 -5.5 25.92 -5.47 27.57 C-5.41 29.84 -5.34 32.1 -5.27 34.37 C-5.11 43.64 -6.53 50.34 -12.44 57.81 C-16.22 61.15 -19.9 61.33 -24.76 61.15 C-35.86 59.74 -44.59 52.73 -51.29 44.11 C-56.17 37.61 -56.17 37.61 -57.44 33.81 C-53.5 33.81 -52.44 35.39 -49.44 37.81 C-47.51 38.96 -47.51 38.96 -45.44 38.81 C-40.21 36.2 -39.13 31.96 -37.39 26.75 C-37.08 25.78 -36.76 24.81 -36.44 23.81 C-33.08 14.3 -29.39 5.9 -20.37 0.69 C-14.06 -2.17 -6.48 -2.24 0 0 Z`,
1355
+ viewBox: { width: 83, height: 83 },
1356
+ translate: { x: 65.4375, y: 11.1875 }
1357
+ }
1358
+ };
1359
+ function bird(params) {
1360
+ const { size, style } = params;
1361
+ const traced = TRACED_PATHS[style];
1362
+ const maxDimension = Math.max(traced.viewBox.width, traced.viewBox.height);
1363
+ const scale = size / maxDimension;
1364
+ const actualWidth = traced.viewBox.width * scale;
1365
+ const actualHeight = traced.viewBox.height * scale;
1366
+ const normalizedPath = normalizeAndScalePath(traced.path, traced.translate, scale);
1367
+ return addSvgFields({
1368
+ path: normalizedPath,
1369
+ width: actualWidth,
1370
+ height: actualHeight,
1371
+ centerX: actualWidth / 2,
1372
+ centerY: actualHeight / 2
1373
+ });
1374
+ }
1375
+ function normalizeAndScalePath(path, translate, scale) {
1376
+ return path.replace(
1377
+ /(-?\d+\.?\d*)\s+(-?\d+\.?\d*)/g,
1378
+ (_, x, y) => {
1379
+ const newX = (parseFloat(x) + translate.x) * scale;
1380
+ const newY = (parseFloat(y) + translate.y) * scale;
1381
+ return `${newX.toFixed(2)} ${newY.toFixed(2)}`;
1382
+ }
1383
+ );
1384
+ }
1385
+
1386
+ // src/generators/silhouettes/cat.ts
1387
+ var TRACED_PATHS2 = {
1388
+ // From 0026_007.svg - Standing cat silhouette (109x216 viewBox)
1389
+ sitting: {
1390
+ path: `M0 0 C0.99 0.66 1.98 1.32 3 2 C2.88 2.81 2.76 3.62 2.64 4.45 C1.59 11 1.59 11 3.94 16.88 C4.62 17.58 5.3 18.28 6 19 C6.69 21.94 6.69 21.94 6 25 C2.35 29.67 -2.21 31.74 -7.78 33.34 C-10.98 34.29 -13.95 35.64 -17 37 C-16.52 51.05 -13.13 63.42 -8 76.38 C-3.31 88.21 0.25 100.43 0.63 113.25 C0.88 115.42 0.88 115.42 4 117 C5.04 113.88 5.14 111.68 5.16 108.4 C5.17 106.68 5.17 106.68 5.19 104.92 C5.2 103.68 5.2 102.43 5.21 101.15 C5.23 99.19 5.25 97.23 5.27 95.28 C5.33 90.45 5.37 85.62 5.4 80.8 C5.42 78.09 5.44 75.39 5.48 72.68 C5.51 70.14 5.53 67.59 5.53 65.05 C5.65 56.73 6.34 49.12 10.94 42 C13.49 39.52 15.54 38.1 19.15 37.85 C24.98 38.41 28.14 39.47 32 44 C33.01 46.92 33.05 48.81 33 52 C31.81 54.06 31.81 54.06 30 55 C28 55.06 28 55.06 26 54 C24.25 50.94 24.25 50.94 23 48 C19.07 48.57 19.07 48.57 16 51 C15.68 54.01 15.48 56.92 15.38 59.94 C15.34 60.87 15.3 61.8 15.26 62.75 C14.86 73.64 14.92 84.52 14.98 95.41 C15.07 112.58 15.13 129.77 14.79 146.94 C14.76 148.45 14.74 149.97 14.73 151.48 C14.59 164.94 12.21 176.71 3 187 C-3.63 192.93 -14.68 197.14 -23.5 197.5 C-29.91 196.58 -33.61 194.01 -37.56 189.06 C-54.37 165.01 -53.77 127.39 -48.98 99.77 C-47.06 89.86 -43.71 80.61 -39.88 71.31 C-35.96 61.8 -32.76 51.02 -32.94 40.63 C-32.96 39.43 -32.98 38.23 -33 37 C-38.07 34.75 -43.18 32.88 -48.45 31.16 C-52.4 29.36 -54.53 27.24 -56.06 23.19 C-55.99 19.62 -55.64 19.3 -53.44 16.75 C-51.5 14.38 -50.96 13.51 -51.18 10.4 C-51.59 8.63 -52.06 6.88 -52.58 5.14 C-52.79 4.08 -52.79 4.08 -53 3 C-52.34 2.34 -51.68 1.68 -51 1 C-47.62 1.33 -46.03 2.74 -43.61 5.01 C-37.98 9.36 -32.06 8.95 -25.19 8.88 C-23.98 8.91 -22.77 8.95 -21.53 9 C-12.18 8.99 -6.9 6.21 0 0 Z`,
1391
+ viewBox: { width: 109, height: 216 },
1392
+ translate: { x: 66, y: 9 }
1393
+ },
1394
+ // From 0042_002.svg - Cat in profile/walking pose (191x425 viewBox)
1395
+ walking: {
1396
+ path: `M0 0 C10.29 7.63 13.75 19.98 17.54 31.72 C19.71 38.31 19.71 38.31 24.78 42.72 C26.37 43.35 26.37 43.35 28 44 C25.14 63.94 6.86 83.15 -8.39 94.83 C-13.4 98.45 -18.48 101.42 -24.07 104.05 C-25.96 104.85 -25.96 104.85 -27 106 C-27.35 115.76 -23.74 124.93 -20.63 134 C-20.23 135.18 -20.23 135.18 -19.82 136.39 C-15.15 150.18 -9.94 163.69 -4.23 177.1 C-3.07 179.84 -1.92 182.6 -0.78 185.36 C2.18 192.5 5.23 199.58 8.56 206.56 C22.5 236.07 30.23 268.33 30.1 300.98 C30.1 302.4 30.09 303.82 30.09 305.24 C30.09 308.94 30.08 312.65 30.07 316.35 C30.06 320.15 30.05 323.94 30.05 327.74 C30.04 335.16 30.02 342.58 30 350 C30.99 350 31.98 350 33 350 C37.81 337.57 42.15 325.32 44.59 312.2 C44.89 310.6 45.2 309.01 45.53 307.41 C52.34 273.03 40.61 236.94 27.92 205.3 C12.07 165.59 12.07 165.59 15 156 C16.51 153.98 17.47 153.17 19.88 152.42 C31.37 151.17 41.43 154.96 52 159 C52 159.99 52 160.98 52 162 C45.25 162.14 38.69 161.76 31.98 161.02 C28.67 161 26.8 161.2 24 163 C22.32 167.81 23.4 171.25 25.06 175.94 C25.29 176.6 25.53 177.26 25.77 177.94 C27.49 182.79 29.4 187.57 31.35 192.34 C53.2 246.42 67.82 301.72 44 358 C43.59 359.04 43.18 360.07 42.75 361.14 C37.54 374.09 31.19 386.75 18 393 C16.93 393.59 16.93 393.59 15.84 394.2 C-9.5 407.94 -43.12 406.72 -70.25 399.19 C-80.09 395.81 -89.3 389.36 -94.08 379.85 C-95.24 376.26 -95.33 372.91 -95.3 369.19 C-95.3 368.41 -95.29 367.63 -95.29 366.83 C-95.12 357.19 -93.87 347.67 -92.6 138.12 C-92.19 335.01 -91.79 331.89 -91.4 328.77 C-87.11 295.21 -87.11 295.21 -82.44 279.88 C-82.1 278.74 -81.75 277.6 -81.4 276.43 C-72.57 247.97 -58.92 221.89 -40.31 198.61 C-31.53 187.6 -25.93 177.42 -26.77 163 C-27.39 157.55 -29.44 152.37 -31.23 147.23 C-32.64 143.14 -33.92 139.01 -35.19 134.88 C-35.45 134.03 -35.7 133.19 -35.97 132.32 C-37.82 126.06 -38.97 119.96 -39.68 113.46 C-39.74 111.06 -39.74 111.06 -41 110 C-46.91 109.46 -52.68 109.66 -57.69 113.19 C-59.23 115.17 -59.23 115.17 -60.5 118.5 C-62.52 123.21 -62.52 123.21 -65 125 C-65.56 125.08 -66.13 125.17 -66.71 125.25 C-70.15 126.37 -72.56 128.72 -75.25 131.06 C-75.8 131.53 -76.36 132.01 -76.93 132.49 C-78.29 133.66 -79.65 134.83 -81 136 C-81.99 135.01 -81.99 135.01 -83 134 C-81.02 131.69 -79.04 129.38 -77 127 C-77.66 126.01 -78.32 125.02 -79 124 C-74.27 119.62 -69.73 115.98 -64 113 C-64.33 112.34 -64.66 111.68 -65 111 C-67.39 110.59 -69.71 110.29 -72.13 110.06 C-77.9 109.42 -83.61 108.62 -89.31 107.5 C-90.53 107.26 -91.74 107.03 -92.99 106.78 C-96 106 -96 106 -99 104 C-98.77 103.41 -98.55 102.81 -98.32 102.2 C-97.12 98.21 -96.38 95.33 -98.18 91.45 C-99.4 89.66 -100.65 87.88 -101.92 86.11 C-107.93 77.12 -112.45 65.7 -114 55 C-112.43 53.43 -110.91 53.81 -108.73 53.79 C-102.42 53.85 -96.46 55.1 -90.31 56.44 C-86.21 57.3 -82.11 58.16 -78 59 C-77.27 59.16 -76.55 59.32 -75.8 59.49 C-73.05 60.02 -71.49 60.29 -69.02 58.85 C-68.48 58.26 -67.94 57.67 -67.38 57.06 C-56.55 46.69 -41.79 40.39 -27.49 36.28 C-22.82 35.01 -22.82 35.01 -19.27 31.92 C-18.85 30.96 -18.43 29.99 -18 29 C-17.19 27.48 -16.37 25.96 -15.55 24.45 C-14.15 21.86 -12.76 19.26 -11.38 16.66 C-8.11 10.62 -4.37 5.29 0 0 Z`,
1397
+ viewBox: { width: 191, height: 425 },
1398
+ translate: { x: 124, y: 10 }
1399
+ },
1400
+ // From 0055_023.svg - Cat stretching/arched (185x253 viewBox)
1401
+ stretching: {
1402
+ path: `M0 0 C2.13 1.13 2.13 1.13 4 3 C6.45 11.19 4.54 20.53 2.27 28.57 C1.92 31.71 2.76 32.85 4.5 35.44 C6.3 38.45 6.99 39.67 7.06 43.25 C5.86 46.37 4.09 48.42 2 51 C2.33 51.99 2.66 52.98 3 54 C3.93 54.31 4.86 54.62 5.81 54.94 C9 56 9 56 10.94 58.06 C13.76 60.72 16.23 60.64 20 61 C20.33 61.33 20.66 61.66 21 62 C22.83 62.25 24.67 62.47 26.5 62.69 C35.09 64.07 41.4 68.28 46.78 75.09 C51.31 82.18 52.09 90.02 50.31 98.13 C48.09 102.99 45.69 106.78 41.31 109.94 C36.73 111.41 32.75 112.05 28 111 C23.76 108.36 20.76 105.14 18 101 C15.5 100.58 15.5 100.58 13 101 C12.34 101.66 11.68 102.32 11 103 C11.38 108.48 12.54 113.64 13.94 118.94 C14.64 121.62 15.33 124.31 16 127 C16.18 127.72 16.36 128.44 16.55 129.18 C20.51 145.81 20.84 165.17 11.69 180.15 C7.45 186.15 2.1 190.94 -4 195 C-4.85 198.03 -4.85 198.03 -5.38 201.56 C-7.2 210.73 -10.22 217.46 -17.57 223.43 C-32.9 233.32 -55.4 233.2 -72.81 229.81 C-82 227.43 -90.19 223.76 -96 216 C-101.96 205.42 -102.48 193.3 -99.75 181.57 C-95.52 166.1 -88.12 154.19 -80 141.5 C-69.62 125.26 -59.92 108.81 -59.81 88.94 C-59.8 87.75 -59.78 86.56 -59.77 85.34 C-60 82 -60.24 79.85 -62 77 C-64.51 75.88 -64.51 75.88 -67.5 75.44 C-85.46 71.58 -99.68 61.6 -111.38 47.61 C-113.18 44.7 -113.52 43.35 -113 40 C-111.71 37.97 -110.38 35.97 -109 34 C-107.78 31.22 -107.9 30.3 -108.88 27.38 C-111.66 19.03 -112.21 9.22 -109 1 C-103.32 0.46 -99.75 2.23 -94.88 4.81 C-94.17 5.17 -93.47 5.53 -92.75 5.89 C-89.88 7.37 -87.26 8.8 -84.7 10.77 C-82.94 12.31 -82.94 12.31 -79.94 11.88 C-76.76 11.26 -73.67 10.37 -70.56 9.5 C-65.98 8.22 -61.74 7.38 -57 7 C-56.35 6.95 -55.7 6.89 -55.04 6.84 C-46.71 6.48 -37.64 8.28 -29.86 11.16 C-25.74 12.37 -23.36 11.73 -19.64 9.73 C-18.85 9.22 -18.06 8.71 -17.25 8.19 C-11.75 4.77 -6.15 2.05 0 0 Z`,
1403
+ viewBox: { width: 185, height: 253 },
1404
+ translate: { x: 124, y: 10 }
1405
+ }
1406
+ };
1407
+ function cat(params) {
1408
+ const { size, style } = params;
1409
+ const traced = TRACED_PATHS2[style];
1410
+ const maxDimension = Math.max(traced.viewBox.width, traced.viewBox.height);
1411
+ const scale = size / maxDimension;
1412
+ const actualWidth = traced.viewBox.width * scale;
1413
+ const actualHeight = traced.viewBox.height * scale;
1414
+ const normalizedPath = normalizeAndScalePath2(traced.path, traced.translate, scale);
1415
+ return addSvgFields({
1416
+ path: normalizedPath,
1417
+ width: actualWidth,
1418
+ height: actualHeight,
1419
+ centerX: actualWidth / 2,
1420
+ centerY: actualHeight / 2
1421
+ });
1422
+ }
1423
+ function normalizeAndScalePath2(path, translate, scale) {
1424
+ return path.replace(
1425
+ /(-?\d+\.?\d*)\s+(-?\d+\.?\d*)/g,
1426
+ (_, x, y) => {
1427
+ const newX = (parseFloat(x) + translate.x) * scale;
1428
+ const newY = (parseFloat(y) + translate.y) * scale;
1429
+ return `${newX.toFixed(2)} ${newY.toFixed(2)}`;
1430
+ }
1431
+ );
1432
+ }
1433
+
1434
+ // src/generators/silhouettes/dog.ts
1435
+ function dog(params) {
1436
+ const { size, style } = params;
1437
+ const scale = size / 100;
1438
+ let basePath;
1439
+ switch (style) {
1440
+ case "running":
1441
+ basePath = `M 10,50 C 5,45 5,35 15,30 L 25,20 C 30,15 35,20 35,25 L 40,30 C 50,25 60,25 70,30 L 80,25 C 85,22 90,28 85,35 L 90,40 C 95,45 95,55 90,60 L 95,75 L 85,75 L 80,60 L 70,65 L 65,80 L 55,80 L 60,65 L 40,65 L 35,80 L 25,80 L 30,65 L 20,60 L 10,75 L 5,70 L 15,55 C 10,55 5,55 10,50 Z M 25,35 C 27,35 28,37 28,39 C 28,41 27,42 25,42 C 23,42 22,41 22,39 C 22,37 23,35 25,35 Z`;
1442
+ break;
1443
+ case "sitting":
1444
+ basePath = `M 50,15 C 40,15 35,25 40,35 L 35,35 C 30,35 28,40 32,45 L 25,50 C 20,55 20,70 25,80 L 25,95 L 40,95 L 40,85 C 45,82 55,82 60,85 L 60,95 L 75,95 L 75,80 C 80,70 80,55 75,50 L 68,45 C 72,40 70,35 65,35 L 60,35 C 65,25 60,15 50,15 Z M 42,30 C 44,30 45,32 45,34 C 45,36 44,38 42,38 C 40,38 39,36 39,34 C 39,32 40,30 42,30 Z M 58,30 C 60,30 61,32 61,34 C 61,36 60,38 58,38 C 56,38 55,36 55,34 C 55,32 56,30 58,30 Z`;
1445
+ break;
1446
+ case "standing":
1447
+ default:
1448
+ basePath = `M 15,40 C 10,35 10,25 20,20 L 25,10 C 28,5 35,10 33,18 L 40,25 C 55,20 70,25 80,35 L 90,30 C 95,28 98,35 93,40 L 95,50 C 98,60 95,70 90,75 L 90,90 L 80,90 L 80,75 L 70,75 L 70,90 L 60,90 L 60,75 L 40,75 L 40,90 L 30,90 L 30,75 L 20,75 L 20,90 L 10,90 L 10,75 C 5,70 5,55 15,45 Z M 25,30 C 27,30 28,32 28,34 C 28,36 27,38 25,38 C 23,38 22,36 22,34 C 22,32 23,30 25,30 Z`;
1449
+ }
1450
+ const path = scalePath(basePath, scale);
1451
+ return addSvgFields({
1452
+ path,
1453
+ width: size,
1454
+ height: size,
1455
+ centerX: size / 2,
1456
+ centerY: size / 2
1457
+ });
1458
+ }
1459
+ function scalePath(path, scale) {
1460
+ return path.replace(/([\d.]+),([\d.]+)/g, (_, x, y) => {
1461
+ return `${(parseFloat(x) * scale).toFixed(2)},${(parseFloat(y) * scale).toFixed(2)}`;
1462
+ });
1463
+ }
1464
+
1465
+ // src/generators/silhouettes/fish.ts
1466
+ var TRACED_PATHS3 = {
1467
+ // From 0057_017.svg - Tropical/detailed fish (169x134 viewBox) - main silhouette shape
1468
+ tropical: {
1469
+ path: `M0 0 C0.79 -0 1.58 -0.01 2.39 -0.01 C9.57 0.05 16.08 1.05 22.5 4.31 C23.3 4.47 24.11 4.63 24.93 4.79 C36.56 7.15 46.43 17.19 52.89 26.7 C54.87 29.86 56.74 33.03 58.5 36.31 C59.43 38.02 59.43 38.02 60.39 39.75 C63.19 45.43 65.13 51.46 67.13 57.46 C67.82 59.51 68.52 61.55 69.23 63.6 C69.67 64.91 70.11 66.23 70.55 67.54 C70.95 68.72 71.35 69.9 71.76 71.12 C72.51 74.34 72.44 76.18 71.5 79.31 C46.89 86.28 14.65 85.14 -8.13 72.9 C-12.51 70.2 -15.57 67.52 -18.14 63.02 C-19.54 61.06 -19.54 61.06 -22.38 59.59 C-26.31 56.72 -27.74 53.89 -29.75 49.56 C-30.09 48.88 -30.43 48.21 -30.77 47.51 C-35.11 38.53 -37.19 29.37 -34.31 19.63 C-31.37 11.81 -25.78 7.11 -18.5 3.31 C-12.27 0.68 -6.72 -0.14 0 0 Z`,
1470
+ viewBox: { width: 129, height: 104 },
1471
+ translate: { x: 45.5, y: 9.6875 }
1472
+ },
1473
+ // From 0005_004.svg - Simple fish shape (115x46 viewBox)
1474
+ simple: {
1475
+ path: `M0 0 C0.8 0.11 1.6 0.22 2.42 0.34 C4.93 0.69 7.43 1.06 9.94 1.44 C10.71 1.55 11.49 1.66 12.29 1.77 C14.21 2.08 16.11 2.53 18 3 C18.99 4.48 18.99 4.48 20 6 C19 7 19 7 16.23 7.03 C15.04 7 13.85 6.97 12.63 6.94 C6.18 6.88 0.27 7.57 -6 9 C-6 9.99 -6 10.98 -6 12 C-1.16 14.55 3.49 14.23 8.81 14.13 C10.14 14.11 10.14 14.11 11.49 14.1 C13.66 14.07 15.83 14.04 18 14 C18 14.99 18 15.98 18 17 C14.99 18.69 12.45 19.38 9.04 19.82 C8.08 19.94 7.12 20.06 6.13 20.19 C5.12 20.31 4.11 20.44 3.06 20.56 C2.02 20.69 0.97 20.82 -0.11 20.95 C-3.07 21.31 -6.03 21.66 -9 22 C-10.19 22.14 -11.37 22.27 -12.6 22.41 C-34.59 24.49 -58.75 25.32 -77 11 C-75.96 7.84 -74.96 6.98 -72.09 5.18 C-49.24 -6.03 -24.56 -3.65 0 0 Z`,
1476
+ viewBox: { width: 115, height: 46 },
1477
+ translate: { x: 86, y: 12 }
1478
+ },
1479
+ // From 0017_003.svg - Koi/curved fish shape (130x77 viewBox)
1480
+ koi: {
1481
+ path: `M0 0 C0.83 -0.02 1.65 -0.03 2.5 -0.05 C9.21 0.07 14.46 1.87 19.52 6.35 C24.99 13.78 26.51 22.44 25.5 31.56 C24.54 36.47 23.23 39.75 19.88 43.5 C8.35 50.54 -5.42 47.39 -17.98 45.3 C-23.15 44.44 -28.27 43.84 -33.5 43.56 C-34.64 43.47 -35.78 43.39 -36.96 43.3 C-44.03 42.97 -48.8 43.26 -54.46 47.7 C-57.93 50.87 -61.29 54.12 -64.5 57.56 C-65.16 56.9 -65.82 56.24 -66.5 55.56 C-62.54 49.62 -58.58 43.68 -54.5 37.56 C-56.86 32.84 -57.85 32.63 -62.6 30.77 C-63.81 30.28 -65.03 29.8 -66.27 29.3 C-67.56 28.8 -68.84 28.31 -70.13 27.81 C-71.42 27.3 -72.71 26.79 -74 26.28 C-77.16 25.03 -80.33 23.79 -83.5 22.56 C-83.5 21.57 -83.5 20.58 -83.5 19.56 C-82.84 19.58 -82.17 19.59 -81.49 19.61 C-63.01 19.99 -50.8 18.47 -34.48 9.7 C-23.13 3.65 -12.96 0.19 0 0 Z`,
1482
+ viewBox: { width: 130, height: 77 },
1483
+ translate: { x: 94.5, y: 10.4375 }
1484
+ }
1485
+ };
1486
+ function fish(params) {
1487
+ const { size, style } = params;
1488
+ const traced = TRACED_PATHS3[style];
1489
+ const maxDimension = Math.max(traced.viewBox.width, traced.viewBox.height);
1490
+ const scale = size / maxDimension;
1491
+ const actualWidth = traced.viewBox.width * scale;
1492
+ const actualHeight = traced.viewBox.height * scale;
1493
+ const normalizedPath = normalizeAndScalePath3(traced.path, traced.translate, scale);
1494
+ return addSvgFields({
1495
+ path: normalizedPath,
1496
+ width: actualWidth,
1497
+ height: actualHeight,
1498
+ centerX: actualWidth / 2,
1499
+ centerY: actualHeight / 2
1500
+ });
1501
+ }
1502
+ function normalizeAndScalePath3(path, translate, scale) {
1503
+ return path.replace(
1504
+ /(-?\d+\.?\d*)\s+(-?\d+\.?\d*)/g,
1505
+ (_, x, y) => {
1506
+ const newX = (parseFloat(x) + translate.x) * scale;
1507
+ const newY = (parseFloat(y) + translate.y) * scale;
1508
+ return `${newX.toFixed(2)} ${newY.toFixed(2)}`;
1509
+ }
1510
+ );
1511
+ }
1512
+
1513
+ // src/generators/silhouettes/leaf.ts
1514
+ var TRACED_PATHS4 = {
1515
+ // From 0016_020.svg - Oval/simple leaf shape (61x136 viewBox)
1516
+ oval: {
1517
+ path: `M0 0 C3.88 3.57 6.56 7.18 9 11.88 C9.34 12.53 9.68 13.18 10.04 13.85 C21.05 35.48 24.35 62.76 17.32 86.18 C13.41 97.84 8.26 108.05 1 118 C-12.5 105.38 -18.61 82.92 -19.28 65.03 C-19.8 41.42 -14.64 21.9 -2 2 C-1.34 1.34 -0.68 0.68 0 0 Z`,
1518
+ viewBox: { width: 61, height: 136 },
1519
+ translate: { x: 30, y: 9 }
1520
+ },
1521
+ // From 0048_016.svg - Pointed/elongated leaf (92x205 viewBox)
1522
+ pointed: {
1523
+ path: `M0 0 C3.27 1.35 4.61 2.47 6.15 5.65 C6.51 6.4 6.87 7.14 7.25 7.92 C7.62 8.73 7.99 9.54 8.38 10.38 C8.77 11.22 9.16 12.06 9.56 12.93 C23.31 43.54 25.37 78.11 13.85 109.79 C12.16 114.18 10.33 118.5 8.44 122.81 C8.06 123.68 7.69 124.55 7.3 125.44 C6.93 126.25 6.56 127.06 6.18 127.89 C5.86 128.61 5.54 129.34 5.2 130.08 C3.79 132.34 2.2 133.53 0 135 C-1.98 132.69 -3.96 130.38 -6 128 C-9.51 131.51 -9.69 133.9 -10.31 138.56 C-12.83 154.7 -18.3 172.36 -29 185 C-32 184 -32 184 -33.07 182.43 C-33.39 181.75 -33.72 181.08 -34.05 180.38 C-34.42 179.62 -34.78 178.86 -35.16 178.07 C-35.54 177.24 -35.92 176.42 -36.31 175.56 C-36.71 174.71 -37.1 173.86 -37.51 172.98 C-44.81 156.92 -50.26 139.73 -51 122 C-51.03 121.37 -51.05 120.73 -51.08 120.08 C-52 95.22 -46.67 69.95 -31 50 C-27.17 51.45 -25.88 53.43 -24 57 C-23.01 56.5 -23.01 56.5 -22 56 C-21.43 54.19 -21.43 54.19 -21.11 51.98 C-20.96 51.15 -20.81 50.32 -20.66 49.46 C-20.5 48.57 -20.35 47.67 -20.19 46.75 C-18.02 35.21 -14.15 25.15 -9 14.63 C-8.68 13.97 -8.36 13.32 -8.03 12.64 C-5.73 8.1 -3.04 4.08 0 0 Z`,
1524
+ viewBox: { width: 92, height: 205 },
1525
+ translate: { x: 61, y: 10 }
1526
+ },
1527
+ // From 0035_033.svg - Broad/dual leaf shape (82x44 viewBox)
1528
+ broad: {
1529
+ path: `M0 0 C1.94 2.44 1.94 2.44 2.5 5.81 C1.63 11.44 -0.6 14.31 -5.06 17.75 C-9.66 20.34 -13.36 20.62 -18.63 20.69 C-20.33 20.73 -20.33 20.73 -22.07 20.77 C-25.06 20.44 -25.06 20.44 -26.96 18.92 C-27.33 18.43 -27.69 17.94 -28.06 17.44 C-27.01 15.18 -25.95 12.93 -24.88 10.69 C-24.58 10.05 -24.29 9.42 -23.99 8.77 C-21.7 4.04 -19.19 0.56 -14.03 -1.29 C-8.93 -1.99 -4.68 -2.39 0 0 Z`,
1530
+ viewBox: { width: 82, height: 44 },
1531
+ translate: { x: 69.0625, y: 12.5625 }
1532
+ }
1533
+ };
1534
+ function leaf(params) {
1535
+ const { size, style } = params;
1536
+ const traced = TRACED_PATHS4[style];
1537
+ const maxDimension = Math.max(traced.viewBox.width, traced.viewBox.height);
1538
+ const scale = size / maxDimension;
1539
+ const actualWidth = traced.viewBox.width * scale;
1540
+ const actualHeight = traced.viewBox.height * scale;
1541
+ const normalizedPath = normalizeAndScalePath4(traced.path, traced.translate, scale);
1542
+ return addSvgFields({
1543
+ path: normalizedPath,
1544
+ width: actualWidth,
1545
+ height: actualHeight,
1546
+ centerX: actualWidth / 2,
1547
+ centerY: actualHeight / 2
1548
+ });
1549
+ }
1550
+ function normalizeAndScalePath4(path, translate, scale) {
1551
+ return path.replace(
1552
+ /(-?\d+\.?\d*)\s+(-?\d+\.?\d*)/g,
1553
+ (_, x, y) => {
1554
+ const newX = (parseFloat(x) + translate.x) * scale;
1555
+ const newY = (parseFloat(y) + translate.y) * scale;
1556
+ return `${newX.toFixed(2)} ${newY.toFixed(2)}`;
1557
+ }
1558
+ );
1559
+ }
1560
+
1561
+ // src/generators/silhouettes/rocket.ts
1562
+ function rocket(params) {
1563
+ const { size, style } = params;
1564
+ const scale = size / 100;
1565
+ let basePath;
1566
+ switch (style) {
1567
+ case "streamlined":
1568
+ basePath = `M 50,5 C 40,10 35,25 35,40 L 20,55 L 25,60 L 35,55 L 35,75 L 40,90 L 45,85 L 50,95 L 55,85 L 60,90 L 65,75 L 65,55 L 75,60 L 80,55 L 65,40 C 65,25 60,10 50,5 Z M 45,30 C 47,30 50,35 50,40 C 50,45 47,50 45,50 C 43,50 40,45 40,40 C 40,35 43,30 45,30 Z`;
1569
+ break;
1570
+ case "chunky":
1571
+ basePath = `M 50,5 C 35,10 30,30 30,50 L 15,60 L 15,75 L 30,70 L 30,80 L 35,95 L 45,85 L 50,95 L 55,85 L 65,95 L 70,80 L 70,70 L 85,75 L 85,60 L 70,50 C 70,30 65,10 50,5 Z M 40,35 L 60,35 L 60,55 L 40,55 Z`;
1572
+ break;
1573
+ case "classic":
1574
+ default:
1575
+ basePath = `M 50,5 C 40,8 38,20 38,35 L 20,50 L 22,60 L 38,52 L 38,75 L 42,95 L 50,80 L 58,95 L 62,75 L 62,52 L 78,60 L 80,50 L 62,35 C 62,20 60,8 50,5 Z M 44,30 C 48,30 52,35 52,42 C 52,49 48,55 44,55 C 40,55 36,49 36,42 C 36,35 40,30 44,30 Z M 50,60 L 45,70 L 50,68 L 55,70 Z`;
1576
+ }
1577
+ const path = scalePath2(basePath, scale);
1578
+ return addSvgFields({
1579
+ path,
1580
+ width: size,
1581
+ height: size,
1582
+ centerX: size / 2,
1583
+ centerY: size / 2
1584
+ });
1585
+ }
1586
+ function scalePath2(path, scale) {
1587
+ return path.replace(/([\d.]+),([\d.]+)/g, (_, x, y) => {
1588
+ return `${(parseFloat(x) * scale).toFixed(2)},${(parseFloat(y) * scale).toFixed(2)}`;
1589
+ });
1590
+ }
1591
+
1592
+ export {
1593
+ boomerang,
1594
+ blob,
1595
+ circle,
1596
+ kidney,
1597
+ moon,
1598
+ oval,
1599
+ semicircle,
1600
+ arrow,
1601
+ bowtie,
1602
+ chevron,
1603
+ cross,
1604
+ cursor,
1605
+ diamond,
1606
+ polygon,
1607
+ hexagon,
1608
+ pentagon,
1609
+ octagon,
1610
+ rectangle,
1611
+ swallowtail,
1612
+ triangle,
1613
+ atomic,
1614
+ flower,
1615
+ spiral,
1616
+ star,
1617
+ starburst,
1618
+ sun,
1619
+ bird,
1620
+ cat,
1621
+ dog,
1622
+ fish,
1623
+ leaf,
1624
+ rocket
1625
+ };
1626
+ //# sourceMappingURL=chunk-5A7FSZ3T.js.map