git-hash-art 0.9.0 → 0.10.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
@@ -541,6 +541,18 @@ function $d016ad53434219a1$export$6d1620b367f86f7a(rng) {
541
541
  intensity: intensity
542
542
  };
543
543
  }
544
+ function $d016ad53434219a1$export$1793a1bfbe4f6ff5(hex, degrees) {
545
+ const [h, s, l] = $d016ad53434219a1$var$hexToHsl(hex);
546
+ return $d016ad53434219a1$var$hslToHex((h + degrees + 360) % 360, s, l);
547
+ }
548
+ function $d016ad53434219a1$export$703ba40a4347f77a(base, layerRatio, hueShiftPerLayer) {
549
+ const shift = layerRatio * hueShiftPerLayer;
550
+ return {
551
+ dominant: $d016ad53434219a1$export$1793a1bfbe4f6ff5(base.dominant, shift),
552
+ secondary: $d016ad53434219a1$export$1793a1bfbe4f6ff5(base.secondary, shift * 0.7),
553
+ accent: $d016ad53434219a1$export$1793a1bfbe4f6ff5(base.accent, shift * 0.5)
554
+ };
555
+ }
544
556
 
545
557
 
546
558
 
@@ -1824,7 +1836,8 @@ const $c3de8257a8baa3b0$var$RENDER_STYLES = [
1824
1836
  "noise-grain",
1825
1837
  "wood-grain",
1826
1838
  "marble-vein",
1827
- "fabric-weave"
1839
+ "fabric-weave",
1840
+ "hand-drawn"
1828
1841
  ];
1829
1842
  function $c3de8257a8baa3b0$export$9fd4e64b2acd410e(rng) {
1830
1843
  return $c3de8257a8baa3b0$var$RENDER_STYLES[Math.floor(rng() * $c3de8257a8baa3b0$var$RENDER_STYLES.length)];
@@ -2205,6 +2218,33 @@ function $c3de8257a8baa3b0$export$71b514a25c47df50(ctx, shape, x, y, config) {
2205
2218
  ctx.globalAlpha /= 0.3;
2206
2219
  break;
2207
2220
  }
2221
+ case "hand-drawn":
2222
+ {
2223
+ // Wobbly hand-drawn edge treatment — fill normally, then redraw
2224
+ // the outline with perturbed control points for a sketchy feel
2225
+ const savedAlphaHD = ctx.globalAlpha;
2226
+ ctx.globalAlpha = savedAlphaHD * 0.85;
2227
+ ctx.fill();
2228
+ ctx.globalAlpha = savedAlphaHD;
2229
+ // Draw 2-3 slightly offset wobbly strokes for a sketchy look
2230
+ const wobblePasses = 2 + (rng ? Math.floor(rng() * 2) : 0);
2231
+ ctx.lineWidth = strokeWidth * 0.8;
2232
+ for(let wp = 0; wp < wobblePasses; wp++){
2233
+ ctx.globalAlpha = savedAlphaHD * (0.4 - wp * 0.1);
2234
+ ctx.save();
2235
+ // Slight random offset per pass
2236
+ const wobbleX = rng ? (rng() - 0.5) * size * 0.02 : 0;
2237
+ const wobbleY = rng ? (rng() - 0.5) * size * 0.02 : 0;
2238
+ ctx.translate(wobbleX, wobbleY);
2239
+ // Slightly different scale per pass for edge variation
2240
+ const wobbleScale = 1 + (rng ? (rng() - 0.5) * 0.03 : 0);
2241
+ ctx.scale(wobbleScale, wobbleScale);
2242
+ ctx.stroke();
2243
+ ctx.restore();
2244
+ }
2245
+ ctx.globalAlpha = savedAlphaHD;
2246
+ break;
2247
+ }
2208
2248
  case "fill-and-stroke":
2209
2249
  default:
2210
2250
  ctx.fill();
@@ -2340,7 +2380,8 @@ const $e73976f898150d4d$export$4343b39fe47bd82c = {
2340
2380
  bestStyles: [
2341
2381
  "fill-only",
2342
2382
  "watercolor",
2343
- "fill-and-stroke"
2383
+ "fill-and-stroke",
2384
+ "hand-drawn"
2344
2385
  ]
2345
2386
  },
2346
2387
  square: {
@@ -2377,7 +2418,8 @@ const $e73976f898150d4d$export$4343b39fe47bd82c = {
2377
2418
  bestStyles: [
2378
2419
  "fill-and-stroke",
2379
2420
  "fill-only",
2380
- "watercolor"
2421
+ "watercolor",
2422
+ "hand-drawn"
2381
2423
  ]
2382
2424
  },
2383
2425
  hexagon: {
@@ -2757,7 +2799,8 @@ const $e73976f898150d4d$export$4343b39fe47bd82c = {
2757
2799
  bestStyles: [
2758
2800
  "fill-only",
2759
2801
  "watercolor",
2760
- "fill-and-stroke"
2802
+ "fill-and-stroke",
2803
+ "hand-drawn"
2761
2804
  ]
2762
2805
  },
2763
2806
  ngon: {
@@ -3637,8 +3680,51 @@ const $f89bc858f7202849$var$ARCHETYPES = [
3637
3680
  invertForeground: false
3638
3681
  }
3639
3682
  ];
3683
+ /**
3684
+ * Linearly interpolate between two archetype numeric parameters.
3685
+ */ function $f89bc858f7202849$var$lerpNum(a, b, t) {
3686
+ return a + (b - a) * t;
3687
+ }
3688
+ /**
3689
+ * Blend two archetypes by interpolating their numeric parameters
3690
+ * and merging their style arrays.
3691
+ */ function $f89bc858f7202849$var$blendArchetypes(a, b, t) {
3692
+ // Merge preferred styles — unique union, primary archetype first
3693
+ const mergedStyles = [
3694
+ ...new Set([
3695
+ ...a.preferredStyles,
3696
+ ...b.preferredStyles
3697
+ ])
3698
+ ];
3699
+ return {
3700
+ name: `${a.name}+${b.name}`,
3701
+ gridSize: Math.round($f89bc858f7202849$var$lerpNum(a.gridSize, b.gridSize, t)),
3702
+ layers: Math.round($f89bc858f7202849$var$lerpNum(a.layers, b.layers, t)),
3703
+ baseOpacity: $f89bc858f7202849$var$lerpNum(a.baseOpacity, b.baseOpacity, t),
3704
+ opacityReduction: $f89bc858f7202849$var$lerpNum(a.opacityReduction, b.opacityReduction, t),
3705
+ minShapeSize: Math.round($f89bc858f7202849$var$lerpNum(a.minShapeSize, b.minShapeSize, t)),
3706
+ maxShapeSize: Math.round($f89bc858f7202849$var$lerpNum(a.maxShapeSize, b.maxShapeSize, t)),
3707
+ backgroundStyle: t < 0.5 ? a.backgroundStyle : b.backgroundStyle,
3708
+ paletteMode: t < 0.5 ? a.paletteMode : b.paletteMode,
3709
+ preferredStyles: mergedStyles,
3710
+ flowLineMultiplier: $f89bc858f7202849$var$lerpNum(a.flowLineMultiplier, b.flowLineMultiplier, t),
3711
+ heroShape: t < 0.5 ? a.heroShape : b.heroShape,
3712
+ glowMultiplier: $f89bc858f7202849$var$lerpNum(a.glowMultiplier, b.glowMultiplier, t),
3713
+ sizePower: $f89bc858f7202849$var$lerpNum(a.sizePower, b.sizePower, t),
3714
+ invertForeground: t < 0.5 ? a.invertForeground : b.invertForeground
3715
+ };
3716
+ }
3640
3717
  function $f89bc858f7202849$export$f1142fd7da4d6590(rng) {
3641
- return $f89bc858f7202849$var$ARCHETYPES[Math.floor(rng() * $f89bc858f7202849$var$ARCHETYPES.length)];
3718
+ const primary = $f89bc858f7202849$var$ARCHETYPES[Math.floor(rng() * $f89bc858f7202849$var$ARCHETYPES.length)];
3719
+ // ~15% chance of blending with a second archetype
3720
+ if (rng() < 0.15) {
3721
+ const secondary = $f89bc858f7202849$var$ARCHETYPES[Math.floor(rng() * $f89bc858f7202849$var$ARCHETYPES.length)];
3722
+ if (secondary.name !== primary.name) {
3723
+ const blendT = 0.25 + rng() * 0.25; // 25-50% blend toward secondary
3724
+ return $f89bc858f7202849$var$blendArchetypes(primary, secondary, blendT);
3725
+ }
3726
+ }
3727
+ return primary;
3642
3728
  }
3643
3729
 
3644
3730
 
@@ -3974,6 +4060,8 @@ function $4f72c5a314eddf25$export$29a844702096332e(ctx, gitHash, config = {}) {
3974
4060
  const colorGrade = (0, $d016ad53434219a1$export$6d1620b367f86f7a)(rng);
3975
4061
  // ── 0e. Light direction — consistent shadow angle ──────────────
3976
4062
  const lightAngle = rng() * Math.PI * 2;
4063
+ // ── 0f. Palette evolution — hue drift direction across layers ──
4064
+ const paletteHueShift = (rng() - 0.5) * 40; // -20° to +20° total drift
3977
4065
  const scaleFactor = Math.min(width, height) / 1024;
3978
4066
  const adjustedMinSize = minShapeSize * scaleFactor;
3979
4067
  const adjustedMaxSize = maxShapeSize * scaleFactor;
@@ -4148,6 +4236,41 @@ function $4f72c5a314eddf25$export$29a844702096332e(ctx, gitHash, config = {}) {
4148
4236
  ry + (nearest.y - ry) * pull
4149
4237
  ];
4150
4238
  }
4239
+ // ── 3b. Void zone decoration — intentional negative space ────
4240
+ for (const zone of voidZones){
4241
+ // Subtle halo ring around void zones
4242
+ ctx.globalAlpha = 0.04 + rng() * 0.04;
4243
+ ctx.strokeStyle = (0, $d016ad53434219a1$export$f2121afcad3d553f)(colorHierarchy.accent, 0.2);
4244
+ ctx.lineWidth = 1.5 * scaleFactor;
4245
+ ctx.beginPath();
4246
+ ctx.arc(zone.x, zone.y, zone.radius, 0, Math.PI * 2);
4247
+ ctx.stroke();
4248
+ // ~50% chance: scatter tiny dots inside the void
4249
+ if (rng() < 0.5) {
4250
+ const dotCount = 3 + Math.floor(rng() * 6);
4251
+ ctx.globalAlpha = 0.06 + rng() * 0.04;
4252
+ ctx.fillStyle = (0, $d016ad53434219a1$export$f2121afcad3d553f)(colorHierarchy.secondary, 0.15);
4253
+ for(let d = 0; d < dotCount; d++){
4254
+ const angle = rng() * Math.PI * 2;
4255
+ const dist = rng() * zone.radius * 0.7;
4256
+ const dotR = (1 + rng() * 3) * scaleFactor;
4257
+ ctx.beginPath();
4258
+ ctx.arc(zone.x + Math.cos(angle) * dist, zone.y + Math.sin(angle) * dist, dotR, 0, Math.PI * 2);
4259
+ ctx.fill();
4260
+ }
4261
+ }
4262
+ // ~30% chance: thin concentric ring inside
4263
+ if (rng() < 0.3) {
4264
+ ctx.globalAlpha = 0.03 + rng() * 0.03;
4265
+ ctx.strokeStyle = (0, $d016ad53434219a1$export$f2121afcad3d553f)(colorHierarchy.dominant, 0.1);
4266
+ ctx.lineWidth = 0.5 * scaleFactor;
4267
+ const innerR = zone.radius * (0.4 + rng() * 0.3);
4268
+ ctx.beginPath();
4269
+ ctx.arc(zone.x, zone.y, innerR, 0, Math.PI * 2);
4270
+ ctx.stroke();
4271
+ }
4272
+ }
4273
+ ctx.globalAlpha = 1;
4151
4274
  // ── 4. Flow field seed values ──────────────────────────────────
4152
4275
  const fieldAngleBase = rng() * Math.PI * 2;
4153
4276
  const fieldFreq = 0.5 + rng() * 2;
@@ -4220,6 +4343,18 @@ function $4f72c5a314eddf25$export$29a844702096332e(ctx, gitHash, config = {}) {
4220
4343
  const dofFactor = 1 - layerRatio * 0.5; // 1.0 for front layer, 0.5 for back
4221
4344
  const dofStrokeScale = 0.4 + dofFactor * 0.6; // strokes thin out with depth
4222
4345
  const dofContrastReduction = layerRatio * 0.2; // colors fade toward bg
4346
+ // Color palette evolution — hue-rotate the hierarchy per layer
4347
+ const layerHierarchy = (0, $d016ad53434219a1$export$703ba40a4347f77a)(colorHierarchy, layerRatio, paletteHueShift);
4348
+ // Focal depth: shapes near focal points get more detail
4349
+ const focalDetailBoost = (px, py)=>{
4350
+ let minFocalDist = Infinity;
4351
+ for (const fp of focalPoints){
4352
+ const d = Math.hypot(px - fp.x, py - fp.y);
4353
+ if (d < minFocalDist) minFocalDist = d;
4354
+ }
4355
+ const maxDist = Math.hypot(width, height) * 0.5;
4356
+ return Math.max(0, 1 - minFocalDist / maxDist); // 1.0 at focal, 0.0 at edges
4357
+ };
4223
4358
  for(let i = 0; i < numShapes; i++){
4224
4359
  // Position from composition mode, then focal bias
4225
4360
  const rawPos = $4f72c5a314eddf25$var$getCompositionPosition(compositionMode, rng, width, height, i, numShapes, cx, cy);
@@ -4250,9 +4385,9 @@ function $4f72c5a314eddf25$export$29a844702096332e(ctx, gitHash, config = {}) {
4250
4385
  rotation = rotation + (angleToHero - rotation) * blendFactor * 0.4;
4251
4386
  }
4252
4387
  }
4253
- // Positional color from hierarchy + jitter
4254
- let fillBase = $4f72c5a314eddf25$var$getPositionalColor(x, y, width, height, colorHierarchy, rng);
4255
- const strokeBase = (0, $d016ad53434219a1$export$b49f62f0a99da0e8)(colorHierarchy, rng);
4388
+ // Positional color from hierarchy + jitter (using evolved layer palette)
4389
+ let fillBase = $4f72c5a314eddf25$var$getPositionalColor(x, y, width, height, layerHierarchy, rng);
4390
+ const strokeBase = (0, $d016ad53434219a1$export$b49f62f0a99da0e8)(layerHierarchy, rng);
4256
4391
  // Desaturate colors on later layers for depth
4257
4392
  if (atmosphericDesat > 0) fillBase = (0, $d016ad53434219a1$export$fb75607d98509d9)(fillBase, atmosphericDesat);
4258
4393
  // Temperature contrast: shift foreground shapes opposite to background
@@ -4344,6 +4479,25 @@ function $4f72c5a314eddf25$export$29a844702096332e(ctx, gitHash, config = {}) {
4344
4479
  mirrorGap: size * (0.1 + rng() * 0.3)
4345
4480
  });
4346
4481
  else (0, $c3de8257a8baa3b0$export$bb35a6995ddbf32d)(ctx, shape, finalX, finalY, shapeConfig);
4482
+ // ── Glazing — luminous multi-pass transparency on ~20% of shapes ──
4483
+ if (rng() < 0.2 && size > adjustedMinSize * 2) {
4484
+ const glazePasses = 2 + Math.floor(rng() * 2);
4485
+ for(let g = 0; g < glazePasses; g++){
4486
+ const glazeScale = 1 - (g + 1) * 0.12; // progressively smaller
4487
+ const glazeAlpha = 0.08 + g * 0.04; // progressively more opaque toward center
4488
+ ctx.globalAlpha = glazeAlpha;
4489
+ (0, $c3de8257a8baa3b0$export$bb35a6995ddbf32d)(ctx, shape, finalX, finalY, {
4490
+ fillColor: (0, $d016ad53434219a1$export$f2121afcad3d553f)(fillColor, 0.15 + g * 0.1),
4491
+ strokeColor: "rgba(0,0,0,0)",
4492
+ strokeWidth: 0,
4493
+ size: size * glazeScale,
4494
+ rotation: rotation,
4495
+ proportionType: "GOLDEN_RATIO",
4496
+ renderStyle: "fill-only",
4497
+ rng: rng
4498
+ });
4499
+ }
4500
+ }
4347
4501
  shapePositions.push({
4348
4502
  x: finalX,
4349
4503
  y: finalY,
@@ -4381,7 +4535,10 @@ function $4f72c5a314eddf25$export$29a844702096332e(ctx, gitHash, config = {}) {
4381
4535
  }
4382
4536
  }
4383
4537
  // ── 5d. Recursive nesting ──────────────────────────────────
4384
- if (size > adjustedMaxSize * 0.4 && rng() < 0.15) {
4538
+ // Focal depth: shapes near focal points get more detail
4539
+ const focalProximity = focalDetailBoost(finalX, finalY);
4540
+ const nestingChance = 0.15 + focalProximity * 0.15; // 15-30% near focal
4541
+ if (size > adjustedMaxSize * 0.4 && rng() < nestingChance) {
4385
4542
  const innerCount = 1 + Math.floor(rng() * 3);
4386
4543
  for(let n = 0; n < innerCount; n++){
4387
4544
  // Pick inner shape from palette affinities
@@ -4406,7 +4563,8 @@ function $4f72c5a314eddf25$export$29a844702096332e(ctx, gitHash, config = {}) {
4406
4563
  }
4407
4564
  }
4408
4565
  // ── 5e. Shape constellations — pre-composed groups ─────────
4409
- if (size > adjustedMaxSize * 0.35 && rng() < 0.12) {
4566
+ const constellationChance = 0.12 + focalProximity * 0.1; // 12-22% near focal
4567
+ if (size > adjustedMaxSize * 0.35 && rng() < constellationChance) {
4410
4568
  const constellation = $4f72c5a314eddf25$var$CONSTELLATIONS[Math.floor(rng() * $4f72c5a314eddf25$var$CONSTELLATIONS.length)];
4411
4569
  const members = constellation.build(rng, size);
4412
4570
  const groupRotation = rng() * Math.PI * 2;
@@ -4510,7 +4668,41 @@ function $4f72c5a314eddf25$export$29a844702096332e(ctx, gitHash, config = {}) {
4510
4668
  prevY = fy;
4511
4669
  }
4512
4670
  }
4513
- // ── 6b. Apply symmetry mirroring ─────────────────────────────────
4671
+ // ── 6b. Motion/energy lines short directional bursts ─────────
4672
+ const energyArchetypes = [
4673
+ "dense-chaotic",
4674
+ "cosmic",
4675
+ "neon-glow",
4676
+ "bold-graphic"
4677
+ ];
4678
+ const hasEnergyLines = energyArchetypes.some((a)=>archetype.name.includes(a)) || rng() < 0.25;
4679
+ if (hasEnergyLines && shapePositions.length > 0) {
4680
+ const energyCount = 5 + Math.floor(rng() * 10);
4681
+ ctx.lineCap = "round";
4682
+ for(let e = 0; e < energyCount; e++){
4683
+ // Pick a random shape to radiate from
4684
+ const source = shapePositions[Math.floor(rng() * shapePositions.length)];
4685
+ const burstCount = 2 + Math.floor(rng() * 4);
4686
+ const baseAngle = flowAngle(source.x, source.y);
4687
+ for(let b = 0; b < burstCount; b++){
4688
+ const angle = baseAngle + (rng() - 0.5) * 1.2;
4689
+ const lineLen = (source.size * 0.3 + rng() * source.size * 0.5) * scaleFactor * 0.3;
4690
+ const startDist = source.size * 0.5;
4691
+ const sx = source.x + Math.cos(angle) * startDist;
4692
+ const sy = source.y + Math.sin(angle) * startDist;
4693
+ const ex = sx + Math.cos(angle) * lineLen;
4694
+ const ey = sy + Math.sin(angle) * lineLen;
4695
+ ctx.globalAlpha = 0.04 + rng() * 0.06;
4696
+ ctx.strokeStyle = (0, $d016ad53434219a1$export$f2121afcad3d553f)((0, $d016ad53434219a1$export$90ad0e6170cf6af5)((0, $d016ad53434219a1$export$b49f62f0a99da0e8)(colorHierarchy, rng), bgLum), 0.3);
4697
+ ctx.lineWidth = (0.5 + rng() * 1.5) * scaleFactor;
4698
+ ctx.beginPath();
4699
+ ctx.moveTo(sx, sy);
4700
+ ctx.lineTo(ex, ey);
4701
+ ctx.stroke();
4702
+ }
4703
+ }
4704
+ }
4705
+ // ── 6c. Apply symmetry mirroring ─────────────────────────────────
4514
4706
  if (symmetryMode !== "none") {
4515
4707
  const canvas = ctx.canvas;
4516
4708
  ctx.save();
@@ -4621,6 +4813,44 @@ function $4f72c5a314eddf25$export$29a844702096332e(ctx, gitHash, config = {}) {
4621
4813
  ctx.restore();
4622
4814
  ctx.globalCompositeOperation = "source-over";
4623
4815
  }
4816
+ // ── 11. Signature mark — unique geometric chop from hash prefix ──
4817
+ {
4818
+ const sigRng = (0, $e4b03e131ed2a289$export$eaf9227667332084)((0, $e4b03e131ed2a289$export$e9cc707de01b7042)(gitHash, 42));
4819
+ const sigSize = Math.min(width, height) * 0.025;
4820
+ // Bottom-right corner with padding
4821
+ const sigX = width - sigSize * 2.5;
4822
+ const sigY = height - sigSize * 2.5;
4823
+ const sigSegments = 4 + Math.floor(sigRng() * 4); // 4-7 segments
4824
+ const sigColor = (0, $d016ad53434219a1$export$f2121afcad3d553f)(colorHierarchy.accent, 0.15);
4825
+ ctx.save();
4826
+ ctx.globalAlpha = 0.12 + sigRng() * 0.08;
4827
+ ctx.translate(sigX, sigY);
4828
+ ctx.strokeStyle = sigColor;
4829
+ ctx.fillStyle = (0, $d016ad53434219a1$export$f2121afcad3d553f)(colorHierarchy.dominant, 0.06);
4830
+ ctx.lineWidth = Math.max(0.5, 0.8 * scaleFactor);
4831
+ // Outer ring
4832
+ ctx.beginPath();
4833
+ ctx.arc(0, 0, sigSize, 0, Math.PI * 2);
4834
+ ctx.stroke();
4835
+ ctx.fill();
4836
+ // Inner geometric pattern — unique per hash
4837
+ ctx.beginPath();
4838
+ for(let s = 0; s < sigSegments; s++){
4839
+ const angle1 = sigRng() * Math.PI * 2;
4840
+ const angle2 = sigRng() * Math.PI * 2;
4841
+ const r1 = sigSize * (0.2 + sigRng() * 0.6);
4842
+ const r2 = sigSize * (0.2 + sigRng() * 0.6);
4843
+ ctx.moveTo(Math.cos(angle1) * r1, Math.sin(angle1) * r1);
4844
+ ctx.lineTo(Math.cos(angle2) * r2, Math.sin(angle2) * r2);
4845
+ }
4846
+ ctx.stroke();
4847
+ // Center dot
4848
+ ctx.beginPath();
4849
+ ctx.arc(0, 0, sigSize * 0.12, 0, Math.PI * 2);
4850
+ ctx.fillStyle = sigColor;
4851
+ ctx.fill();
4852
+ ctx.restore();
4853
+ }
4624
4854
  ctx.globalAlpha = 1;
4625
4855
  }
4626
4856