git-hash-art 0.6.0 → 0.7.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
@@ -412,6 +412,30 @@ function $9d614e7d77fc2947$export$51ea55f869b7e0d3(hex, target, amount) {
412
412
  const [h, s, l] = $9d614e7d77fc2947$var$hexToHsl(hex);
413
413
  return $9d614e7d77fc2947$var$hslToHex($9d614e7d77fc2947$var$shiftHueToward(h, target, amount), s, l);
414
414
  }
415
+ function $9d614e7d77fc2947$export$5c6e3c2b59b7fbbe(hex) {
416
+ const [r, g, b] = $9d614e7d77fc2947$var$hexToRgb(hex).map((c)=>{
417
+ const s = c / 255;
418
+ return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
419
+ });
420
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b;
421
+ }
422
+ function $9d614e7d77fc2947$export$90ad0e6170cf6af5(fgHex, bgLuminance, minContrast = 0.15) {
423
+ const fgLum = $9d614e7d77fc2947$export$5c6e3c2b59b7fbbe(fgHex);
424
+ const diff = Math.abs(fgLum - bgLuminance);
425
+ if (diff >= minContrast) return fgHex;
426
+ const [h, s, l] = $9d614e7d77fc2947$var$hexToHsl(fgHex);
427
+ if (bgLuminance > 0.5) {
428
+ // Light background — darken and boost saturation
429
+ const targetL = Math.max(0.08, l - (minContrast - diff) * 1.5);
430
+ const targetS = Math.min(1, s + 0.2);
431
+ return $9d614e7d77fc2947$var$hslToHex(h, targetS, targetL);
432
+ } else {
433
+ // Dark background — lighten and boost saturation
434
+ const targetL = Math.min(0.92, l + (minContrast - diff) * 1.5);
435
+ const targetS = Math.min(1, s + 0.15);
436
+ return $9d614e7d77fc2947$var$hslToHex(h, targetS, targetL);
437
+ }
438
+ }
415
439
 
416
440
 
417
441
 
@@ -1192,10 +1216,172 @@ const $d63629e16208c310$export$c2fc138f94dd4b2a = {
1192
1216
  };
1193
1217
 
1194
1218
 
1219
+ /**
1220
+ * Procedural shape generators — hash-derived shapes that are unique
1221
+ * per generation. Unlike the fixed shape library, these produce geometry
1222
+ * that doesn't repeat across hashes.
1223
+ *
1224
+ * All draw functions accept an RNG via the config parameter so the
1225
+ * shapes are deterministic from the hash.
1226
+ */ const $a7241acce45d5513$export$580f80cfb9de73bc = (ctx, size, config)=>{
1227
+ const rng = config?.rng ?? Math.random;
1228
+ const r = size / 2;
1229
+ const numPoints = 5 + Math.floor(rng() * 5); // 5-9 lobes
1230
+ const points = [];
1231
+ for(let i = 0; i < numPoints; i++){
1232
+ const angle = i / numPoints * Math.PI * 2;
1233
+ const jitter = 0.5 + rng() * 0.5; // radius varies 50-100%
1234
+ points.push({
1235
+ x: Math.cos(angle) * r * jitter,
1236
+ y: Math.sin(angle) * r * jitter
1237
+ });
1238
+ }
1239
+ ctx.beginPath();
1240
+ // Start at midpoint between last and first point
1241
+ const last = points[points.length - 1];
1242
+ const first = points[0];
1243
+ ctx.moveTo((last.x + first.x) / 2, (last.y + first.y) / 2);
1244
+ for(let i = 0; i < numPoints; i++){
1245
+ const curr = points[i];
1246
+ const next = points[(i + 1) % numPoints];
1247
+ const midX = (curr.x + next.x) / 2;
1248
+ const midY = (curr.y + next.y) / 2;
1249
+ ctx.quadraticCurveTo(curr.x, curr.y, midX, midY);
1250
+ }
1251
+ ctx.closePath();
1252
+ };
1253
+ const $a7241acce45d5513$export$7a6094023f0902a6 = (ctx, size, config)=>{
1254
+ const rng = config?.rng ?? Math.random;
1255
+ const r = size / 2;
1256
+ const sides = 3 + Math.floor(rng() * 10); // 3-12 sides
1257
+ const jitterAmount = 0.1 + rng() * 0.4; // 10-50% vertex displacement
1258
+ ctx.beginPath();
1259
+ for(let i = 0; i < sides; i++){
1260
+ const angle = i / sides * Math.PI * 2 - Math.PI / 2;
1261
+ const radiusJitter = 1 - jitterAmount + rng() * jitterAmount * 2;
1262
+ const x = Math.cos(angle) * r * radiusJitter;
1263
+ const y = Math.sin(angle) * r * radiusJitter;
1264
+ if (i === 0) ctx.moveTo(x, y);
1265
+ else ctx.lineTo(x, y);
1266
+ }
1267
+ ctx.closePath();
1268
+ };
1269
+ const $a7241acce45d5513$export$ef56b4a8316e47d5 = (ctx, size, config)=>{
1270
+ const rng = config?.rng ?? Math.random;
1271
+ const r = size / 2;
1272
+ // Frequency ratios — small integers produce recognizable patterns
1273
+ const freqA = 1 + Math.floor(rng() * 5); // 1-5
1274
+ const freqB = 1 + Math.floor(rng() * 5); // 1-5
1275
+ const phase = rng() * Math.PI; // phase offset
1276
+ const steps = 120;
1277
+ ctx.beginPath();
1278
+ for(let i = 0; i <= steps; i++){
1279
+ const t = i / steps * Math.PI * 2;
1280
+ const x = Math.sin(freqA * t + phase) * r;
1281
+ const y = Math.sin(freqB * t) * r;
1282
+ if (i === 0) ctx.moveTo(x, y);
1283
+ else ctx.lineTo(x, y);
1284
+ }
1285
+ ctx.closePath();
1286
+ };
1287
+ const $a7241acce45d5513$export$1db9219b4f34658c = (ctx, size, config)=>{
1288
+ const rng = config?.rng ?? Math.random;
1289
+ const r = size / 2;
1290
+ // Exponent range: 0.3 (spiky astroid) to 5 (rounded rectangle)
1291
+ const n = 0.3 + rng() * 4.7;
1292
+ const steps = 120;
1293
+ ctx.beginPath();
1294
+ for(let i = 0; i <= steps; i++){
1295
+ const t = i / steps * Math.PI * 2;
1296
+ const cosT = Math.cos(t);
1297
+ const sinT = Math.sin(t);
1298
+ // Superellipse parametric form
1299
+ const x = Math.sign(cosT) * Math.pow(Math.abs(cosT), 2 / n) * r;
1300
+ const y = Math.sign(sinT) * Math.pow(Math.abs(sinT), 2 / n) * r;
1301
+ if (i === 0) ctx.moveTo(x, y);
1302
+ else ctx.lineTo(x, y);
1303
+ }
1304
+ ctx.closePath();
1305
+ };
1306
+ const $a7241acce45d5513$export$b027c64d22b01985 = (ctx, size, config)=>{
1307
+ const rng = config?.rng ?? Math.random;
1308
+ const scale = size / 2;
1309
+ // R = outer radius, r = inner radius, d = pen distance from inner center
1310
+ const R = 1;
1311
+ const r = 0.2 + rng() * 0.6; // 0.2-0.8
1312
+ const d = 0.3 + rng() * 0.7; // 0.3-1.0
1313
+ // Number of full rotations needed to close the curve
1314
+ const gcd = (a, b)=>{
1315
+ const ai = Math.round(a * 1000);
1316
+ const bi = Math.round(b * 1000);
1317
+ const g = (x, y)=>y === 0 ? x : g(y, x % y);
1318
+ return g(ai, bi) / 1000;
1319
+ };
1320
+ const period = r / gcd(R, r);
1321
+ const maxT = Math.min(period, 10) * Math.PI * 2; // cap at 10 rotations
1322
+ const steps = Math.min(600, Math.floor(maxT * 20));
1323
+ ctx.beginPath();
1324
+ for(let i = 0; i <= steps; i++){
1325
+ const t = i / steps * maxT;
1326
+ const x = ((R - r) * Math.cos(t) + d * Math.cos((R - r) / r * t)) * scale / (1 + d);
1327
+ const y = ((R - r) * Math.sin(t) - d * Math.sin((R - r) / r * t)) * scale / (1 + d);
1328
+ if (i === 0) ctx.moveTo(x, y);
1329
+ else ctx.lineTo(x, y);
1330
+ }
1331
+ ctx.closePath();
1332
+ };
1333
+ const $a7241acce45d5513$export$7608ccd03bfb705d = (ctx, size, config)=>{
1334
+ const rng = config?.rng ?? Math.random;
1335
+ const r = size / 2;
1336
+ const rings = 2 + Math.floor(rng() * 4); // 2-5 rings
1337
+ const freq = 3 + Math.floor(rng() * 12); // 3-14 waves per ring
1338
+ const amp = 0.05 + rng() * 0.15; // 5-20% of radius
1339
+ ctx.beginPath();
1340
+ for(let ring = 0; ring < rings; ring++){
1341
+ const baseR = r * (0.3 + ring / rings * 0.7);
1342
+ const steps = 80;
1343
+ for(let i = 0; i <= steps; i++){
1344
+ const t = i / steps * Math.PI * 2;
1345
+ const wave = Math.sin(t * freq + ring * 1.5) * baseR * amp;
1346
+ const x = Math.cos(t) * (baseR + wave);
1347
+ const y = Math.sin(t) * (baseR + wave);
1348
+ if (i === 0) ctx.moveTo(x, y);
1349
+ else ctx.lineTo(x, y);
1350
+ }
1351
+ }
1352
+ };
1353
+ const $a7241acce45d5513$export$11a377e7498bb523 = (ctx, size, config)=>{
1354
+ const rng = config?.rng ?? Math.random;
1355
+ const r = size / 2;
1356
+ const k = 2 + Math.floor(rng() * 6); // 2-7 petal parameter
1357
+ const steps = 200;
1358
+ ctx.beginPath();
1359
+ for(let i = 0; i <= steps; i++){
1360
+ const theta = i / steps * Math.PI * 2 * (k % 2 === 0 ? 1 : 2);
1361
+ const rr = Math.cos(k * theta) * r;
1362
+ const x = rr * Math.cos(theta);
1363
+ const y = rr * Math.sin(theta);
1364
+ if (i === 0) ctx.moveTo(x, y);
1365
+ else ctx.lineTo(x, y);
1366
+ }
1367
+ ctx.closePath();
1368
+ };
1369
+ const $a7241acce45d5513$export$40cfb4c637f2fbb5 = {
1370
+ blob: $a7241acce45d5513$export$580f80cfb9de73bc,
1371
+ ngon: $a7241acce45d5513$export$7a6094023f0902a6,
1372
+ lissajous: $a7241acce45d5513$export$ef56b4a8316e47d5,
1373
+ superellipse: $a7241acce45d5513$export$1db9219b4f34658c,
1374
+ spirograph: $a7241acce45d5513$export$b027c64d22b01985,
1375
+ waveRing: $a7241acce45d5513$export$7608ccd03bfb705d,
1376
+ rose: $a7241acce45d5513$export$11a377e7498bb523
1377
+ };
1378
+
1379
+
1195
1380
  const $701ba7c7229ef06d$export$4ff7fc6f1af248b5 = {
1196
1381
  ...(0, $f225038c018b3815$export$492753207a5258e1),
1197
1382
  ...(0, $8bde0a7ee87832b5$export$dbe318a13ce51887),
1198
- ...(0, $d63629e16208c310$export$c2fc138f94dd4b2a)
1383
+ ...(0, $d63629e16208c310$export$c2fc138f94dd4b2a),
1384
+ ...(0, $a7241acce45d5513$export$40cfb4c637f2fbb5)
1199
1385
  };
1200
1386
 
1201
1387
 
@@ -1399,7 +1585,9 @@ function $9beb8f41637c29fd$export$bb35a6995ddbf32d(ctx, shape, x, y, config) {
1399
1585
  ctx.lineWidth = strokeWidth;
1400
1586
  const drawFunction = (0, $701ba7c7229ef06d$export$4ff7fc6f1af248b5)[shape];
1401
1587
  if (drawFunction) {
1402
- drawFunction(ctx, size);
1588
+ drawFunction(ctx, size, {
1589
+ rng: rng
1590
+ });
1403
1591
  $9beb8f41637c29fd$var$applyRenderStyle(ctx, renderStyle, fillColor, strokeColor, strokeWidth, size, rng);
1404
1592
  }
1405
1593
  // Reset shadow so patterns aren't double-glowed
@@ -1688,6 +1876,15 @@ const $b623126c6e9cbb71$var$SACRED_SHAPES = [
1688
1876
  "torus",
1689
1877
  "eggOfLife"
1690
1878
  ];
1879
+ const $b623126c6e9cbb71$var$PROCEDURAL_SHAPES = [
1880
+ "blob",
1881
+ "ngon",
1882
+ "lissajous",
1883
+ "superellipse",
1884
+ "spirograph",
1885
+ "waveRing",
1886
+ "rose"
1887
+ ];
1691
1888
  const $b623126c6e9cbb71$var$COMPOSITION_MODES = [
1692
1889
  "radial",
1693
1890
  "flow-field",
@@ -1700,12 +1897,14 @@ function $b623126c6e9cbb71$var$pickShape(rng, layerRatio, shapeNames) {
1700
1897
  const basicW = 1 - layerRatio * 0.6;
1701
1898
  const complexW = 0.3 + layerRatio * 0.3;
1702
1899
  const sacredW = 0.1 + layerRatio * 0.4;
1703
- const total = basicW + complexW + sacredW;
1900
+ const proceduralW = 0.25 + layerRatio * 0.2; // always present, grows with depth
1901
+ const total = basicW + complexW + sacredW + proceduralW;
1704
1902
  const roll = rng() * total;
1705
1903
  let pool;
1706
1904
  if (roll < basicW) pool = $b623126c6e9cbb71$var$BASIC_SHAPES;
1707
1905
  else if (roll < basicW + complexW) pool = $b623126c6e9cbb71$var$COMPLEX_SHAPES;
1708
- else pool = $b623126c6e9cbb71$var$SACRED_SHAPES;
1906
+ else if (roll < basicW + complexW + sacredW) pool = $b623126c6e9cbb71$var$SACRED_SHAPES;
1907
+ else pool = $b623126c6e9cbb71$var$PROCEDURAL_SHAPES;
1709
1908
  const available = pool.filter((s)=>shapeNames.includes(s));
1710
1909
  if (available.length === 0) return shapeNames[Math.floor(rng() * shapeNames.length)];
1711
1910
  return available[Math.floor(rng() * available.length)];
@@ -1888,6 +2087,8 @@ function $b623126c6e9cbb71$export$29a844702096332e(ctx, gitHash, config = {}) {
1888
2087
  // ── 1. Background ──────────────────────────────────────────────
1889
2088
  const bgRadius = Math.hypot(cx, cy);
1890
2089
  $b623126c6e9cbb71$var$drawBackground(ctx, archetype.backgroundStyle, bgStart, bgEnd, width, height, cx, cy, bgRadius, rng, colors);
2090
+ // Compute average background luminance for contrast enforcement
2091
+ const bgLum = ((0, $9d614e7d77fc2947$export$5c6e3c2b59b7fbbe)(bgStart) + (0, $9d614e7d77fc2947$export$5c6e3c2b59b7fbbe)(bgEnd)) / 2;
1891
2092
  // ── 1b. Layered background (Feature G) ─────────────────────────
1892
2093
  // Draw large, very faint shapes to give the background texture
1893
2094
  const bgShapeCount = 3 + Math.floor(rng() * 4);
@@ -1999,8 +2200,8 @@ function $b623126c6e9cbb71$export$29a844702096332e(ctx, gitHash, config = {}) {
1999
2200
  const heroShape = heroPool.filter((s)=>shapeNames.includes(s))[Math.floor(rng() * heroPool.filter((s)=>shapeNames.includes(s)).length)] || shapeNames[Math.floor(rng() * shapeNames.length)];
2000
2201
  const heroSize = adjustedMaxSize * (0.8 + rng() * 0.5);
2001
2202
  const heroRotation = rng() * 360;
2002
- const heroFill = (0, $9d614e7d77fc2947$export$f2121afcad3d553f)((0, $9d614e7d77fc2947$export$59539d800dbe6858)(colors[Math.floor(rng() * colors.length)], rng, 0.05), 0.15 + rng() * 0.2);
2003
- const heroStroke = (0, $9d614e7d77fc2947$export$59539d800dbe6858)(colors[Math.floor(rng() * colors.length)], rng, 0.05);
2203
+ const heroFill = (0, $9d614e7d77fc2947$export$f2121afcad3d553f)((0, $9d614e7d77fc2947$export$90ad0e6170cf6af5)((0, $9d614e7d77fc2947$export$59539d800dbe6858)(colors[Math.floor(rng() * colors.length)], rng, 0.05), bgLum), 0.15 + rng() * 0.2);
2204
+ const heroStroke = (0, $9d614e7d77fc2947$export$90ad0e6170cf6af5)((0, $9d614e7d77fc2947$export$59539d800dbe6858)(colors[Math.floor(rng() * colors.length)], rng, 0.05), bgLum);
2004
2205
  ctx.globalAlpha = 0.5 + rng() * 0.2;
2005
2206
  (0, $9beb8f41637c29fd$export$bb35a6995ddbf32d)(ctx, heroShape, heroFocal.x, heroFocal.y, {
2006
2207
  fillColor: heroFill,
@@ -2062,8 +2263,8 @@ function $b623126c6e9cbb71$export$29a844702096332e(ctx, gitHash, config = {}) {
2062
2263
  if (atmosphericDesat > 0) fillBase = (0, $9d614e7d77fc2947$export$fb75607d98509d9)(fillBase, atmosphericDesat);
2063
2264
  // Temperature contrast: shift foreground shapes opposite to background
2064
2265
  if (fgTempTarget) fillBase = (0, $9d614e7d77fc2947$export$51ea55f869b7e0d3)(fillBase, fgTempTarget, 0.15 + layerRatio * 0.1);
2065
- const fillColor = (0, $9d614e7d77fc2947$export$59539d800dbe6858)(fillBase, rng, 0.06);
2066
- const strokeColor = (0, $9d614e7d77fc2947$export$59539d800dbe6858)(strokeBase, rng, 0.05);
2266
+ const fillColor = (0, $9d614e7d77fc2947$export$90ad0e6170cf6af5)((0, $9d614e7d77fc2947$export$59539d800dbe6858)(fillBase, rng, 0.06), bgLum);
2267
+ const strokeColor = (0, $9d614e7d77fc2947$export$90ad0e6170cf6af5)((0, $9d614e7d77fc2947$export$59539d800dbe6858)(strokeBase, rng, 0.05), bgLum);
2067
2268
  // Semi-transparent fill
2068
2269
  const fillAlpha = 0.2 + rng() * 0.5;
2069
2270
  const transparentFill = (0, $9d614e7d77fc2947$export$f2121afcad3d553f)(fillColor, fillAlpha);
@@ -2137,7 +2338,7 @@ function $b623126c6e9cbb71$export$29a844702096332e(ctx, gitHash, config = {}) {
2137
2338
  const steps = 30 + Math.floor(rng() * 40);
2138
2339
  const stepLen = (3 + rng() * 5) * scaleFactor;
2139
2340
  const startWidth = (1 + rng() * 3) * scaleFactor;
2140
- const lineColor = (0, $9d614e7d77fc2947$export$f2121afcad3d553f)(colors[Math.floor(rng() * colors.length)], 0.4);
2341
+ const lineColor = (0, $9d614e7d77fc2947$export$f2121afcad3d553f)((0, $9d614e7d77fc2947$export$90ad0e6170cf6af5)(colors[Math.floor(rng() * colors.length)], bgLum), 0.4);
2141
2342
  const lineAlpha = 0.06 + rng() * 0.1;
2142
2343
  // Draw as individual segments with tapering width
2143
2344
  let prevX = fx;
@@ -2226,7 +2427,7 @@ function $b623126c6e9cbb71$export$29a844702096332e(ctx, gitHash, config = {}) {
2226
2427
  const cpx = mx + -dy / (dist || 1) * bulge;
2227
2428
  const cpy = my + dx / (dist || 1) * bulge;
2228
2429
  ctx.globalAlpha = 0.06 + rng() * 0.1;
2229
- ctx.strokeStyle = (0, $9d614e7d77fc2947$export$f2121afcad3d553f)(colors[Math.floor(rng() * colors.length)], 0.3);
2430
+ ctx.strokeStyle = (0, $9d614e7d77fc2947$export$f2121afcad3d553f)((0, $9d614e7d77fc2947$export$90ad0e6170cf6af5)(colors[Math.floor(rng() * colors.length)], bgLum), 0.3);
2230
2431
  ctx.beginPath();
2231
2432
  ctx.moveTo(a.x, a.y);
2232
2433
  ctx.quadraticCurveTo(cpx, cpy, b.x, b.y);