git-hash-art 0.8.0 → 0.9.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.
package/dist/main.js CHANGED
@@ -1331,35 +1331,32 @@ const $dd5df256f00f6199$export$c2fc138f94dd4b2a = {
1331
1331
  */ const $6222456bc073291c$export$580f80cfb9de73bc = (ctx, size, config)=>{
1332
1332
  const rng = config?.rng ?? Math.random;
1333
1333
  const r = size / 2;
1334
- const numPoints = 5 + Math.floor(rng() * 5); // 5-9 lobes
1334
+ const numPoints = 5 + Math.floor(rng() * 5);
1335
1335
  const points = [];
1336
1336
  for(let i = 0; i < numPoints; i++){
1337
1337
  const angle = i / numPoints * Math.PI * 2;
1338
- const jitter = 0.5 + rng() * 0.5; // radius varies 50-100%
1338
+ const jitter = 0.5 + rng() * 0.5;
1339
1339
  points.push({
1340
1340
  x: Math.cos(angle) * r * jitter,
1341
1341
  y: Math.sin(angle) * r * jitter
1342
1342
  });
1343
1343
  }
1344
1344
  ctx.beginPath();
1345
- // Start at midpoint between last and first point
1346
1345
  const last = points[points.length - 1];
1347
1346
  const first = points[0];
1348
1347
  ctx.moveTo((last.x + first.x) / 2, (last.y + first.y) / 2);
1349
1348
  for(let i = 0; i < numPoints; i++){
1350
1349
  const curr = points[i];
1351
1350
  const next = points[(i + 1) % numPoints];
1352
- const midX = (curr.x + next.x) / 2;
1353
- const midY = (curr.y + next.y) / 2;
1354
- ctx.quadraticCurveTo(curr.x, curr.y, midX, midY);
1351
+ ctx.quadraticCurveTo(curr.x, curr.y, (curr.x + next.x) / 2, (curr.y + next.y) / 2);
1355
1352
  }
1356
1353
  ctx.closePath();
1357
1354
  };
1358
1355
  const $6222456bc073291c$export$7a6094023f0902a6 = (ctx, size, config)=>{
1359
1356
  const rng = config?.rng ?? Math.random;
1360
1357
  const r = size / 2;
1361
- const sides = 3 + Math.floor(rng() * 10); // 3-12 sides
1362
- const jitterAmount = 0.1 + rng() * 0.4; // 10-50% vertex displacement
1358
+ const sides = 3 + Math.floor(rng() * 10);
1359
+ const jitterAmount = 0.1 + rng() * 0.4;
1363
1360
  ctx.beginPath();
1364
1361
  for(let i = 0; i < sides; i++){
1365
1362
  const angle = i / sides * Math.PI * 2 - Math.PI / 2;
@@ -1374,10 +1371,9 @@ const $6222456bc073291c$export$7a6094023f0902a6 = (ctx, size, config)=>{
1374
1371
  const $6222456bc073291c$export$ef56b4a8316e47d5 = (ctx, size, config)=>{
1375
1372
  const rng = config?.rng ?? Math.random;
1376
1373
  const r = size / 2;
1377
- // Frequency ratios small integers produce recognizable patterns
1378
- const freqA = 1 + Math.floor(rng() * 5); // 1-5
1379
- const freqB = 1 + Math.floor(rng() * 5); // 1-5
1380
- const phase = rng() * Math.PI; // phase offset
1374
+ const freqA = 1 + Math.floor(rng() * 5);
1375
+ const freqB = 1 + Math.floor(rng() * 5);
1376
+ const phase = rng() * Math.PI;
1381
1377
  const steps = 120;
1382
1378
  ctx.beginPath();
1383
1379
  for(let i = 0; i <= steps; i++){
@@ -1392,7 +1388,6 @@ const $6222456bc073291c$export$ef56b4a8316e47d5 = (ctx, size, config)=>{
1392
1388
  const $6222456bc073291c$export$1db9219b4f34658c = (ctx, size, config)=>{
1393
1389
  const rng = config?.rng ?? Math.random;
1394
1390
  const r = size / 2;
1395
- // Exponent range: 0.3 (spiky astroid) to 5 (rounded rectangle)
1396
1391
  const n = 0.3 + rng() * 4.7;
1397
1392
  const steps = 120;
1398
1393
  ctx.beginPath();
@@ -1400,7 +1395,6 @@ const $6222456bc073291c$export$1db9219b4f34658c = (ctx, size, config)=>{
1400
1395
  const t = i / steps * Math.PI * 2;
1401
1396
  const cosT = Math.cos(t);
1402
1397
  const sinT = Math.sin(t);
1403
- // Superellipse parametric form
1404
1398
  const x = Math.sign(cosT) * Math.pow(Math.abs(cosT), 2 / n) * r;
1405
1399
  const y = Math.sign(sinT) * Math.pow(Math.abs(sinT), 2 / n) * r;
1406
1400
  if (i === 0) ctx.moveTo(x, y);
@@ -1411,11 +1405,9 @@ const $6222456bc073291c$export$1db9219b4f34658c = (ctx, size, config)=>{
1411
1405
  const $6222456bc073291c$export$b027c64d22b01985 = (ctx, size, config)=>{
1412
1406
  const rng = config?.rng ?? Math.random;
1413
1407
  const scale = size / 2;
1414
- // R = outer radius, r = inner radius, d = pen distance from inner center
1415
1408
  const R = 1;
1416
- const r = 0.2 + rng() * 0.6; // 0.2-0.8
1417
- const d = 0.3 + rng() * 0.7; // 0.3-1.0
1418
- // Number of full rotations needed to close the curve
1409
+ const r = 0.2 + rng() * 0.6;
1410
+ const d = 0.3 + rng() * 0.7;
1419
1411
  const gcd = (a, b)=>{
1420
1412
  const ai = Math.round(a * 1000);
1421
1413
  const bi = Math.round(b * 1000);
@@ -1423,7 +1415,7 @@ const $6222456bc073291c$export$b027c64d22b01985 = (ctx, size, config)=>{
1423
1415
  return g(ai, bi) / 1000;
1424
1416
  };
1425
1417
  const period = r / gcd(R, r);
1426
- const maxT = Math.min(period, 10) * Math.PI * 2; // cap at 10 rotations
1418
+ const maxT = Math.min(period, 10) * Math.PI * 2;
1427
1419
  const steps = Math.min(600, Math.floor(maxT * 20));
1428
1420
  ctx.beginPath();
1429
1421
  for(let i = 0; i <= steps; i++){
@@ -1438,9 +1430,9 @@ const $6222456bc073291c$export$b027c64d22b01985 = (ctx, size, config)=>{
1438
1430
  const $6222456bc073291c$export$7608ccd03bfb705d = (ctx, size, config)=>{
1439
1431
  const rng = config?.rng ?? Math.random;
1440
1432
  const r = size / 2;
1441
- const rings = 2 + Math.floor(rng() * 4); // 2-5 rings
1442
- const freq = 3 + Math.floor(rng() * 12); // 3-14 waves per ring
1443
- const amp = 0.05 + rng() * 0.15; // 5-20% of radius
1433
+ const rings = 2 + Math.floor(rng() * 4);
1434
+ const freq = 3 + Math.floor(rng() * 12);
1435
+ const amp = 0.05 + rng() * 0.15;
1444
1436
  ctx.beginPath();
1445
1437
  for(let ring = 0; ring < rings; ring++){
1446
1438
  const baseR = r * (0.3 + ring / rings * 0.7);
@@ -1458,7 +1450,7 @@ const $6222456bc073291c$export$7608ccd03bfb705d = (ctx, size, config)=>{
1458
1450
  const $6222456bc073291c$export$11a377e7498bb523 = (ctx, size, config)=>{
1459
1451
  const rng = config?.rng ?? Math.random;
1460
1452
  const r = size / 2;
1461
- const k = 2 + Math.floor(rng() * 6); // 2-7 petal parameter
1453
+ const k = 2 + Math.floor(rng() * 6);
1462
1454
  const steps = 200;
1463
1455
  ctx.beginPath();
1464
1456
  for(let i = 0; i <= steps; i++){
@@ -1471,6 +1463,308 @@ const $6222456bc073291c$export$11a377e7498bb523 = (ctx, size, config)=>{
1471
1463
  }
1472
1464
  ctx.closePath();
1473
1465
  };
1466
+ const $6222456bc073291c$export$76b6526575ea179b = (ctx, size, config)=>{
1467
+ const rng = config?.rng ?? Math.random;
1468
+ const r = size / 2;
1469
+ const shardCount = 4 + Math.floor(rng() * 5); // 4-8 shards
1470
+ ctx.beginPath();
1471
+ for(let s = 0; s < shardCount; s++){
1472
+ const baseAngle = s / shardCount * Math.PI * 2 + (rng() - 0.5) * 0.3;
1473
+ const dist = r * (0.15 + rng() * 0.35);
1474
+ const cx = Math.cos(baseAngle) * dist;
1475
+ const cy = Math.sin(baseAngle) * dist;
1476
+ const shardSize = r * (0.2 + rng() * 0.4);
1477
+ const verts = 3 + Math.floor(rng() * 3); // 3-5 vertices per shard
1478
+ const shardAngleOffset = rng() * Math.PI * 2;
1479
+ for(let v = 0; v < verts; v++){
1480
+ const angle = shardAngleOffset + v / verts * Math.PI * 2;
1481
+ // Elongate shards along their radial direction
1482
+ const stretch = v % 2 === 0 ? 1.0 : 0.3 + rng() * 0.4;
1483
+ const px = cx + Math.cos(angle) * shardSize * stretch;
1484
+ const py = cy + Math.sin(angle) * shardSize * stretch;
1485
+ if (v === 0) ctx.moveTo(px, py);
1486
+ else ctx.lineTo(px, py);
1487
+ }
1488
+ ctx.closePath();
1489
+ }
1490
+ };
1491
+ const $6222456bc073291c$export$ed9ff98da5b05073 = (ctx, size, config)=>{
1492
+ const rng = config?.rng ?? Math.random;
1493
+ const r = size / 2;
1494
+ const edgeCount = 5 + Math.floor(rng() * 4); // 5-8 edges
1495
+ const points = [];
1496
+ // Generate edge midpoints at varying distances
1497
+ for(let i = 0; i < edgeCount; i++){
1498
+ const angle = i / edgeCount * Math.PI * 2 + (rng() - 0.5) * 0.4;
1499
+ const dist = r * (0.6 + rng() * 0.4);
1500
+ points.push({
1501
+ angle: angle,
1502
+ x: Math.cos(angle) * dist,
1503
+ y: Math.sin(angle) * dist
1504
+ });
1505
+ }
1506
+ // Sort by angle for proper winding
1507
+ points.sort((a, b)=>a.angle - b.angle);
1508
+ ctx.beginPath();
1509
+ ctx.moveTo(points[0].x, points[0].y);
1510
+ for(let i = 1; i < points.length; i++)ctx.lineTo(points[i].x, points[i].y);
1511
+ ctx.closePath();
1512
+ };
1513
+ const $6222456bc073291c$export$e0452d9a794fe7e5 = (ctx, size, config)=>{
1514
+ const rng = config?.rng ?? Math.random;
1515
+ const r = size / 2;
1516
+ const biteSize = 0.6 + rng() * 0.3; // 60-90% of radius
1517
+ const biteOffset = r * (0.3 + rng() * 0.4);
1518
+ const biteAngle = rng() * Math.PI * 2;
1519
+ // Outer circle
1520
+ ctx.beginPath();
1521
+ ctx.arc(0, 0, r, 0, Math.PI * 2);
1522
+ // Subtract inner circle using even-odd rule
1523
+ const bx = Math.cos(biteAngle) * biteOffset;
1524
+ const by = Math.sin(biteAngle) * biteOffset;
1525
+ // Draw inner circle counter-clockwise for subtraction
1526
+ ctx.moveTo(bx + r * biteSize, by);
1527
+ ctx.arc(bx, by, r * biteSize, 0, Math.PI * 2, true);
1528
+ };
1529
+ const $6222456bc073291c$export$38bfe5eb52137e01 = (ctx, size, config)=>{
1530
+ const rng = config?.rng ?? Math.random;
1531
+ const r = size / 2;
1532
+ const segments = 12 + Math.floor(rng() * 8);
1533
+ const startAngle = rng() * Math.PI * 2;
1534
+ const curvature = (rng() - 0.5) * 0.4;
1535
+ // Build spine points
1536
+ const spine = [];
1537
+ let angle = startAngle;
1538
+ let px = 0, py = 0;
1539
+ for(let i = 0; i <= segments; i++){
1540
+ spine.push({
1541
+ x: px,
1542
+ y: py
1543
+ });
1544
+ const stepLen = r / segments * (1.5 + rng() * 0.5);
1545
+ angle += curvature + (rng() - 0.5) * 0.6;
1546
+ px += Math.cos(angle) * stepLen;
1547
+ py += Math.sin(angle) * stepLen;
1548
+ }
1549
+ // Build tapered outline by offsetting perpendicular to spine
1550
+ ctx.beginPath();
1551
+ const leftSide = [];
1552
+ const rightSide = [];
1553
+ for(let i = 0; i < spine.length; i++){
1554
+ const t = i / (spine.length - 1);
1555
+ const width = r * 0.12 * (1 - t * 0.9); // taper from thick to thin
1556
+ const next = spine[Math.min(i + 1, spine.length - 1)];
1557
+ const dx = next.x - spine[i].x;
1558
+ const dy = next.y - spine[i].y;
1559
+ const len = Math.hypot(dx, dy) || 1;
1560
+ const nx = -dy / len;
1561
+ const ny = dx / len;
1562
+ leftSide.push({
1563
+ x: spine[i].x + nx * width,
1564
+ y: spine[i].y + ny * width
1565
+ });
1566
+ rightSide.push({
1567
+ x: spine[i].x - nx * width,
1568
+ y: spine[i].y - ny * width
1569
+ });
1570
+ }
1571
+ ctx.moveTo(leftSide[0].x, leftSide[0].y);
1572
+ for(let i = 1; i < leftSide.length; i++)ctx.lineTo(leftSide[i].x, leftSide[i].y);
1573
+ for(let i = rightSide.length - 1; i >= 0; i--)ctx.lineTo(rightSide[i].x, rightSide[i].y);
1574
+ ctx.closePath();
1575
+ };
1576
+ const $6222456bc073291c$export$105caa8cfd63c422 = (ctx, size, config)=>{
1577
+ const rng = config?.rng ?? Math.random;
1578
+ const r = size / 2;
1579
+ const lobeCount = 4 + Math.floor(rng() * 4); // 4-7 lobes
1580
+ const spineAngle = rng() * Math.PI * 2;
1581
+ const spineLen = r * 0.6;
1582
+ ctx.beginPath();
1583
+ for(let i = 0; i < lobeCount; i++){
1584
+ const t = i / (lobeCount - 1) - 0.5; // -0.5 to 0.5
1585
+ const sx = Math.cos(spineAngle) * spineLen * t;
1586
+ const sy = Math.sin(spineAngle) * spineLen * t;
1587
+ // Offset perpendicular for cloud shape
1588
+ const perpAngle = spineAngle + Math.PI / 2;
1589
+ const perpOff = (rng() - 0.3) * r * 0.3;
1590
+ const cx = sx + Math.cos(perpAngle) * perpOff;
1591
+ const cy = sy + Math.sin(perpAngle) * perpOff;
1592
+ const lobeR = r * (0.25 + rng() * 0.2);
1593
+ ctx.moveTo(cx + lobeR, cy);
1594
+ ctx.arc(cx, cy, lobeR, 0, Math.PI * 2);
1595
+ }
1596
+ };
1597
+ const $6222456bc073291c$export$e181e5bd3c539569 = (ctx, size, config)=>{
1598
+ const rng = config?.rng ?? Math.random;
1599
+ const r = size / 2;
1600
+ const spikeCount = 8 + Math.floor(rng() * 8); // 8-15 spikes
1601
+ const points = [];
1602
+ for(let i = 0; i < spikeCount; i++){
1603
+ const angle = i / spikeCount * Math.PI * 2;
1604
+ const isSpike = i % 2 === 0;
1605
+ const dist = isSpike ? r * (0.5 + rng() * 0.5 // spikes reach 50-100% of radius
1606
+ ) : r * (0.15 + rng() * 0.2); // valleys at 15-35%
1607
+ points.push({
1608
+ x: Math.cos(angle) * dist,
1609
+ y: Math.sin(angle) * dist
1610
+ });
1611
+ }
1612
+ ctx.beginPath();
1613
+ ctx.moveTo(points[0].x, points[0].y);
1614
+ for(let i = 0; i < points.length; i++){
1615
+ const curr = points[i];
1616
+ const next = points[(i + 1) % points.length];
1617
+ const cpx = (curr.x + next.x) / 2 + (rng() - 0.5) * r * 0.15;
1618
+ const cpy = (curr.y + next.y) / 2 + (rng() - 0.5) * r * 0.15;
1619
+ ctx.quadraticCurveTo(cpx, cpy, next.x, next.y);
1620
+ }
1621
+ ctx.closePath();
1622
+ };
1623
+ const $6222456bc073291c$export$155b4780b4c6bb7b = (ctx, size, config)=>{
1624
+ const rng = config?.rng ?? Math.random;
1625
+ const r = size / 2;
1626
+ const subdivisions = 1 + Math.floor(rng() * 3); // 1-3
1627
+ // Start with icosahedron vertices projected to 2D
1628
+ const baseVerts = 6 + subdivisions * 4;
1629
+ const points = [];
1630
+ for(let i = 0; i < baseVerts; i++){
1631
+ const angle = i / baseVerts * Math.PI * 2;
1632
+ const ring = i % 2 === 0 ? 1.0 : 0.5 + rng() * 0.3;
1633
+ points.push({
1634
+ x: Math.cos(angle) * r * ring,
1635
+ y: Math.sin(angle) * r * ring
1636
+ });
1637
+ }
1638
+ ctx.beginPath();
1639
+ // Draw triangulated mesh — connect each point to neighbors and center
1640
+ for(let i = 0; i < points.length; i++){
1641
+ const next = points[(i + 1) % points.length];
1642
+ ctx.moveTo(points[i].x, points[i].y);
1643
+ ctx.lineTo(next.x, next.y);
1644
+ // Connect to center
1645
+ ctx.moveTo(points[i].x, points[i].y);
1646
+ ctx.lineTo(0, 0);
1647
+ // Cross-connect to create triangulation
1648
+ if (i % 2 === 0 && i + 2 < points.length) {
1649
+ ctx.moveTo(points[i].x, points[i].y);
1650
+ ctx.lineTo(points[i + 2].x, points[i + 2].y);
1651
+ }
1652
+ }
1653
+ // Outer ring
1654
+ ctx.moveTo(points[0].x, points[0].y);
1655
+ for(let i = 1; i < points.length; i++)ctx.lineTo(points[i].x, points[i].y);
1656
+ ctx.closePath();
1657
+ };
1658
+ const $6222456bc073291c$export$9a7e648f11155172 = (ctx, size, config)=>{
1659
+ const rng = config?.rng ?? Math.random;
1660
+ const r = size / 2;
1661
+ const phi = (1 + Math.sqrt(5)) / 2; // golden ratio
1662
+ const isKite = rng() < 0.5;
1663
+ ctx.beginPath();
1664
+ if (isKite) {
1665
+ // Kite: two golden triangles joined at base
1666
+ const topY = -r;
1667
+ const bottomY = r * (1 / phi);
1668
+ const midY = r * (1 / phi - 1) * 0.3;
1669
+ const wingX = r * 0.6;
1670
+ ctx.moveTo(0, topY);
1671
+ ctx.lineTo(wingX, midY);
1672
+ ctx.lineTo(0, bottomY);
1673
+ ctx.lineTo(-wingX, midY);
1674
+ } else {
1675
+ // Dart: concave quadrilateral
1676
+ const topY = -r;
1677
+ const bottomY = r * 0.3;
1678
+ const midY = -r * 0.1;
1679
+ const wingX = r * 0.5;
1680
+ ctx.moveTo(0, topY);
1681
+ ctx.lineTo(wingX, midY);
1682
+ ctx.lineTo(0, bottomY);
1683
+ ctx.lineTo(-wingX, midY);
1684
+ }
1685
+ ctx.closePath();
1686
+ };
1687
+ const $6222456bc073291c$export$1fc0aedbabd73399 = (ctx, size, config)=>{
1688
+ const r = size / 2;
1689
+ // Vertices of equilateral triangle
1690
+ const verts = [];
1691
+ for(let i = 0; i < 3; i++){
1692
+ const angle = i / 3 * Math.PI * 2 - Math.PI / 2;
1693
+ verts.push({
1694
+ x: Math.cos(angle) * r * 0.7,
1695
+ y: Math.sin(angle) * r * 0.7
1696
+ });
1697
+ }
1698
+ // Side length = distance between vertices
1699
+ const sideLen = Math.hypot(verts[1].x - verts[0].x, verts[1].y - verts[0].y);
1700
+ ctx.beginPath();
1701
+ for(let i = 0; i < 3; i++){
1702
+ const from = verts[(i + 1) % 3];
1703
+ const to = verts[(i + 2) % 3];
1704
+ const center = verts[i];
1705
+ const startAngle = Math.atan2(from.y - center.y, from.x - center.x);
1706
+ const endAngle = Math.atan2(to.y - center.y, to.x - center.x);
1707
+ if (i === 0) ctx.moveTo(from.x, from.y);
1708
+ ctx.arc(center.x, center.y, sideLen, startAngle, endAngle);
1709
+ }
1710
+ ctx.closePath();
1711
+ };
1712
+ const $6222456bc073291c$export$ef7b5e0c19a21fd1 = (ctx, size, config)=>{
1713
+ const rng = config?.rng ?? Math.random;
1714
+ const r = size / 2;
1715
+ const dotCount = 15 + Math.floor(rng() * 25); // 15-39 dots
1716
+ const clusterTightness = 0.3 + rng() * 0.5;
1717
+ ctx.beginPath();
1718
+ for(let i = 0; i < dotCount; i++){
1719
+ // Gaussian-ish distribution via Box-Muller approximation
1720
+ const u1 = Math.max(0.001, rng());
1721
+ const u2 = rng();
1722
+ const mag = Math.sqrt(-2 * Math.log(u1)) * clusterTightness;
1723
+ const angle = u2 * Math.PI * 2;
1724
+ const dx = Math.cos(angle) * mag * r;
1725
+ const dy = Math.sin(angle) * mag * r;
1726
+ const dotR = r * (0.02 + rng() * 0.04);
1727
+ ctx.moveTo(dx + dotR, dy);
1728
+ ctx.arc(dx, dy, dotR, 0, Math.PI * 2);
1729
+ }
1730
+ };
1731
+ const $6222456bc073291c$export$f15df8ab60dfcc9a = (ctx, size, config)=>{
1732
+ const rng = config?.rng ?? Math.random;
1733
+ const r = size / 2;
1734
+ const angle1 = rng() * Math.PI;
1735
+ const angle2 = angle1 + Math.PI / 2 + (rng() - 0.5) * 0.3;
1736
+ const spacing = r * (0.08 + rng() * 0.08);
1737
+ const hasCross = rng() < 0.6;
1738
+ // Draw bounding shape (ellipse)
1739
+ const rx = r * (0.7 + rng() * 0.3);
1740
+ const ry = r * (0.5 + rng() * 0.3);
1741
+ // Outer boundary
1742
+ ctx.beginPath();
1743
+ ctx.ellipse(0, 0, rx, ry, 0, 0, Math.PI * 2);
1744
+ // Hatch lines clipped to the ellipse
1745
+ const cos1 = Math.cos(angle1);
1746
+ const sin1 = Math.sin(angle1);
1747
+ for(let d = -r; d <= r; d += spacing){
1748
+ const lx1 = d * cos1 - r * sin1;
1749
+ const ly1 = d * sin1 + r * cos1;
1750
+ const lx2 = d * cos1 + r * sin1;
1751
+ const ly2 = d * sin1 - r * cos1;
1752
+ ctx.moveTo(lx1, ly1);
1753
+ ctx.lineTo(lx2, ly2);
1754
+ }
1755
+ if (hasCross) {
1756
+ const cos2 = Math.cos(angle2);
1757
+ const sin2 = Math.sin(angle2);
1758
+ for(let d = -r; d <= r; d += spacing * 1.3){
1759
+ const lx1 = d * cos2 - r * sin2;
1760
+ const ly1 = d * sin2 + r * cos2;
1761
+ const lx2 = d * cos2 + r * sin2;
1762
+ const ly2 = d * sin2 - r * cos2;
1763
+ ctx.moveTo(lx1, ly1);
1764
+ ctx.lineTo(lx2, ly2);
1765
+ }
1766
+ }
1767
+ };
1474
1768
  const $6222456bc073291c$export$40cfb4c637f2fbb5 = {
1475
1769
  blob: $6222456bc073291c$export$580f80cfb9de73bc,
1476
1770
  ngon: $6222456bc073291c$export$7a6094023f0902a6,
@@ -1478,7 +1772,18 @@ const $6222456bc073291c$export$40cfb4c637f2fbb5 = {
1478
1772
  superellipse: $6222456bc073291c$export$1db9219b4f34658c,
1479
1773
  spirograph: $6222456bc073291c$export$b027c64d22b01985,
1480
1774
  waveRing: $6222456bc073291c$export$7608ccd03bfb705d,
1481
- rose: $6222456bc073291c$export$11a377e7498bb523
1775
+ rose: $6222456bc073291c$export$11a377e7498bb523,
1776
+ shardField: $6222456bc073291c$export$76b6526575ea179b,
1777
+ voronoiCell: $6222456bc073291c$export$ed9ff98da5b05073,
1778
+ crescent: $6222456bc073291c$export$e0452d9a794fe7e5,
1779
+ tendril: $6222456bc073291c$export$38bfe5eb52137e01,
1780
+ cloudForm: $6222456bc073291c$export$105caa8cfd63c422,
1781
+ inkSplat: $6222456bc073291c$export$e181e5bd3c539569,
1782
+ geodesicDome: $6222456bc073291c$export$155b4780b4c6bb7b,
1783
+ penroseTile: $6222456bc073291c$export$9a7e648f11155172,
1784
+ reuleauxTriangle: $6222456bc073291c$export$1fc0aedbabd73399,
1785
+ dotCluster: $6222456bc073291c$export$ef7b5e0c19a21fd1,
1786
+ crosshatchPatch: $6222456bc073291c$export$f15df8ab60dfcc9a
1482
1787
  };
1483
1788
 
1484
1789
 
@@ -1513,7 +1818,13 @@ const $c3de8257a8baa3b0$var$RENDER_STYLES = [
1513
1818
  "dashed",
1514
1819
  "watercolor",
1515
1820
  "hatched",
1516
- "incomplete"
1821
+ "incomplete",
1822
+ "stipple",
1823
+ "stencil",
1824
+ "noise-grain",
1825
+ "wood-grain",
1826
+ "marble-vein",
1827
+ "fabric-weave"
1517
1828
  ];
1518
1829
  function $c3de8257a8baa3b0$export$9fd4e64b2acd410e(rng) {
1519
1830
  return $c3de8257a8baa3b0$var$RENDER_STYLES[Math.floor(rng() * $c3de8257a8baa3b0$var$RENDER_STYLES.length)];
@@ -1687,6 +1998,213 @@ function $c3de8257a8baa3b0$export$71b514a25c47df50(ctx, shape, x, y, config) {
1687
1998
  ctx.lineDashOffset = 0;
1688
1999
  break;
1689
2000
  }
2001
+ case "stipple":
2002
+ {
2003
+ // Dot-fill texture — clip to shape, then scatter dots
2004
+ const savedAlphaS = ctx.globalAlpha;
2005
+ ctx.globalAlpha = savedAlphaS * 0.15;
2006
+ ctx.fill(); // ghost fill
2007
+ ctx.globalAlpha = savedAlphaS;
2008
+ ctx.save();
2009
+ ctx.clip();
2010
+ const dotSpacing = Math.max(2, size * 0.03);
2011
+ const extent = size * 0.55;
2012
+ ctx.globalAlpha = savedAlphaS * 0.7;
2013
+ for(let dx = -extent; dx <= extent; dx += dotSpacing)for(let dy = -extent; dy <= extent; dy += dotSpacing){
2014
+ // Jitter each dot position for organic feel
2015
+ const jx = rng ? (rng() - 0.5) * dotSpacing * 0.6 : 0;
2016
+ const jy = rng ? (rng() - 0.5) * dotSpacing * 0.6 : 0;
2017
+ const dotR = rng ? dotSpacing * (0.15 + rng() * 0.2) : dotSpacing * 0.2;
2018
+ ctx.beginPath();
2019
+ ctx.arc(dx + jx, dy + jy, dotR, 0, Math.PI * 2);
2020
+ ctx.fill();
2021
+ }
2022
+ ctx.restore();
2023
+ ctx.globalAlpha = savedAlphaS;
2024
+ // Outline
2025
+ ctx.globalAlpha *= 0.4;
2026
+ ctx.stroke();
2027
+ ctx.globalAlpha /= 0.4;
2028
+ break;
2029
+ }
2030
+ case "stencil":
2031
+ {
2032
+ // Negative-space cutout — fill a rectangle, then erase the shape
2033
+ const savedAlphaSt = ctx.globalAlpha;
2034
+ // Fill a bounding area with the stroke color
2035
+ ctx.globalAlpha = savedAlphaSt * 0.5;
2036
+ ctx.fillStyle = strokeColor;
2037
+ ctx.fillRect(-size * 0.6, -size * 0.6, size * 1.2, size * 1.2);
2038
+ // Cut out the shape using destination-out
2039
+ ctx.globalCompositeOperation = "destination-out";
2040
+ ctx.globalAlpha = 1;
2041
+ ctx.fill();
2042
+ ctx.globalCompositeOperation = "source-over";
2043
+ ctx.globalAlpha = savedAlphaSt;
2044
+ // Subtle outline of the cutout
2045
+ ctx.globalAlpha *= 0.3;
2046
+ ctx.stroke();
2047
+ ctx.globalAlpha /= 0.3;
2048
+ break;
2049
+ }
2050
+ case "noise-grain":
2051
+ {
2052
+ // Procedural noise grain texture clipped to shape boundary
2053
+ const savedAlphaN = ctx.globalAlpha;
2054
+ ctx.globalAlpha = savedAlphaN * 0.25;
2055
+ ctx.fill(); // base tint
2056
+ ctx.globalAlpha = savedAlphaN;
2057
+ ctx.save();
2058
+ ctx.clip();
2059
+ const grainSpacing = Math.max(1.5, size * 0.015);
2060
+ const extentN = size * 0.55;
2061
+ ctx.globalAlpha = savedAlphaN * 0.6;
2062
+ for(let gx = -extentN; gx <= extentN; gx += grainSpacing)for(let gy = -extentN; gy <= extentN; gy += grainSpacing){
2063
+ if (!rng) break;
2064
+ const jx = (rng() - 0.5) * grainSpacing * 1.2;
2065
+ const jy = (rng() - 0.5) * grainSpacing * 1.2;
2066
+ const brightness = rng() > 0.5 ? 255 : 0;
2067
+ const dotAlpha = 0.15 + rng() * 0.35;
2068
+ ctx.globalAlpha = savedAlphaN * dotAlpha;
2069
+ ctx.fillStyle = `rgba(${brightness},${brightness},${brightness},1)`;
2070
+ const dotSize = grainSpacing * (0.3 + rng() * 0.5);
2071
+ ctx.fillRect(gx + jx, gy + jy, dotSize, dotSize);
2072
+ }
2073
+ ctx.restore();
2074
+ ctx.fillStyle = fillColor;
2075
+ ctx.globalAlpha = savedAlphaN;
2076
+ ctx.globalAlpha *= 0.4;
2077
+ ctx.stroke();
2078
+ ctx.globalAlpha /= 0.4;
2079
+ break;
2080
+ }
2081
+ case "wood-grain":
2082
+ {
2083
+ // Parallel wavy lines simulating wood grain, clipped to shape
2084
+ const savedAlphaW = ctx.globalAlpha;
2085
+ ctx.globalAlpha = savedAlphaW * 0.2;
2086
+ ctx.fill(); // base tint
2087
+ ctx.globalAlpha = savedAlphaW;
2088
+ ctx.save();
2089
+ ctx.clip();
2090
+ const grainLineSpacing = Math.max(2, size * 0.035);
2091
+ const extentW = size * 0.55;
2092
+ const waveFreq = rng ? 3 + rng() * 5 : 5;
2093
+ const waveAmp = rng ? size * (0.01 + rng() * 0.03) : size * 0.02;
2094
+ const grainAngle = rng ? rng() * Math.PI : Math.PI * 0.25;
2095
+ ctx.lineWidth = Math.max(0.5, strokeWidth * 0.3);
2096
+ ctx.globalAlpha = savedAlphaW * 0.5;
2097
+ const cosG = Math.cos(grainAngle);
2098
+ const sinG = Math.sin(grainAngle);
2099
+ for(let d = -extentW; d <= extentW; d += grainLineSpacing){
2100
+ ctx.beginPath();
2101
+ for(let t = -extentW; t <= extentW; t += 2){
2102
+ const wave = Math.sin(t / extentW * waveFreq * Math.PI) * waveAmp;
2103
+ const px = t * cosG - (d + wave) * sinG;
2104
+ const py = t * sinG + (d + wave) * cosG;
2105
+ if (t === -extentW) ctx.moveTo(px, py);
2106
+ else ctx.lineTo(px, py);
2107
+ }
2108
+ ctx.stroke();
2109
+ }
2110
+ ctx.restore();
2111
+ ctx.globalAlpha = savedAlphaW;
2112
+ ctx.globalAlpha *= 0.35;
2113
+ ctx.stroke();
2114
+ ctx.globalAlpha /= 0.35;
2115
+ break;
2116
+ }
2117
+ case "marble-vein":
2118
+ {
2119
+ // Branching vein lines on a soft fill, clipped to shape
2120
+ const savedAlphaM = ctx.globalAlpha;
2121
+ ctx.globalAlpha = savedAlphaM * 0.35;
2122
+ ctx.fill(); // soft base
2123
+ ctx.globalAlpha = savedAlphaM;
2124
+ ctx.save();
2125
+ ctx.clip();
2126
+ const veinCount = rng ? 2 + Math.floor(rng() * 3) : 3;
2127
+ const extentM = size * 0.45;
2128
+ ctx.lineWidth = Math.max(0.5, strokeWidth * 0.5);
2129
+ ctx.globalAlpha = savedAlphaM * 0.4;
2130
+ for(let v = 0; v < veinCount; v++){
2131
+ const startX = rng ? (rng() - 0.5) * extentM * 2 : 0;
2132
+ const startY = rng ? -extentM + rng() * extentM * 0.5 : -extentM;
2133
+ let vx = startX;
2134
+ let vy = startY;
2135
+ const steps = 15 + (rng ? Math.floor(rng() * 15) : 10);
2136
+ const stepLen = size * 0.04;
2137
+ ctx.beginPath();
2138
+ ctx.moveTo(vx, vy);
2139
+ for(let s = 0; s < steps; s++){
2140
+ const drift = rng ? (rng() - 0.5) * stepLen * 1.5 : 0;
2141
+ vx += drift;
2142
+ vy += stepLen;
2143
+ ctx.lineTo(vx, vy);
2144
+ // Branch ~20% of the time
2145
+ if (rng && rng() < 0.2 && s > 2 && s < steps - 3) {
2146
+ const branchDir = rng() < 0.5 ? -1 : 1;
2147
+ let bx = vx;
2148
+ let by = vy;
2149
+ const bSteps = 3 + Math.floor(rng() * 5);
2150
+ ctx.moveTo(bx, by);
2151
+ for(let bs = 0; bs < bSteps; bs++){
2152
+ bx += branchDir * stepLen * (0.5 + rng() * 0.5);
2153
+ by += stepLen * 0.6;
2154
+ ctx.lineTo(bx, by);
2155
+ }
2156
+ ctx.moveTo(vx, vy); // return to main vein
2157
+ }
2158
+ }
2159
+ ctx.stroke();
2160
+ }
2161
+ ctx.restore();
2162
+ ctx.globalAlpha = savedAlphaM;
2163
+ ctx.globalAlpha *= 0.3;
2164
+ ctx.stroke();
2165
+ ctx.globalAlpha /= 0.3;
2166
+ break;
2167
+ }
2168
+ case "fabric-weave":
2169
+ {
2170
+ // Interlocking horizontal/vertical threads clipped to shape
2171
+ const savedAlphaF = ctx.globalAlpha;
2172
+ ctx.globalAlpha = savedAlphaF * 0.15;
2173
+ ctx.fill(); // ghost base
2174
+ ctx.globalAlpha = savedAlphaF;
2175
+ ctx.save();
2176
+ ctx.clip();
2177
+ const threadSpacing = Math.max(2, size * 0.04);
2178
+ const extentF = size * 0.55;
2179
+ ctx.lineWidth = Math.max(0.8, threadSpacing * 0.5);
2180
+ ctx.globalAlpha = savedAlphaF * 0.55;
2181
+ // Horizontal threads
2182
+ for(let y = -extentF; y <= extentF; y += threadSpacing * 2){
2183
+ ctx.beginPath();
2184
+ ctx.moveTo(-extentF, y);
2185
+ ctx.lineTo(extentF, y);
2186
+ ctx.stroke();
2187
+ }
2188
+ // Vertical threads (offset by half spacing for weave effect)
2189
+ ctx.globalAlpha = savedAlphaF * 0.45;
2190
+ ctx.strokeStyle = fillColor;
2191
+ for(let x = -extentF; x <= extentF; x += threadSpacing * 2){
2192
+ ctx.beginPath();
2193
+ for(let y = -extentF; y <= extentF; y += threadSpacing * 2){
2194
+ // Over-under: draw segment, skip segment
2195
+ ctx.moveTo(x, y);
2196
+ ctx.lineTo(x, y + threadSpacing);
2197
+ }
2198
+ ctx.stroke();
2199
+ }
2200
+ ctx.strokeStyle = strokeColor;
2201
+ ctx.restore();
2202
+ ctx.globalAlpha = savedAlphaF;
2203
+ ctx.globalAlpha *= 0.3;
2204
+ ctx.stroke();
2205
+ ctx.globalAlpha /= 0.3;
2206
+ break;
2207
+ }
1690
2208
  case "fill-and-stroke":
1691
2209
  default:
1692
2210
  ctx.fill();
@@ -1733,6 +2251,64 @@ function $c3de8257a8baa3b0$export$bb35a6995ddbf32d(ctx, shape, x, y, config) {
1733
2251
  });
1734
2252
  ctx.restore();
1735
2253
  }
2254
+ function $c3de8257a8baa3b0$export$8bd8bbd1a8e53689(ctx, shape, x, y, config) {
2255
+ const { mirrorAxis: mirrorAxis = "horizontal", mirrorGap: mirrorGap = 0 } = config;
2256
+ // Draw the primary shape
2257
+ $c3de8257a8baa3b0$export$bb35a6995ddbf32d(ctx, shape, x, y, config);
2258
+ // Draw the mirrored copy
2259
+ ctx.save();
2260
+ const savedAlpha = ctx.globalAlpha;
2261
+ ctx.globalAlpha = savedAlpha * 0.7; // mirror is slightly softer
2262
+ switch(mirrorAxis){
2263
+ case "horizontal":
2264
+ // Reflect across vertical axis at shape position
2265
+ $c3de8257a8baa3b0$export$bb35a6995ddbf32d(ctx, shape, x, y + mirrorGap, {
2266
+ ...config,
2267
+ rotation: -(config.rotation || 0),
2268
+ size: config.size * 0.95
2269
+ });
2270
+ break;
2271
+ case "vertical":
2272
+ $c3de8257a8baa3b0$export$bb35a6995ddbf32d(ctx, shape, x + mirrorGap, y, {
2273
+ ...config,
2274
+ rotation: 180 - (config.rotation || 0),
2275
+ size: config.size * 0.95
2276
+ });
2277
+ break;
2278
+ case "diagonal":
2279
+ // Reflect across 45° axis
2280
+ $c3de8257a8baa3b0$export$bb35a6995ddbf32d(ctx, shape, x + mirrorGap * 0.7, y + mirrorGap * 0.7, {
2281
+ ...config,
2282
+ rotation: 90 - (config.rotation || 0),
2283
+ size: config.size * 0.9
2284
+ });
2285
+ break;
2286
+ case "radial-4":
2287
+ // Four-way radial mirror
2288
+ for(let i = 1; i < 4; i++){
2289
+ const angle = i / 4 * Math.PI * 2;
2290
+ const mx = x + Math.cos(angle) * mirrorGap;
2291
+ const my = y + Math.sin(angle) * mirrorGap;
2292
+ ctx.globalAlpha = savedAlpha * (0.7 - i * 0.1);
2293
+ $c3de8257a8baa3b0$export$bb35a6995ddbf32d(ctx, shape, mx, my, {
2294
+ ...config,
2295
+ rotation: (config.rotation || 0) + i * 90,
2296
+ size: config.size * (0.95 - i * 0.05)
2297
+ });
2298
+ }
2299
+ break;
2300
+ }
2301
+ ctx.globalAlpha = savedAlpha;
2302
+ ctx.restore();
2303
+ }
2304
+ function $c3de8257a8baa3b0$export$879206e23912d1a9(rng) {
2305
+ const roll = rng();
2306
+ if (roll < 0.60) return null;
2307
+ if (roll < 0.75) return "horizontal";
2308
+ if (roll < 0.87) return "vertical";
2309
+ if (roll < 0.95) return "diagonal";
2310
+ return "radial-4";
2311
+ }
1736
2312
 
1737
2313
 
1738
2314
 
@@ -2235,7 +2811,8 @@ const $e73976f898150d4d$export$4343b39fe47bd82c = {
2235
2811
  bestStyles: [
2236
2812
  "fill-only",
2237
2813
  "watercolor",
2238
- "fill-and-stroke"
2814
+ "fill-and-stroke",
2815
+ "wood-grain"
2239
2816
  ]
2240
2817
  },
2241
2818
  spirograph: {
@@ -2291,6 +2868,202 @@ const $e73976f898150d4d$export$4343b39fe47bd82c = {
2291
2868
  "fill-only",
2292
2869
  "watercolor"
2293
2870
  ]
2871
+ },
2872
+ // ── New procedural shapes ─────────────────────────────────────
2873
+ shardField: {
2874
+ tier: 2,
2875
+ minSizeFraction: 0.1,
2876
+ maxSizeFraction: 0.7,
2877
+ affinities: [
2878
+ "voronoiCell",
2879
+ "diamond",
2880
+ "triangle",
2881
+ "penroseTile"
2882
+ ],
2883
+ category: "procedural",
2884
+ heroCandidate: false,
2885
+ bestStyles: [
2886
+ "fill-and-stroke",
2887
+ "stroke-only",
2888
+ "fill-only"
2889
+ ]
2890
+ },
2891
+ voronoiCell: {
2892
+ tier: 1,
2893
+ minSizeFraction: 0.08,
2894
+ maxSizeFraction: 0.9,
2895
+ affinities: [
2896
+ "shardField",
2897
+ "ngon",
2898
+ "superellipse",
2899
+ "blob"
2900
+ ],
2901
+ category: "procedural",
2902
+ heroCandidate: false,
2903
+ bestStyles: [
2904
+ "fill-and-stroke",
2905
+ "fill-only",
2906
+ "watercolor",
2907
+ "marble-vein"
2908
+ ]
2909
+ },
2910
+ crescent: {
2911
+ tier: 1,
2912
+ minSizeFraction: 0.1,
2913
+ maxSizeFraction: 1.0,
2914
+ affinities: [
2915
+ "circle",
2916
+ "blob",
2917
+ "cloudForm",
2918
+ "vesicaPiscis"
2919
+ ],
2920
+ category: "procedural",
2921
+ heroCandidate: true,
2922
+ bestStyles: [
2923
+ "fill-only",
2924
+ "watercolor",
2925
+ "fill-and-stroke"
2926
+ ]
2927
+ },
2928
+ tendril: {
2929
+ tier: 2,
2930
+ minSizeFraction: 0.1,
2931
+ maxSizeFraction: 0.8,
2932
+ affinities: [
2933
+ "blob",
2934
+ "inkSplat",
2935
+ "lissajous",
2936
+ "fibonacciSpiral"
2937
+ ],
2938
+ category: "procedural",
2939
+ heroCandidate: false,
2940
+ bestStyles: [
2941
+ "fill-only",
2942
+ "watercolor",
2943
+ "fill-and-stroke"
2944
+ ]
2945
+ },
2946
+ cloudForm: {
2947
+ tier: 1,
2948
+ minSizeFraction: 0.15,
2949
+ maxSizeFraction: 1.0,
2950
+ affinities: [
2951
+ "blob",
2952
+ "circle",
2953
+ "crescent",
2954
+ "superellipse"
2955
+ ],
2956
+ category: "procedural",
2957
+ heroCandidate: false,
2958
+ bestStyles: [
2959
+ "fill-only",
2960
+ "watercolor"
2961
+ ]
2962
+ },
2963
+ inkSplat: {
2964
+ tier: 2,
2965
+ minSizeFraction: 0.1,
2966
+ maxSizeFraction: 0.8,
2967
+ affinities: [
2968
+ "blob",
2969
+ "tendril",
2970
+ "shardField",
2971
+ "star"
2972
+ ],
2973
+ category: "procedural",
2974
+ heroCandidate: false,
2975
+ bestStyles: [
2976
+ "fill-only",
2977
+ "watercolor",
2978
+ "fill-and-stroke"
2979
+ ]
2980
+ },
2981
+ geodesicDome: {
2982
+ tier: 2,
2983
+ minSizeFraction: 0.2,
2984
+ maxSizeFraction: 0.9,
2985
+ affinities: [
2986
+ "metatronsCube",
2987
+ "platonicSolid",
2988
+ "hexagon",
2989
+ "triangle"
2990
+ ],
2991
+ category: "procedural",
2992
+ heroCandidate: true,
2993
+ bestStyles: [
2994
+ "stroke-only",
2995
+ "dashed",
2996
+ "double-stroke"
2997
+ ]
2998
+ },
2999
+ penroseTile: {
3000
+ tier: 2,
3001
+ minSizeFraction: 0.06,
3002
+ maxSizeFraction: 0.6,
3003
+ affinities: [
3004
+ "diamond",
3005
+ "triangle",
3006
+ "shardField",
3007
+ "voronoiCell"
3008
+ ],
3009
+ category: "procedural",
3010
+ heroCandidate: false,
3011
+ bestStyles: [
3012
+ "fill-and-stroke",
3013
+ "fill-only",
3014
+ "double-stroke"
3015
+ ]
3016
+ },
3017
+ reuleauxTriangle: {
3018
+ tier: 1,
3019
+ minSizeFraction: 0.08,
3020
+ maxSizeFraction: 1.0,
3021
+ affinities: [
3022
+ "triangle",
3023
+ "circle",
3024
+ "superellipse",
3025
+ "vesicaPiscis"
3026
+ ],
3027
+ category: "procedural",
3028
+ heroCandidate: true,
3029
+ bestStyles: [
3030
+ "fill-and-stroke",
3031
+ "fill-only",
3032
+ "watercolor"
3033
+ ]
3034
+ },
3035
+ dotCluster: {
3036
+ tier: 3,
3037
+ minSizeFraction: 0.05,
3038
+ maxSizeFraction: 0.5,
3039
+ affinities: [
3040
+ "cloudForm",
3041
+ "inkSplat",
3042
+ "blob"
3043
+ ],
3044
+ category: "procedural",
3045
+ heroCandidate: false,
3046
+ bestStyles: [
3047
+ "fill-only",
3048
+ "stipple"
3049
+ ]
3050
+ },
3051
+ crosshatchPatch: {
3052
+ tier: 3,
3053
+ minSizeFraction: 0.1,
3054
+ maxSizeFraction: 0.6,
3055
+ affinities: [
3056
+ "voronoiCell",
3057
+ "ngon",
3058
+ "superellipse"
3059
+ ],
3060
+ category: "procedural",
3061
+ heroCandidate: false,
3062
+ bestStyles: [
3063
+ "stroke-only",
3064
+ "hatched",
3065
+ "fabric-weave"
3066
+ ]
2294
3067
  }
2295
3068
  };
2296
3069
  function $e73976f898150d4d$export$4a95df8944b5033b(rng, shapeNames, archetypeName) {
@@ -2365,6 +3138,81 @@ function $e73976f898150d4d$export$4a95df8944b5033b(rng, shapeNames, archetypeNam
2365
3138
  accents: accents
2366
3139
  };
2367
3140
  }
3141
+ if (archetypeName === "shattered-glass") {
3142
+ // Favor angular, fragmented shapes
3143
+ const shardBoost = available.filter((s)=>[
3144
+ "shardField",
3145
+ "voronoiCell",
3146
+ "penroseTile",
3147
+ "diamond",
3148
+ "triangle",
3149
+ "ngon"
3150
+ ].includes(s) && !primary.includes(s));
3151
+ return {
3152
+ primary: [
3153
+ ...primary.filter((s)=>s !== "blob" && s !== "cloudForm"),
3154
+ ...shardBoost.slice(0, 3)
3155
+ ],
3156
+ supporting: supporting.filter((s)=>s !== "blob" && s !== "cloudForm"),
3157
+ accents: accents
3158
+ };
3159
+ }
3160
+ if (archetypeName === "botanical") {
3161
+ // Favor organic, flowing shapes
3162
+ const botanicalBoost = available.filter((s)=>[
3163
+ "tendril",
3164
+ "cloudForm",
3165
+ "blob",
3166
+ "crescent",
3167
+ "rose",
3168
+ "inkSplat"
3169
+ ].includes(s) && !primary.includes(s));
3170
+ return {
3171
+ primary: [
3172
+ ...primary,
3173
+ ...botanicalBoost.slice(0, 3)
3174
+ ],
3175
+ supporting: supporting,
3176
+ accents: accents
3177
+ };
3178
+ }
3179
+ if (archetypeName === "stipple-portrait") {
3180
+ // Favor small, dot-friendly shapes
3181
+ const stippleBoost = available.filter((s)=>[
3182
+ "dotCluster",
3183
+ "circle",
3184
+ "crosshatchPatch",
3185
+ "voronoiCell",
3186
+ "blob"
3187
+ ].includes(s) && !primary.includes(s));
3188
+ return {
3189
+ primary: [
3190
+ ...primary,
3191
+ ...stippleBoost.slice(0, 3)
3192
+ ],
3193
+ supporting: supporting,
3194
+ accents: accents
3195
+ };
3196
+ }
3197
+ if (archetypeName === "celestial") {
3198
+ // Favor sacred geometry and cosmic shapes
3199
+ const celestialBoost = available.filter((s)=>[
3200
+ "crescent",
3201
+ "geodesicDome",
3202
+ "mandala",
3203
+ "flowerOfLife",
3204
+ "spirograph",
3205
+ "fibonacciSpiral"
3206
+ ].includes(s) && !primary.includes(s));
3207
+ return {
3208
+ primary: [
3209
+ ...primary,
3210
+ ...celestialBoost.slice(0, 3)
3211
+ ],
3212
+ supporting: supporting,
3213
+ accents: accents
3214
+ };
3215
+ }
2368
3216
  return {
2369
3217
  primary: primary,
2370
3218
  supporting: supporting,
@@ -2702,6 +3550,91 @@ const $f89bc858f7202849$var$ARCHETYPES = [
2702
3550
  glowMultiplier: 1,
2703
3551
  sizePower: 1.8,
2704
3552
  invertForeground: false
3553
+ },
3554
+ {
3555
+ name: "shattered-glass",
3556
+ gridSize: 8,
3557
+ layers: 3,
3558
+ baseOpacity: 0.85,
3559
+ opacityReduction: 0.1,
3560
+ minShapeSize: 15,
3561
+ maxShapeSize: 250,
3562
+ backgroundStyle: "solid-dark",
3563
+ paletteMode: "high-contrast",
3564
+ preferredStyles: [
3565
+ "fill-and-stroke",
3566
+ "stroke-only",
3567
+ "fill-only"
3568
+ ],
3569
+ flowLineMultiplier: 0,
3570
+ heroShape: false,
3571
+ glowMultiplier: 0.3,
3572
+ sizePower: 1.0,
3573
+ invertForeground: false
3574
+ },
3575
+ {
3576
+ name: "botanical",
3577
+ gridSize: 4,
3578
+ layers: 4,
3579
+ baseOpacity: 0.5,
3580
+ opacityReduction: 0.06,
3581
+ minShapeSize: 30,
3582
+ maxShapeSize: 400,
3583
+ backgroundStyle: "radial-light",
3584
+ paletteMode: "earth",
3585
+ preferredStyles: [
3586
+ "watercolor",
3587
+ "fill-only",
3588
+ "incomplete"
3589
+ ],
3590
+ flowLineMultiplier: 3,
3591
+ heroShape: true,
3592
+ glowMultiplier: 0.2,
3593
+ sizePower: 1.6,
3594
+ invertForeground: false
3595
+ },
3596
+ {
3597
+ name: "stipple-portrait",
3598
+ gridSize: 9,
3599
+ layers: 2,
3600
+ baseOpacity: 0.8,
3601
+ opacityReduction: 0.05,
3602
+ minShapeSize: 5,
3603
+ maxShapeSize: 120,
3604
+ backgroundStyle: "solid-light",
3605
+ paletteMode: "monochrome",
3606
+ preferredStyles: [
3607
+ "stipple",
3608
+ "fill-only",
3609
+ "hatched"
3610
+ ],
3611
+ flowLineMultiplier: 0,
3612
+ heroShape: false,
3613
+ glowMultiplier: 0,
3614
+ sizePower: 2.8,
3615
+ invertForeground: false
3616
+ },
3617
+ {
3618
+ name: "celestial",
3619
+ gridSize: 7,
3620
+ layers: 5,
3621
+ baseOpacity: 0.45,
3622
+ opacityReduction: 0.04,
3623
+ minShapeSize: 8,
3624
+ maxShapeSize: 450,
3625
+ backgroundStyle: "radial-dark",
3626
+ paletteMode: "neon",
3627
+ preferredStyles: [
3628
+ "fill-only",
3629
+ "watercolor",
3630
+ "stroke-only",
3631
+ "incomplete"
3632
+ ],
3633
+ flowLineMultiplier: 2,
3634
+ heroShape: true,
3635
+ glowMultiplier: 2.5,
3636
+ sizePower: 2.2,
3637
+ invertForeground: false
2705
3638
  }
2706
3639
  ];
2707
3640
  function $f89bc858f7202849$export$f1142fd7da4d6590(rng) {
@@ -2881,6 +3814,135 @@ function $4f72c5a314eddf25$var$drawBackground(ctx, style, bgStart, bgEnd, width,
2881
3814
  }
2882
3815
  }
2883
3816
  }
3817
+ const $4f72c5a314eddf25$var$CONSTELLATIONS = [
3818
+ {
3819
+ name: "flanked-triangle",
3820
+ build: (rng, baseSize)=>{
3821
+ const gap = baseSize * (0.6 + rng() * 0.3);
3822
+ return [
3823
+ {
3824
+ dx: 0,
3825
+ dy: 0,
3826
+ shape: "triangle",
3827
+ size: baseSize,
3828
+ rotation: rng() * 360
3829
+ },
3830
+ {
3831
+ dx: -gap,
3832
+ dy: gap * 0.3,
3833
+ shape: "circle",
3834
+ size: baseSize * 0.35,
3835
+ rotation: 0
3836
+ },
3837
+ {
3838
+ dx: gap,
3839
+ dy: gap * 0.3,
3840
+ shape: "circle",
3841
+ size: baseSize * 0.35,
3842
+ rotation: 0
3843
+ }
3844
+ ];
3845
+ }
3846
+ },
3847
+ {
3848
+ name: "hexagon-ring",
3849
+ build: (rng, baseSize)=>{
3850
+ const members = [];
3851
+ const count = 5 + Math.floor(rng() * 2);
3852
+ const ringR = baseSize * 0.6;
3853
+ for(let i = 0; i < count; i++){
3854
+ const angle = i / count * Math.PI * 2;
3855
+ members.push({
3856
+ dx: Math.cos(angle) * ringR,
3857
+ dy: Math.sin(angle) * ringR,
3858
+ shape: "hexagon",
3859
+ size: baseSize * (0.25 + rng() * 0.1),
3860
+ rotation: angle * 180 / Math.PI
3861
+ });
3862
+ }
3863
+ return members;
3864
+ }
3865
+ },
3866
+ {
3867
+ name: "spiral-dots",
3868
+ build: (rng, baseSize)=>{
3869
+ const members = [];
3870
+ const count = 7 + Math.floor(rng() * 5);
3871
+ const turns = 1.5 + rng();
3872
+ for(let i = 0; i < count; i++){
3873
+ const t = i / count;
3874
+ const angle = t * Math.PI * 2 * turns;
3875
+ const r = t * baseSize * 0.7;
3876
+ members.push({
3877
+ dx: Math.cos(angle) * r,
3878
+ dy: Math.sin(angle) * r,
3879
+ shape: "circle",
3880
+ size: baseSize * (0.08 + (1 - t) * 0.12),
3881
+ rotation: 0
3882
+ });
3883
+ }
3884
+ return members;
3885
+ }
3886
+ },
3887
+ {
3888
+ name: "diamond-cluster",
3889
+ build: (rng, baseSize)=>{
3890
+ const gap = baseSize * 0.45;
3891
+ return [
3892
+ {
3893
+ dx: 0,
3894
+ dy: -gap,
3895
+ shape: "diamond",
3896
+ size: baseSize * 0.4,
3897
+ rotation: 0
3898
+ },
3899
+ {
3900
+ dx: gap,
3901
+ dy: 0,
3902
+ shape: "diamond",
3903
+ size: baseSize * 0.35,
3904
+ rotation: 15
3905
+ },
3906
+ {
3907
+ dx: 0,
3908
+ dy: gap,
3909
+ shape: "diamond",
3910
+ size: baseSize * 0.3,
3911
+ rotation: 30
3912
+ },
3913
+ {
3914
+ dx: -gap,
3915
+ dy: 0,
3916
+ shape: "diamond",
3917
+ size: baseSize * 0.35,
3918
+ rotation: -15
3919
+ }
3920
+ ];
3921
+ }
3922
+ },
3923
+ {
3924
+ name: "crescent-pair",
3925
+ build: (rng, baseSize)=>{
3926
+ const gap = baseSize * 0.5;
3927
+ return [
3928
+ {
3929
+ dx: -gap * 0.4,
3930
+ dy: 0,
3931
+ shape: "crescent",
3932
+ size: baseSize * 0.5,
3933
+ rotation: rng() * 30
3934
+ },
3935
+ {
3936
+ dx: gap * 0.4,
3937
+ dy: 0,
3938
+ shape: "crescent",
3939
+ size: baseSize * 0.45,
3940
+ rotation: 180 + rng() * 30
3941
+ }
3942
+ ];
3943
+ }
3944
+ }
3945
+ ];
2884
3946
  function $4f72c5a314eddf25$export$29a844702096332e(ctx, gitHash, config = {}) {
2885
3947
  const finalConfig = {
2886
3948
  ...(0, $93cf69256c93baa9$export$c2f8e0cc249a8d8f),
@@ -2967,6 +4029,65 @@ function $4f72c5a314eddf25$export$29a844702096332e(ctx, gitHash, config = {}) {
2967
4029
  ctx.stroke();
2968
4030
  }
2969
4031
  ctx.globalCompositeOperation = "source-over";
4032
+ // ── 1c. Background pattern layer — subtle textured paper ───────
4033
+ const bgPatternRoll = rng();
4034
+ if (bgPatternRoll < 0.6) {
4035
+ ctx.save();
4036
+ ctx.globalCompositeOperation = "soft-light";
4037
+ const patternOpacity = 0.02 + rng() * 0.04;
4038
+ const patternColor = (0, $d016ad53434219a1$export$f2121afcad3d553f)(colorHierarchy.dominant, 0.15);
4039
+ if (bgPatternRoll < 0.2) {
4040
+ // Dot grid
4041
+ const dotSpacing = Math.max(8, Math.min(width, height) * (0.015 + rng() * 0.015));
4042
+ const dotR = dotSpacing * 0.08;
4043
+ ctx.globalAlpha = patternOpacity;
4044
+ ctx.fillStyle = patternColor;
4045
+ for(let px = 0; px < width; px += dotSpacing)for(let py = 0; py < height; py += dotSpacing){
4046
+ ctx.beginPath();
4047
+ ctx.arc(px, py, dotR, 0, Math.PI * 2);
4048
+ ctx.fill();
4049
+ }
4050
+ } else if (bgPatternRoll < 0.4) {
4051
+ // Diagonal lines
4052
+ const lineSpacing = Math.max(6, Math.min(width, height) * (0.02 + rng() * 0.02));
4053
+ ctx.globalAlpha = patternOpacity;
4054
+ ctx.strokeStyle = patternColor;
4055
+ ctx.lineWidth = 0.5 * scaleFactor;
4056
+ const diag = Math.hypot(width, height);
4057
+ for(let d = -diag; d < diag; d += lineSpacing){
4058
+ ctx.beginPath();
4059
+ ctx.moveTo(d, 0);
4060
+ ctx.lineTo(d + height, height);
4061
+ ctx.stroke();
4062
+ }
4063
+ } else {
4064
+ // Tessellation — hexagonal grid of tiny shapes
4065
+ const tessSize = Math.max(10, Math.min(width, height) * (0.025 + rng() * 0.02));
4066
+ const tessH = tessSize * Math.sqrt(3);
4067
+ ctx.globalAlpha = patternOpacity * 0.7;
4068
+ ctx.strokeStyle = patternColor;
4069
+ ctx.lineWidth = 0.4 * scaleFactor;
4070
+ for(let row = 0; row * tessH < height + tessH; row++){
4071
+ const offsetX = row % 2 * tessSize * 0.75;
4072
+ for(let col = 0; col * tessSize * 1.5 < width + tessSize * 1.5; col++){
4073
+ const hx = col * tessSize * 1.5 + offsetX;
4074
+ const hy = row * tessH;
4075
+ ctx.beginPath();
4076
+ for(let s = 0; s < 6; s++){
4077
+ const angle = Math.PI / 3 * s - Math.PI / 6;
4078
+ const vx = hx + Math.cos(angle) * tessSize * 0.5;
4079
+ const vy = hy + Math.sin(angle) * tessSize * 0.5;
4080
+ if (s === 0) ctx.moveTo(vx, vy);
4081
+ else ctx.lineTo(vx, vy);
4082
+ }
4083
+ ctx.closePath();
4084
+ ctx.stroke();
4085
+ }
4086
+ }
4087
+ }
4088
+ ctx.restore();
4089
+ }
4090
+ ctx.globalCompositeOperation = "source-over";
2970
4091
  // ── 2. Composition mode ────────────────────────────────────────
2971
4092
  const compositionMode = $4f72c5a314eddf25$var$COMPOSITION_MODES[Math.floor(rng() * $4f72c5a314eddf25$var$COMPOSITION_MODES.length)];
2972
4093
  const symRoll = rng();
@@ -3094,6 +4215,11 @@ function $4f72c5a314eddf25$export$29a844702096332e(ctx, gitHash, config = {}) {
3094
4215
  const layerRenderStyle = rng() < 0.6 ? archetype.preferredStyles[Math.floor(rng() * archetype.preferredStyles.length)] : (0, $c3de8257a8baa3b0$export$9fd4e64b2acd410e)(rng);
3095
4216
  // Atmospheric desaturation for later layers
3096
4217
  const atmosphericDesat = layerRatio * 0.3;
4218
+ // Depth-of-field simulation — later layers are "further away"
4219
+ // Reduce stroke widths and shift colors toward the background
4220
+ const dofFactor = 1 - layerRatio * 0.5; // 1.0 for front layer, 0.5 for back
4221
+ const dofStrokeScale = 0.4 + dofFactor * 0.6; // strokes thin out with depth
4222
+ const dofContrastReduction = layerRatio * 0.2; // colors fade toward bg
3097
4223
  for(let i = 0; i < numShapes; i++){
3098
4224
  // Position from composition mode, then focal bias
3099
4225
  const rawPos = $4f72c5a314eddf25$var$getCompositionPosition(compositionMode, rng, width, height, i, numShapes, cx, cy);
@@ -3136,8 +4262,10 @@ function $4f72c5a314eddf25$export$29a844702096332e(ctx, gitHash, config = {}) {
3136
4262
  // Semi-transparent fill
3137
4263
  const fillAlpha = 0.2 + rng() * 0.5;
3138
4264
  const transparentFill = (0, $d016ad53434219a1$export$f2121afcad3d553f)(fillColor, fillAlpha);
3139
- const strokeWidth = (0.5 + rng() * 2.0) * scaleFactor;
3140
- ctx.globalAlpha = layerOpacity * (0.5 + rng() * 0.5);
4265
+ const strokeWidth = (0.5 + rng() * 2.0) * scaleFactor * dofStrokeScale;
4266
+ // Depth-of-field: reduce opacity slightly for distant layers
4267
+ const dofOpacityScale = 1 - dofContrastReduction;
4268
+ ctx.globalAlpha = layerOpacity * (0.5 + rng() * 0.5) * dofOpacityScale;
3141
4269
  // Glow on sacred shapes more often — scaled by archetype
3142
4270
  const isSacred = $4f72c5a314eddf25$var$SACRED_SHAPES.includes(shape);
3143
4271
  const baseGlowChance = isSacred ? 0.45 : 0.2;
@@ -3156,7 +4284,48 @@ function $4f72c5a314eddf25$export$29a844702096332e(ctx, gitHash, config = {}) {
3156
4284
  const shadowDist = hasGlow ? 0 : size * 0.02;
3157
4285
  const shadowOffX = shadowDist * Math.cos(lightAngle);
3158
4286
  const shadowOffY = shadowDist * Math.sin(lightAngle);
3159
- (0, $c3de8257a8baa3b0$export$bb35a6995ddbf32d)(ctx, shape, x, y, {
4287
+ // ── 5a. Tangent placement — nudge toward nearest shape edge ──
4288
+ let finalX = x;
4289
+ let finalY = y;
4290
+ if (shapePositions.length > 0 && rng() < 0.25) {
4291
+ // Find nearest placed shape
4292
+ let nearestDist = Infinity;
4293
+ let nearestPos = null;
4294
+ for (const sp of shapePositions){
4295
+ const d = Math.hypot(x - sp.x, y - sp.y);
4296
+ if (d < nearestDist && d > 0) {
4297
+ nearestDist = d;
4298
+ nearestPos = sp;
4299
+ }
4300
+ }
4301
+ if (nearestPos) {
4302
+ // Target distance: edges kissing (sum of half-sizes)
4303
+ const targetDist = (size + nearestPos.size) * 0.5;
4304
+ if (nearestDist > targetDist * 0.5 && nearestDist < targetDist * 3) {
4305
+ const angle = Math.atan2(y - nearestPos.y, x - nearestPos.x);
4306
+ finalX = nearestPos.x + Math.cos(angle) * targetDist;
4307
+ finalY = nearestPos.y + Math.sin(angle) * targetDist;
4308
+ // Keep in bounds
4309
+ finalX = Math.max(0, Math.min(width, finalX));
4310
+ finalY = Math.max(0, Math.min(height, finalY));
4311
+ }
4312
+ }
4313
+ }
4314
+ // ── 5b. Shape mirroring — basic shapes get reflected copies ──
4315
+ const mirrorAxis = (0, $c3de8257a8baa3b0$export$879206e23912d1a9)(rng);
4316
+ const isBasicShape = [
4317
+ "circle",
4318
+ "triangle",
4319
+ "square",
4320
+ "hexagon",
4321
+ "star",
4322
+ "diamond",
4323
+ "crescent",
4324
+ "penroseTile",
4325
+ "reuleauxTriangle"
4326
+ ].includes(shape);
4327
+ const shouldMirror = mirrorAxis !== null && isBasicShape && size > adjustedMaxSize * 0.2;
4328
+ const shapeConfig = {
3160
4329
  fillColor: transparentFill,
3161
4330
  strokeColor: strokeColor,
3162
4331
  strokeWidth: strokeWidth,
@@ -3168,22 +4337,28 @@ function $4f72c5a314eddf25$export$29a844702096332e(ctx, gitHash, config = {}) {
3168
4337
  gradientFillEnd: gradientEnd,
3169
4338
  renderStyle: finalRenderStyle,
3170
4339
  rng: rng
4340
+ };
4341
+ if (shouldMirror) (0, $c3de8257a8baa3b0$export$8bd8bbd1a8e53689)(ctx, shape, finalX, finalY, {
4342
+ ...shapeConfig,
4343
+ mirrorAxis: mirrorAxis,
4344
+ mirrorGap: size * (0.1 + rng() * 0.3)
3171
4345
  });
4346
+ else (0, $c3de8257a8baa3b0$export$bb35a6995ddbf32d)(ctx, shape, finalX, finalY, shapeConfig);
3172
4347
  shapePositions.push({
3173
- x: x,
3174
- y: y,
4348
+ x: finalX,
4349
+ y: finalY,
3175
4350
  size: size,
3176
4351
  shape: shape
3177
4352
  });
3178
- // ── 5b. Size echo — large shapes spawn trailing smaller copies ──
4353
+ // ── 5c. Size echo — large shapes spawn trailing smaller copies ──
3179
4354
  if (size > adjustedMaxSize * 0.5 && rng() < 0.2) {
3180
4355
  const echoCount = 2 + Math.floor(rng() * 2);
3181
4356
  const echoAngle = rng() * Math.PI * 2;
3182
4357
  for(let e = 0; e < echoCount; e++){
3183
4358
  const echoScale = 0.3 - e * 0.08;
3184
4359
  const echoDist = size * (0.6 + e * 0.4);
3185
- const echoX = x + Math.cos(echoAngle) * echoDist;
3186
- const echoY = y + Math.sin(echoAngle) * echoDist;
4360
+ const echoX = finalX + Math.cos(echoAngle) * echoDist;
4361
+ const echoY = finalY + Math.sin(echoAngle) * echoDist;
3187
4362
  const echoSize = size * Math.max(0.1, echoScale);
3188
4363
  if (echoX < 0 || echoX > width || echoY < 0 || echoY > height) continue;
3189
4364
  ctx.globalAlpha = layerOpacity * (0.4 - e * 0.1);
@@ -3205,7 +4380,7 @@ function $4f72c5a314eddf25$export$29a844702096332e(ctx, gitHash, config = {}) {
3205
4380
  });
3206
4381
  }
3207
4382
  }
3208
- // ── 5c. Recursive nesting ──────────────────────────────────
4383
+ // ── 5d. Recursive nesting ──────────────────────────────────
3209
4384
  if (size > adjustedMaxSize * 0.4 && rng() < 0.15) {
3210
4385
  const innerCount = 1 + Math.floor(rng() * 3);
3211
4386
  for(let n = 0; n < innerCount; n++){
@@ -3218,7 +4393,7 @@ function $4f72c5a314eddf25$export$29a844702096332e(ctx, gitHash, config = {}) {
3218
4393
  const innerRot = rng() * 360;
3219
4394
  const innerFill = (0, $d016ad53434219a1$export$f2121afcad3d553f)((0, $d016ad53434219a1$export$18a34c25ea7e724b)((0, $d016ad53434219a1$export$b49f62f0a99da0e8)(colorHierarchy, rng), rng, 10, 0.1), 0.3 + rng() * 0.4);
3220
4395
  ctx.globalAlpha = layerOpacity * 0.7;
3221
- (0, $c3de8257a8baa3b0$export$bb35a6995ddbf32d)(ctx, innerShape, x + innerOffX, y + innerOffY, {
4396
+ (0, $c3de8257a8baa3b0$export$bb35a6995ddbf32d)(ctx, innerShape, finalX + innerOffX, finalY + innerOffY, {
3222
4397
  fillColor: innerFill,
3223
4398
  strokeColor: (0, $d016ad53434219a1$export$f2121afcad3d553f)(strokeColor, 0.5),
3224
4399
  strokeWidth: strokeWidth * 0.6,
@@ -3230,6 +4405,41 @@ function $4f72c5a314eddf25$export$29a844702096332e(ctx, gitHash, config = {}) {
3230
4405
  });
3231
4406
  }
3232
4407
  }
4408
+ // ── 5e. Shape constellations — pre-composed groups ─────────
4409
+ if (size > adjustedMaxSize * 0.35 && rng() < 0.12) {
4410
+ const constellation = $4f72c5a314eddf25$var$CONSTELLATIONS[Math.floor(rng() * $4f72c5a314eddf25$var$CONSTELLATIONS.length)];
4411
+ const members = constellation.build(rng, size);
4412
+ const groupRotation = rng() * Math.PI * 2;
4413
+ const cosR = Math.cos(groupRotation);
4414
+ const sinR = Math.sin(groupRotation);
4415
+ for (const member of members){
4416
+ // Rotate the group offset by the group rotation
4417
+ const mx = finalX + member.dx * cosR - member.dy * sinR;
4418
+ const my = finalY + member.dx * sinR + member.dy * cosR;
4419
+ if (mx < 0 || mx > width || my < 0 || my > height) continue;
4420
+ const memberFill = (0, $d016ad53434219a1$export$f2121afcad3d553f)((0, $d016ad53434219a1$export$18a34c25ea7e724b)((0, $d016ad53434219a1$export$b49f62f0a99da0e8)(colorHierarchy, rng), rng, 8, 0.06), fillAlpha * 0.8);
4421
+ const memberStroke = (0, $d016ad53434219a1$export$90ad0e6170cf6af5)((0, $d016ad53434219a1$export$18a34c25ea7e724b)(strokeBase, rng, 5, 0.04), bgLum);
4422
+ ctx.globalAlpha = layerOpacity * 0.6;
4423
+ // Use the member's shape if available, otherwise fall back to palette
4424
+ const memberShape = shapeNames.includes(member.shape) ? member.shape : (0, $e73976f898150d4d$export$3c37d9a045754d0e)(shapePalette, rng, member.size / adjustedMaxSize);
4425
+ (0, $c3de8257a8baa3b0$export$bb35a6995ddbf32d)(ctx, memberShape, mx, my, {
4426
+ fillColor: memberFill,
4427
+ strokeColor: memberStroke,
4428
+ strokeWidth: strokeWidth * 0.7,
4429
+ size: member.size,
4430
+ rotation: member.rotation + groupRotation * 180 / Math.PI,
4431
+ proportionType: "GOLDEN_RATIO",
4432
+ renderStyle: (0, $e73976f898150d4d$export$ab873bb6fb56c1a8)(memberShape, layerRenderStyle, rng),
4433
+ rng: rng
4434
+ });
4435
+ shapePositions.push({
4436
+ x: mx,
4437
+ y: my,
4438
+ size: member.size,
4439
+ shape: memberShape
4440
+ });
4441
+ }
4442
+ }
3233
4443
  }
3234
4444
  }
3235
4445
  // Reset blend mode for post-processing passes