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/module.js CHANGED
@@ -527,6 +527,18 @@ function $9d614e7d77fc2947$export$6d1620b367f86f7a(rng) {
527
527
  intensity: intensity
528
528
  };
529
529
  }
530
+ function $9d614e7d77fc2947$export$1793a1bfbe4f6ff5(hex, degrees) {
531
+ const [h, s, l] = $9d614e7d77fc2947$var$hexToHsl(hex);
532
+ return $9d614e7d77fc2947$var$hslToHex((h + degrees + 360) % 360, s, l);
533
+ }
534
+ function $9d614e7d77fc2947$export$703ba40a4347f77a(base, layerRatio, hueShiftPerLayer) {
535
+ const shift = layerRatio * hueShiftPerLayer;
536
+ return {
537
+ dominant: $9d614e7d77fc2947$export$1793a1bfbe4f6ff5(base.dominant, shift),
538
+ secondary: $9d614e7d77fc2947$export$1793a1bfbe4f6ff5(base.secondary, shift * 0.7),
539
+ accent: $9d614e7d77fc2947$export$1793a1bfbe4f6ff5(base.accent, shift * 0.5)
540
+ };
541
+ }
530
542
 
531
543
 
532
544
 
@@ -1810,7 +1822,8 @@ const $9beb8f41637c29fd$var$RENDER_STYLES = [
1810
1822
  "noise-grain",
1811
1823
  "wood-grain",
1812
1824
  "marble-vein",
1813
- "fabric-weave"
1825
+ "fabric-weave",
1826
+ "hand-drawn"
1814
1827
  ];
1815
1828
  function $9beb8f41637c29fd$export$9fd4e64b2acd410e(rng) {
1816
1829
  return $9beb8f41637c29fd$var$RENDER_STYLES[Math.floor(rng() * $9beb8f41637c29fd$var$RENDER_STYLES.length)];
@@ -2191,6 +2204,33 @@ function $9beb8f41637c29fd$export$71b514a25c47df50(ctx, shape, x, y, config) {
2191
2204
  ctx.globalAlpha /= 0.3;
2192
2205
  break;
2193
2206
  }
2207
+ case "hand-drawn":
2208
+ {
2209
+ // Wobbly hand-drawn edge treatment — fill normally, then redraw
2210
+ // the outline with perturbed control points for a sketchy feel
2211
+ const savedAlphaHD = ctx.globalAlpha;
2212
+ ctx.globalAlpha = savedAlphaHD * 0.85;
2213
+ ctx.fill();
2214
+ ctx.globalAlpha = savedAlphaHD;
2215
+ // Draw 2-3 slightly offset wobbly strokes for a sketchy look
2216
+ const wobblePasses = 2 + (rng ? Math.floor(rng() * 2) : 0);
2217
+ ctx.lineWidth = strokeWidth * 0.8;
2218
+ for(let wp = 0; wp < wobblePasses; wp++){
2219
+ ctx.globalAlpha = savedAlphaHD * (0.4 - wp * 0.1);
2220
+ ctx.save();
2221
+ // Slight random offset per pass
2222
+ const wobbleX = rng ? (rng() - 0.5) * size * 0.02 : 0;
2223
+ const wobbleY = rng ? (rng() - 0.5) * size * 0.02 : 0;
2224
+ ctx.translate(wobbleX, wobbleY);
2225
+ // Slightly different scale per pass for edge variation
2226
+ const wobbleScale = 1 + (rng ? (rng() - 0.5) * 0.03 : 0);
2227
+ ctx.scale(wobbleScale, wobbleScale);
2228
+ ctx.stroke();
2229
+ ctx.restore();
2230
+ }
2231
+ ctx.globalAlpha = savedAlphaHD;
2232
+ break;
2233
+ }
2194
2234
  case "fill-and-stroke":
2195
2235
  default:
2196
2236
  ctx.fill();
@@ -2326,7 +2366,8 @@ const $24064302523652b1$export$4343b39fe47bd82c = {
2326
2366
  bestStyles: [
2327
2367
  "fill-only",
2328
2368
  "watercolor",
2329
- "fill-and-stroke"
2369
+ "fill-and-stroke",
2370
+ "hand-drawn"
2330
2371
  ]
2331
2372
  },
2332
2373
  square: {
@@ -2363,7 +2404,8 @@ const $24064302523652b1$export$4343b39fe47bd82c = {
2363
2404
  bestStyles: [
2364
2405
  "fill-and-stroke",
2365
2406
  "fill-only",
2366
- "watercolor"
2407
+ "watercolor",
2408
+ "hand-drawn"
2367
2409
  ]
2368
2410
  },
2369
2411
  hexagon: {
@@ -2743,7 +2785,8 @@ const $24064302523652b1$export$4343b39fe47bd82c = {
2743
2785
  bestStyles: [
2744
2786
  "fill-only",
2745
2787
  "watercolor",
2746
- "fill-and-stroke"
2788
+ "fill-and-stroke",
2789
+ "hand-drawn"
2747
2790
  ]
2748
2791
  },
2749
2792
  ngon: {
@@ -3623,8 +3666,51 @@ const $3faa2521b78398cf$var$ARCHETYPES = [
3623
3666
  invertForeground: false
3624
3667
  }
3625
3668
  ];
3669
+ /**
3670
+ * Linearly interpolate between two archetype numeric parameters.
3671
+ */ function $3faa2521b78398cf$var$lerpNum(a, b, t) {
3672
+ return a + (b - a) * t;
3673
+ }
3674
+ /**
3675
+ * Blend two archetypes by interpolating their numeric parameters
3676
+ * and merging their style arrays.
3677
+ */ function $3faa2521b78398cf$var$blendArchetypes(a, b, t) {
3678
+ // Merge preferred styles — unique union, primary archetype first
3679
+ const mergedStyles = [
3680
+ ...new Set([
3681
+ ...a.preferredStyles,
3682
+ ...b.preferredStyles
3683
+ ])
3684
+ ];
3685
+ return {
3686
+ name: `${a.name}+${b.name}`,
3687
+ gridSize: Math.round($3faa2521b78398cf$var$lerpNum(a.gridSize, b.gridSize, t)),
3688
+ layers: Math.round($3faa2521b78398cf$var$lerpNum(a.layers, b.layers, t)),
3689
+ baseOpacity: $3faa2521b78398cf$var$lerpNum(a.baseOpacity, b.baseOpacity, t),
3690
+ opacityReduction: $3faa2521b78398cf$var$lerpNum(a.opacityReduction, b.opacityReduction, t),
3691
+ minShapeSize: Math.round($3faa2521b78398cf$var$lerpNum(a.minShapeSize, b.minShapeSize, t)),
3692
+ maxShapeSize: Math.round($3faa2521b78398cf$var$lerpNum(a.maxShapeSize, b.maxShapeSize, t)),
3693
+ backgroundStyle: t < 0.5 ? a.backgroundStyle : b.backgroundStyle,
3694
+ paletteMode: t < 0.5 ? a.paletteMode : b.paletteMode,
3695
+ preferredStyles: mergedStyles,
3696
+ flowLineMultiplier: $3faa2521b78398cf$var$lerpNum(a.flowLineMultiplier, b.flowLineMultiplier, t),
3697
+ heroShape: t < 0.5 ? a.heroShape : b.heroShape,
3698
+ glowMultiplier: $3faa2521b78398cf$var$lerpNum(a.glowMultiplier, b.glowMultiplier, t),
3699
+ sizePower: $3faa2521b78398cf$var$lerpNum(a.sizePower, b.sizePower, t),
3700
+ invertForeground: t < 0.5 ? a.invertForeground : b.invertForeground
3701
+ };
3702
+ }
3626
3703
  function $3faa2521b78398cf$export$f1142fd7da4d6590(rng) {
3627
- return $3faa2521b78398cf$var$ARCHETYPES[Math.floor(rng() * $3faa2521b78398cf$var$ARCHETYPES.length)];
3704
+ const primary = $3faa2521b78398cf$var$ARCHETYPES[Math.floor(rng() * $3faa2521b78398cf$var$ARCHETYPES.length)];
3705
+ // ~15% chance of blending with a second archetype
3706
+ if (rng() < 0.15) {
3707
+ const secondary = $3faa2521b78398cf$var$ARCHETYPES[Math.floor(rng() * $3faa2521b78398cf$var$ARCHETYPES.length)];
3708
+ if (secondary.name !== primary.name) {
3709
+ const blendT = 0.25 + rng() * 0.25; // 25-50% blend toward secondary
3710
+ return $3faa2521b78398cf$var$blendArchetypes(primary, secondary, blendT);
3711
+ }
3712
+ }
3713
+ return primary;
3628
3714
  }
3629
3715
 
3630
3716
 
@@ -3960,6 +4046,8 @@ function $b623126c6e9cbb71$export$29a844702096332e(ctx, gitHash, config = {}) {
3960
4046
  const colorGrade = (0, $9d614e7d77fc2947$export$6d1620b367f86f7a)(rng);
3961
4047
  // ── 0e. Light direction — consistent shadow angle ──────────────
3962
4048
  const lightAngle = rng() * Math.PI * 2;
4049
+ // ── 0f. Palette evolution — hue drift direction across layers ──
4050
+ const paletteHueShift = (rng() - 0.5) * 40; // -20° to +20° total drift
3963
4051
  const scaleFactor = Math.min(width, height) / 1024;
3964
4052
  const adjustedMinSize = minShapeSize * scaleFactor;
3965
4053
  const adjustedMaxSize = maxShapeSize * scaleFactor;
@@ -4134,6 +4222,41 @@ function $b623126c6e9cbb71$export$29a844702096332e(ctx, gitHash, config = {}) {
4134
4222
  ry + (nearest.y - ry) * pull
4135
4223
  ];
4136
4224
  }
4225
+ // ── 3b. Void zone decoration — intentional negative space ────
4226
+ for (const zone of voidZones){
4227
+ // Subtle halo ring around void zones
4228
+ ctx.globalAlpha = 0.04 + rng() * 0.04;
4229
+ ctx.strokeStyle = (0, $9d614e7d77fc2947$export$f2121afcad3d553f)(colorHierarchy.accent, 0.2);
4230
+ ctx.lineWidth = 1.5 * scaleFactor;
4231
+ ctx.beginPath();
4232
+ ctx.arc(zone.x, zone.y, zone.radius, 0, Math.PI * 2);
4233
+ ctx.stroke();
4234
+ // ~50% chance: scatter tiny dots inside the void
4235
+ if (rng() < 0.5) {
4236
+ const dotCount = 3 + Math.floor(rng() * 6);
4237
+ ctx.globalAlpha = 0.06 + rng() * 0.04;
4238
+ ctx.fillStyle = (0, $9d614e7d77fc2947$export$f2121afcad3d553f)(colorHierarchy.secondary, 0.15);
4239
+ for(let d = 0; d < dotCount; d++){
4240
+ const angle = rng() * Math.PI * 2;
4241
+ const dist = rng() * zone.radius * 0.7;
4242
+ const dotR = (1 + rng() * 3) * scaleFactor;
4243
+ ctx.beginPath();
4244
+ ctx.arc(zone.x + Math.cos(angle) * dist, zone.y + Math.sin(angle) * dist, dotR, 0, Math.PI * 2);
4245
+ ctx.fill();
4246
+ }
4247
+ }
4248
+ // ~30% chance: thin concentric ring inside
4249
+ if (rng() < 0.3) {
4250
+ ctx.globalAlpha = 0.03 + rng() * 0.03;
4251
+ ctx.strokeStyle = (0, $9d614e7d77fc2947$export$f2121afcad3d553f)(colorHierarchy.dominant, 0.1);
4252
+ ctx.lineWidth = 0.5 * scaleFactor;
4253
+ const innerR = zone.radius * (0.4 + rng() * 0.3);
4254
+ ctx.beginPath();
4255
+ ctx.arc(zone.x, zone.y, innerR, 0, Math.PI * 2);
4256
+ ctx.stroke();
4257
+ }
4258
+ }
4259
+ ctx.globalAlpha = 1;
4137
4260
  // ── 4. Flow field seed values ──────────────────────────────────
4138
4261
  const fieldAngleBase = rng() * Math.PI * 2;
4139
4262
  const fieldFreq = 0.5 + rng() * 2;
@@ -4206,6 +4329,18 @@ function $b623126c6e9cbb71$export$29a844702096332e(ctx, gitHash, config = {}) {
4206
4329
  const dofFactor = 1 - layerRatio * 0.5; // 1.0 for front layer, 0.5 for back
4207
4330
  const dofStrokeScale = 0.4 + dofFactor * 0.6; // strokes thin out with depth
4208
4331
  const dofContrastReduction = layerRatio * 0.2; // colors fade toward bg
4332
+ // Color palette evolution — hue-rotate the hierarchy per layer
4333
+ const layerHierarchy = (0, $9d614e7d77fc2947$export$703ba40a4347f77a)(colorHierarchy, layerRatio, paletteHueShift);
4334
+ // Focal depth: shapes near focal points get more detail
4335
+ const focalDetailBoost = (px, py)=>{
4336
+ let minFocalDist = Infinity;
4337
+ for (const fp of focalPoints){
4338
+ const d = Math.hypot(px - fp.x, py - fp.y);
4339
+ if (d < minFocalDist) minFocalDist = d;
4340
+ }
4341
+ const maxDist = Math.hypot(width, height) * 0.5;
4342
+ return Math.max(0, 1 - minFocalDist / maxDist); // 1.0 at focal, 0.0 at edges
4343
+ };
4209
4344
  for(let i = 0; i < numShapes; i++){
4210
4345
  // Position from composition mode, then focal bias
4211
4346
  const rawPos = $b623126c6e9cbb71$var$getCompositionPosition(compositionMode, rng, width, height, i, numShapes, cx, cy);
@@ -4236,9 +4371,9 @@ function $b623126c6e9cbb71$export$29a844702096332e(ctx, gitHash, config = {}) {
4236
4371
  rotation = rotation + (angleToHero - rotation) * blendFactor * 0.4;
4237
4372
  }
4238
4373
  }
4239
- // Positional color from hierarchy + jitter
4240
- let fillBase = $b623126c6e9cbb71$var$getPositionalColor(x, y, width, height, colorHierarchy, rng);
4241
- const strokeBase = (0, $9d614e7d77fc2947$export$b49f62f0a99da0e8)(colorHierarchy, rng);
4374
+ // Positional color from hierarchy + jitter (using evolved layer palette)
4375
+ let fillBase = $b623126c6e9cbb71$var$getPositionalColor(x, y, width, height, layerHierarchy, rng);
4376
+ const strokeBase = (0, $9d614e7d77fc2947$export$b49f62f0a99da0e8)(layerHierarchy, rng);
4242
4377
  // Desaturate colors on later layers for depth
4243
4378
  if (atmosphericDesat > 0) fillBase = (0, $9d614e7d77fc2947$export$fb75607d98509d9)(fillBase, atmosphericDesat);
4244
4379
  // Temperature contrast: shift foreground shapes opposite to background
@@ -4330,6 +4465,25 @@ function $b623126c6e9cbb71$export$29a844702096332e(ctx, gitHash, config = {}) {
4330
4465
  mirrorGap: size * (0.1 + rng() * 0.3)
4331
4466
  });
4332
4467
  else (0, $9beb8f41637c29fd$export$bb35a6995ddbf32d)(ctx, shape, finalX, finalY, shapeConfig);
4468
+ // ── Glazing — luminous multi-pass transparency on ~20% of shapes ──
4469
+ if (rng() < 0.2 && size > adjustedMinSize * 2) {
4470
+ const glazePasses = 2 + Math.floor(rng() * 2);
4471
+ for(let g = 0; g < glazePasses; g++){
4472
+ const glazeScale = 1 - (g + 1) * 0.12; // progressively smaller
4473
+ const glazeAlpha = 0.08 + g * 0.04; // progressively more opaque toward center
4474
+ ctx.globalAlpha = glazeAlpha;
4475
+ (0, $9beb8f41637c29fd$export$bb35a6995ddbf32d)(ctx, shape, finalX, finalY, {
4476
+ fillColor: (0, $9d614e7d77fc2947$export$f2121afcad3d553f)(fillColor, 0.15 + g * 0.1),
4477
+ strokeColor: "rgba(0,0,0,0)",
4478
+ strokeWidth: 0,
4479
+ size: size * glazeScale,
4480
+ rotation: rotation,
4481
+ proportionType: "GOLDEN_RATIO",
4482
+ renderStyle: "fill-only",
4483
+ rng: rng
4484
+ });
4485
+ }
4486
+ }
4333
4487
  shapePositions.push({
4334
4488
  x: finalX,
4335
4489
  y: finalY,
@@ -4367,7 +4521,10 @@ function $b623126c6e9cbb71$export$29a844702096332e(ctx, gitHash, config = {}) {
4367
4521
  }
4368
4522
  }
4369
4523
  // ── 5d. Recursive nesting ──────────────────────────────────
4370
- if (size > adjustedMaxSize * 0.4 && rng() < 0.15) {
4524
+ // Focal depth: shapes near focal points get more detail
4525
+ const focalProximity = focalDetailBoost(finalX, finalY);
4526
+ const nestingChance = 0.15 + focalProximity * 0.15; // 15-30% near focal
4527
+ if (size > adjustedMaxSize * 0.4 && rng() < nestingChance) {
4371
4528
  const innerCount = 1 + Math.floor(rng() * 3);
4372
4529
  for(let n = 0; n < innerCount; n++){
4373
4530
  // Pick inner shape from palette affinities
@@ -4392,7 +4549,8 @@ function $b623126c6e9cbb71$export$29a844702096332e(ctx, gitHash, config = {}) {
4392
4549
  }
4393
4550
  }
4394
4551
  // ── 5e. Shape constellations — pre-composed groups ─────────
4395
- if (size > adjustedMaxSize * 0.35 && rng() < 0.12) {
4552
+ const constellationChance = 0.12 + focalProximity * 0.1; // 12-22% near focal
4553
+ if (size > adjustedMaxSize * 0.35 && rng() < constellationChance) {
4396
4554
  const constellation = $b623126c6e9cbb71$var$CONSTELLATIONS[Math.floor(rng() * $b623126c6e9cbb71$var$CONSTELLATIONS.length)];
4397
4555
  const members = constellation.build(rng, size);
4398
4556
  const groupRotation = rng() * Math.PI * 2;
@@ -4496,7 +4654,41 @@ function $b623126c6e9cbb71$export$29a844702096332e(ctx, gitHash, config = {}) {
4496
4654
  prevY = fy;
4497
4655
  }
4498
4656
  }
4499
- // ── 6b. Apply symmetry mirroring ─────────────────────────────────
4657
+ // ── 6b. Motion/energy lines short directional bursts ─────────
4658
+ const energyArchetypes = [
4659
+ "dense-chaotic",
4660
+ "cosmic",
4661
+ "neon-glow",
4662
+ "bold-graphic"
4663
+ ];
4664
+ const hasEnergyLines = energyArchetypes.some((a)=>archetype.name.includes(a)) || rng() < 0.25;
4665
+ if (hasEnergyLines && shapePositions.length > 0) {
4666
+ const energyCount = 5 + Math.floor(rng() * 10);
4667
+ ctx.lineCap = "round";
4668
+ for(let e = 0; e < energyCount; e++){
4669
+ // Pick a random shape to radiate from
4670
+ const source = shapePositions[Math.floor(rng() * shapePositions.length)];
4671
+ const burstCount = 2 + Math.floor(rng() * 4);
4672
+ const baseAngle = flowAngle(source.x, source.y);
4673
+ for(let b = 0; b < burstCount; b++){
4674
+ const angle = baseAngle + (rng() - 0.5) * 1.2;
4675
+ const lineLen = (source.size * 0.3 + rng() * source.size * 0.5) * scaleFactor * 0.3;
4676
+ const startDist = source.size * 0.5;
4677
+ const sx = source.x + Math.cos(angle) * startDist;
4678
+ const sy = source.y + Math.sin(angle) * startDist;
4679
+ const ex = sx + Math.cos(angle) * lineLen;
4680
+ const ey = sy + Math.sin(angle) * lineLen;
4681
+ ctx.globalAlpha = 0.04 + rng() * 0.06;
4682
+ ctx.strokeStyle = (0, $9d614e7d77fc2947$export$f2121afcad3d553f)((0, $9d614e7d77fc2947$export$90ad0e6170cf6af5)((0, $9d614e7d77fc2947$export$b49f62f0a99da0e8)(colorHierarchy, rng), bgLum), 0.3);
4683
+ ctx.lineWidth = (0.5 + rng() * 1.5) * scaleFactor;
4684
+ ctx.beginPath();
4685
+ ctx.moveTo(sx, sy);
4686
+ ctx.lineTo(ex, ey);
4687
+ ctx.stroke();
4688
+ }
4689
+ }
4690
+ }
4691
+ // ── 6c. Apply symmetry mirroring ─────────────────────────────────
4500
4692
  if (symmetryMode !== "none") {
4501
4693
  const canvas = ctx.canvas;
4502
4694
  ctx.save();
@@ -4607,6 +4799,44 @@ function $b623126c6e9cbb71$export$29a844702096332e(ctx, gitHash, config = {}) {
4607
4799
  ctx.restore();
4608
4800
  ctx.globalCompositeOperation = "source-over";
4609
4801
  }
4802
+ // ── 11. Signature mark — unique geometric chop from hash prefix ──
4803
+ {
4804
+ const sigRng = (0, $461134e0b6ce0619$export$eaf9227667332084)((0, $461134e0b6ce0619$export$e9cc707de01b7042)(gitHash, 42));
4805
+ const sigSize = Math.min(width, height) * 0.025;
4806
+ // Bottom-right corner with padding
4807
+ const sigX = width - sigSize * 2.5;
4808
+ const sigY = height - sigSize * 2.5;
4809
+ const sigSegments = 4 + Math.floor(sigRng() * 4); // 4-7 segments
4810
+ const sigColor = (0, $9d614e7d77fc2947$export$f2121afcad3d553f)(colorHierarchy.accent, 0.15);
4811
+ ctx.save();
4812
+ ctx.globalAlpha = 0.12 + sigRng() * 0.08;
4813
+ ctx.translate(sigX, sigY);
4814
+ ctx.strokeStyle = sigColor;
4815
+ ctx.fillStyle = (0, $9d614e7d77fc2947$export$f2121afcad3d553f)(colorHierarchy.dominant, 0.06);
4816
+ ctx.lineWidth = Math.max(0.5, 0.8 * scaleFactor);
4817
+ // Outer ring
4818
+ ctx.beginPath();
4819
+ ctx.arc(0, 0, sigSize, 0, Math.PI * 2);
4820
+ ctx.stroke();
4821
+ ctx.fill();
4822
+ // Inner geometric pattern — unique per hash
4823
+ ctx.beginPath();
4824
+ for(let s = 0; s < sigSegments; s++){
4825
+ const angle1 = sigRng() * Math.PI * 2;
4826
+ const angle2 = sigRng() * Math.PI * 2;
4827
+ const r1 = sigSize * (0.2 + sigRng() * 0.6);
4828
+ const r2 = sigSize * (0.2 + sigRng() * 0.6);
4829
+ ctx.moveTo(Math.cos(angle1) * r1, Math.sin(angle1) * r1);
4830
+ ctx.lineTo(Math.cos(angle2) * r2, Math.sin(angle2) * r2);
4831
+ }
4832
+ ctx.stroke();
4833
+ // Center dot
4834
+ ctx.beginPath();
4835
+ ctx.arc(0, 0, sigSize * 0.12, 0, Math.PI * 2);
4836
+ ctx.fillStyle = sigColor;
4837
+ ctx.fill();
4838
+ ctx.restore();
4839
+ }
4610
4840
  ctx.globalAlpha = 1;
4611
4841
  }
4612
4842