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/ALGORITHM.md +30 -3
- package/CHANGELOG.md +8 -0
- package/dist/browser.js +211 -10
- package/dist/browser.js.map +1 -1
- package/dist/main.js +211 -10
- package/dist/main.js.map +1 -1
- package/dist/module.js +211 -10
- package/dist/module.js.map +1 -1
- package/package.json +1 -1
- package/src/lib/canvas/colors.ts +45 -0
- package/src/lib/canvas/draw.ts +1 -1
- package/src/lib/canvas/shapes/index.ts +2 -0
- package/src/lib/canvas/shapes/procedural.ts +209 -0
- package/src/lib/render.ts +24 -8
package/ALGORITHM.md
CHANGED
|
@@ -11,12 +11,13 @@ Hash String
|
|
|
11
11
|
│
|
|
12
12
|
├─► Archetype Selection (1 of 10 visual personalities)
|
|
13
13
|
│
|
|
14
|
-
├─► Color Scheme (palette mode from archetype + temperature mode)
|
|
14
|
+
├─► Color Scheme (palette mode from archetype + temperature mode + contrast enforcement)
|
|
15
15
|
│
|
|
16
16
|
└─► Rendering Pipeline (parameters overridden by archetype)
|
|
17
17
|
│
|
|
18
18
|
0. Archetype Override (gridSize, layers, opacity, sizes, styles)
|
|
19
19
|
1. Background Layer (7 styles: radial, linear, solid, multi-stop)
|
|
20
|
+
1a. Background Luminance → contrast enforcement threshold
|
|
20
21
|
1b. Layered Background (faint shapes + concentric rings)
|
|
21
22
|
2. Composition Mode Selection
|
|
22
23
|
2b. Symmetry Mode Selection (none / bilateral / quad)
|
|
@@ -27,7 +28,8 @@ Hash String
|
|
|
27
28
|
│ ├─ Blend Mode (per-layer compositing)
|
|
28
29
|
│ ├─ Render Style (archetype-preferred + random mix)
|
|
29
30
|
│ ├─ Position (composition mode + focal bias + density check)
|
|
30
|
-
│ ├─ Shape Selection (
|
|
31
|
+
│ ├─ Shape Selection (4 categories: basic, complex, sacred, procedural)
|
|
32
|
+
│ ├─ Contrast Enforcement (ensure readability vs background)
|
|
31
33
|
│ ├─ Atmospheric Depth (desaturation on later layers)
|
|
32
34
|
│ ├─ Temperature Contrast (foreground opposite to background)
|
|
33
35
|
│ ├─ Styling (transparency, glow, gradients, color jitter)
|
|
@@ -267,13 +269,25 @@ Later layers progressively desaturate their colors (0% on layer 0, up to 30% on
|
|
|
267
269
|
|
|
268
270
|
### Shape Selection (Layer-Weighted)
|
|
269
271
|
|
|
270
|
-
Shapes are divided into
|
|
272
|
+
Shapes are divided into four categories with weights that shift across layers:
|
|
271
273
|
|
|
272
274
|
| Category | Shapes | Early layers | Late layers |
|
|
273
275
|
|----------|--------|-------------|-------------|
|
|
274
276
|
| **Basic** | circle, square, triangle, hexagon, diamond, cube | High weight | Low weight |
|
|
275
277
|
| **Complex** | star, platonic solid, fibonacci spiral, islamic pattern, celtic knot, merkaba, fractal | Medium | Medium-high |
|
|
276
278
|
| **Sacred** | mandala, flower of life, tree of life, Metatron's cube, Sri Yantra, seed of life, vesica piscis, torus, egg of life | Low | High |
|
|
279
|
+
| **Procedural** | blob, ngon, lissajous, superellipse, spirograph, waveRing, rose | Medium (always present) | Medium-high |
|
|
280
|
+
|
|
281
|
+
Procedural shapes are hash-derived — their geometry is generated from the RNG, so every hash produces unique shapes that don't exist in any other generation. See the Procedural Shapes section below for details.
|
|
282
|
+
|
|
283
|
+
### Contrast Enforcement
|
|
284
|
+
|
|
285
|
+
After color selection, every foreground color (fills, strokes, flow lines, connecting curves) is checked against the average background luminance. If the luminance difference is below the minimum threshold (0.15), the color is adjusted:
|
|
286
|
+
|
|
287
|
+
- **Light backgrounds** — foreground colors are darkened and saturated
|
|
288
|
+
- **Dark backgrounds** — foreground colors are lightened and saturated
|
|
289
|
+
|
|
290
|
+
This prevents the white-on-white and dark-on-dark readability problems that occur when light palette modes (pastel-light, high-contrast) combine with light background styles (solid-light, radial-light).
|
|
277
291
|
|
|
278
292
|
### Size Distribution
|
|
279
293
|
|
|
@@ -366,6 +380,19 @@ Mathematically precise sacred geometry patterns:
|
|
|
366
380
|
- **Torus** — 2D projection of a torus via line segments
|
|
367
381
|
- **Egg of Life** — 7 circles in tight hexagonal packing
|
|
368
382
|
|
|
383
|
+
### Procedural Shapes
|
|
384
|
+
Hash-derived shapes whose geometry is generated from the RNG. Every hash produces unique shapes that don't exist in any other generation:
|
|
385
|
+
|
|
386
|
+
| Shape | Algorithm | Hash Controls |
|
|
387
|
+
|-------|-----------|---------------|
|
|
388
|
+
| **Blob** | Smooth closed curve via quadratic bezier through 5-9 control points arranged around a circle | Number of lobes (5-9), radius jitter per lobe (50-100%) |
|
|
389
|
+
| **Ngon** | Irregular polygon with independent vertex displacement | Side count (3-12), vertex jitter amount (10-50%) |
|
|
390
|
+
| **Lissajous** | Parametric curve `x = sin(a*t + φ), y = sin(b*t)` | Frequency ratios a,b (1-5 each), phase offset φ |
|
|
391
|
+
| **Superellipse** | `|x|^n + |y|^n = 1` rendered parametrically | Exponent n: 0.3 (spiky astroid) → 2 (circle) → 5 (rounded rectangle) |
|
|
392
|
+
| **Spirograph** | Hypotrochoid curve `(R-r)cos(t) + d*cos((R-r)t/r)` | Inner radius ratio r (0.2-0.8), pen distance d (0.3-1.0) |
|
|
393
|
+
| **Wave Ring** | Concentric rings with sinusoidal radial displacement | Ring count (2-5), wave frequency (3-14), amplitude (5-20%) |
|
|
394
|
+
| **Rose** | Polar rose curve `r = cos(k*θ)` | Petal parameter k (2-7), producing k or 2k petals |
|
|
395
|
+
|
|
369
396
|
## Configuration
|
|
370
397
|
|
|
371
398
|
All parameters are exposed via `GenerationConfig`:
|
package/CHANGELOG.md
CHANGED
|
@@ -4,8 +4,16 @@ All notable changes to this project will be documented in this file. Dates are d
|
|
|
4
4
|
|
|
5
5
|
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
6
6
|
|
|
7
|
+
#### [0.7.0](https://github.com/gfargo/git-hash-art/compare/0.6.0...0.7.0)
|
|
8
|
+
|
|
9
|
+
- feat: procedural shape generators and contrast enforcement [`#13`](https://github.com/gfargo/git-hash-art/pull/13)
|
|
10
|
+
- feat: procedural shapes and contrast enforcement [`4f018ab`](https://github.com/gfargo/git-hash-art/commit/4f018abb4c89849954ccc941ee7e9ab468231f78)
|
|
11
|
+
- docs: update ALGORITHM.md with procedural shapes and contrast enforcement [`3e044fd`](https://github.com/gfargo/git-hash-art/commit/3e044fd940fbc0f62e3a9696fa815145cf315f67)
|
|
12
|
+
|
|
7
13
|
#### [0.6.0](https://github.com/gfargo/git-hash-art/compare/0.5.0...0.6.0)
|
|
8
14
|
|
|
15
|
+
> 19 March 2026
|
|
16
|
+
|
|
9
17
|
- feat: archetype system, palette modes, background variety, and CLI [`#12`](https://github.com/gfargo/git-hash-art/pull/12)
|
|
10
18
|
- feat: archetype system for dramatically different visual personalities [`2a1b919`](https://github.com/gfargo/git-hash-art/commit/2a1b919c51d3bfbd9d5c7a381ea5e104f81df2f6)
|
|
11
19
|
- feat: add CLI for generating art from terminal [`184372a`](https://github.com/gfargo/git-hash-art/commit/184372a584f68031bf44379f385f2e78691f98aa)
|
package/dist/browser.js
CHANGED
|
@@ -403,6 +403,30 @@ function $b5a262d09b87e373$export$51ea55f869b7e0d3(hex, target, amount) {
|
|
|
403
403
|
const [h, s, l] = $b5a262d09b87e373$var$hexToHsl(hex);
|
|
404
404
|
return $b5a262d09b87e373$var$hslToHex($b5a262d09b87e373$var$shiftHueToward(h, target, amount), s, l);
|
|
405
405
|
}
|
|
406
|
+
function $b5a262d09b87e373$export$5c6e3c2b59b7fbbe(hex) {
|
|
407
|
+
const [r, g, b] = $b5a262d09b87e373$var$hexToRgb(hex).map((c)=>{
|
|
408
|
+
const s = c / 255;
|
|
409
|
+
return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
|
|
410
|
+
});
|
|
411
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
412
|
+
}
|
|
413
|
+
function $b5a262d09b87e373$export$90ad0e6170cf6af5(fgHex, bgLuminance, minContrast = 0.15) {
|
|
414
|
+
const fgLum = $b5a262d09b87e373$export$5c6e3c2b59b7fbbe(fgHex);
|
|
415
|
+
const diff = Math.abs(fgLum - bgLuminance);
|
|
416
|
+
if (diff >= minContrast) return fgHex;
|
|
417
|
+
const [h, s, l] = $b5a262d09b87e373$var$hexToHsl(fgHex);
|
|
418
|
+
if (bgLuminance > 0.5) {
|
|
419
|
+
// Light background — darken and boost saturation
|
|
420
|
+
const targetL = Math.max(0.08, l - (minContrast - diff) * 1.5);
|
|
421
|
+
const targetS = Math.min(1, s + 0.2);
|
|
422
|
+
return $b5a262d09b87e373$var$hslToHex(h, targetS, targetL);
|
|
423
|
+
} else {
|
|
424
|
+
// Dark background — lighten and boost saturation
|
|
425
|
+
const targetL = Math.min(0.92, l + (minContrast - diff) * 1.5);
|
|
426
|
+
const targetS = Math.min(1, s + 0.15);
|
|
427
|
+
return $b5a262d09b87e373$var$hslToHex(h, targetS, targetL);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
406
430
|
|
|
407
431
|
|
|
408
432
|
|
|
@@ -1183,10 +1207,172 @@ const $77711f013715e6da$export$c2fc138f94dd4b2a = {
|
|
|
1183
1207
|
};
|
|
1184
1208
|
|
|
1185
1209
|
|
|
1210
|
+
/**
|
|
1211
|
+
* Procedural shape generators — hash-derived shapes that are unique
|
|
1212
|
+
* per generation. Unlike the fixed shape library, these produce geometry
|
|
1213
|
+
* that doesn't repeat across hashes.
|
|
1214
|
+
*
|
|
1215
|
+
* All draw functions accept an RNG via the config parameter so the
|
|
1216
|
+
* shapes are deterministic from the hash.
|
|
1217
|
+
*/ const $2899cc29bfcdb86b$export$580f80cfb9de73bc = (ctx, size, config)=>{
|
|
1218
|
+
const rng = config?.rng ?? Math.random;
|
|
1219
|
+
const r = size / 2;
|
|
1220
|
+
const numPoints = 5 + Math.floor(rng() * 5); // 5-9 lobes
|
|
1221
|
+
const points = [];
|
|
1222
|
+
for(let i = 0; i < numPoints; i++){
|
|
1223
|
+
const angle = i / numPoints * Math.PI * 2;
|
|
1224
|
+
const jitter = 0.5 + rng() * 0.5; // radius varies 50-100%
|
|
1225
|
+
points.push({
|
|
1226
|
+
x: Math.cos(angle) * r * jitter,
|
|
1227
|
+
y: Math.sin(angle) * r * jitter
|
|
1228
|
+
});
|
|
1229
|
+
}
|
|
1230
|
+
ctx.beginPath();
|
|
1231
|
+
// Start at midpoint between last and first point
|
|
1232
|
+
const last = points[points.length - 1];
|
|
1233
|
+
const first = points[0];
|
|
1234
|
+
ctx.moveTo((last.x + first.x) / 2, (last.y + first.y) / 2);
|
|
1235
|
+
for(let i = 0; i < numPoints; i++){
|
|
1236
|
+
const curr = points[i];
|
|
1237
|
+
const next = points[(i + 1) % numPoints];
|
|
1238
|
+
const midX = (curr.x + next.x) / 2;
|
|
1239
|
+
const midY = (curr.y + next.y) / 2;
|
|
1240
|
+
ctx.quadraticCurveTo(curr.x, curr.y, midX, midY);
|
|
1241
|
+
}
|
|
1242
|
+
ctx.closePath();
|
|
1243
|
+
};
|
|
1244
|
+
const $2899cc29bfcdb86b$export$7a6094023f0902a6 = (ctx, size, config)=>{
|
|
1245
|
+
const rng = config?.rng ?? Math.random;
|
|
1246
|
+
const r = size / 2;
|
|
1247
|
+
const sides = 3 + Math.floor(rng() * 10); // 3-12 sides
|
|
1248
|
+
const jitterAmount = 0.1 + rng() * 0.4; // 10-50% vertex displacement
|
|
1249
|
+
ctx.beginPath();
|
|
1250
|
+
for(let i = 0; i < sides; i++){
|
|
1251
|
+
const angle = i / sides * Math.PI * 2 - Math.PI / 2;
|
|
1252
|
+
const radiusJitter = 1 - jitterAmount + rng() * jitterAmount * 2;
|
|
1253
|
+
const x = Math.cos(angle) * r * radiusJitter;
|
|
1254
|
+
const y = Math.sin(angle) * r * radiusJitter;
|
|
1255
|
+
if (i === 0) ctx.moveTo(x, y);
|
|
1256
|
+
else ctx.lineTo(x, y);
|
|
1257
|
+
}
|
|
1258
|
+
ctx.closePath();
|
|
1259
|
+
};
|
|
1260
|
+
const $2899cc29bfcdb86b$export$ef56b4a8316e47d5 = (ctx, size, config)=>{
|
|
1261
|
+
const rng = config?.rng ?? Math.random;
|
|
1262
|
+
const r = size / 2;
|
|
1263
|
+
// Frequency ratios — small integers produce recognizable patterns
|
|
1264
|
+
const freqA = 1 + Math.floor(rng() * 5); // 1-5
|
|
1265
|
+
const freqB = 1 + Math.floor(rng() * 5); // 1-5
|
|
1266
|
+
const phase = rng() * Math.PI; // phase offset
|
|
1267
|
+
const steps = 120;
|
|
1268
|
+
ctx.beginPath();
|
|
1269
|
+
for(let i = 0; i <= steps; i++){
|
|
1270
|
+
const t = i / steps * Math.PI * 2;
|
|
1271
|
+
const x = Math.sin(freqA * t + phase) * r;
|
|
1272
|
+
const y = Math.sin(freqB * t) * r;
|
|
1273
|
+
if (i === 0) ctx.moveTo(x, y);
|
|
1274
|
+
else ctx.lineTo(x, y);
|
|
1275
|
+
}
|
|
1276
|
+
ctx.closePath();
|
|
1277
|
+
};
|
|
1278
|
+
const $2899cc29bfcdb86b$export$1db9219b4f34658c = (ctx, size, config)=>{
|
|
1279
|
+
const rng = config?.rng ?? Math.random;
|
|
1280
|
+
const r = size / 2;
|
|
1281
|
+
// Exponent range: 0.3 (spiky astroid) to 5 (rounded rectangle)
|
|
1282
|
+
const n = 0.3 + rng() * 4.7;
|
|
1283
|
+
const steps = 120;
|
|
1284
|
+
ctx.beginPath();
|
|
1285
|
+
for(let i = 0; i <= steps; i++){
|
|
1286
|
+
const t = i / steps * Math.PI * 2;
|
|
1287
|
+
const cosT = Math.cos(t);
|
|
1288
|
+
const sinT = Math.sin(t);
|
|
1289
|
+
// Superellipse parametric form
|
|
1290
|
+
const x = Math.sign(cosT) * Math.pow(Math.abs(cosT), 2 / n) * r;
|
|
1291
|
+
const y = Math.sign(sinT) * Math.pow(Math.abs(sinT), 2 / n) * r;
|
|
1292
|
+
if (i === 0) ctx.moveTo(x, y);
|
|
1293
|
+
else ctx.lineTo(x, y);
|
|
1294
|
+
}
|
|
1295
|
+
ctx.closePath();
|
|
1296
|
+
};
|
|
1297
|
+
const $2899cc29bfcdb86b$export$b027c64d22b01985 = (ctx, size, config)=>{
|
|
1298
|
+
const rng = config?.rng ?? Math.random;
|
|
1299
|
+
const scale = size / 2;
|
|
1300
|
+
// R = outer radius, r = inner radius, d = pen distance from inner center
|
|
1301
|
+
const R = 1;
|
|
1302
|
+
const r = 0.2 + rng() * 0.6; // 0.2-0.8
|
|
1303
|
+
const d = 0.3 + rng() * 0.7; // 0.3-1.0
|
|
1304
|
+
// Number of full rotations needed to close the curve
|
|
1305
|
+
const gcd = (a, b)=>{
|
|
1306
|
+
const ai = Math.round(a * 1000);
|
|
1307
|
+
const bi = Math.round(b * 1000);
|
|
1308
|
+
const g = (x, y)=>y === 0 ? x : g(y, x % y);
|
|
1309
|
+
return g(ai, bi) / 1000;
|
|
1310
|
+
};
|
|
1311
|
+
const period = r / gcd(R, r);
|
|
1312
|
+
const maxT = Math.min(period, 10) * Math.PI * 2; // cap at 10 rotations
|
|
1313
|
+
const steps = Math.min(600, Math.floor(maxT * 20));
|
|
1314
|
+
ctx.beginPath();
|
|
1315
|
+
for(let i = 0; i <= steps; i++){
|
|
1316
|
+
const t = i / steps * maxT;
|
|
1317
|
+
const x = ((R - r) * Math.cos(t) + d * Math.cos((R - r) / r * t)) * scale / (1 + d);
|
|
1318
|
+
const y = ((R - r) * Math.sin(t) - d * Math.sin((R - r) / r * t)) * scale / (1 + d);
|
|
1319
|
+
if (i === 0) ctx.moveTo(x, y);
|
|
1320
|
+
else ctx.lineTo(x, y);
|
|
1321
|
+
}
|
|
1322
|
+
ctx.closePath();
|
|
1323
|
+
};
|
|
1324
|
+
const $2899cc29bfcdb86b$export$7608ccd03bfb705d = (ctx, size, config)=>{
|
|
1325
|
+
const rng = config?.rng ?? Math.random;
|
|
1326
|
+
const r = size / 2;
|
|
1327
|
+
const rings = 2 + Math.floor(rng() * 4); // 2-5 rings
|
|
1328
|
+
const freq = 3 + Math.floor(rng() * 12); // 3-14 waves per ring
|
|
1329
|
+
const amp = 0.05 + rng() * 0.15; // 5-20% of radius
|
|
1330
|
+
ctx.beginPath();
|
|
1331
|
+
for(let ring = 0; ring < rings; ring++){
|
|
1332
|
+
const baseR = r * (0.3 + ring / rings * 0.7);
|
|
1333
|
+
const steps = 80;
|
|
1334
|
+
for(let i = 0; i <= steps; i++){
|
|
1335
|
+
const t = i / steps * Math.PI * 2;
|
|
1336
|
+
const wave = Math.sin(t * freq + ring * 1.5) * baseR * amp;
|
|
1337
|
+
const x = Math.cos(t) * (baseR + wave);
|
|
1338
|
+
const y = Math.sin(t) * (baseR + wave);
|
|
1339
|
+
if (i === 0) ctx.moveTo(x, y);
|
|
1340
|
+
else ctx.lineTo(x, y);
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
};
|
|
1344
|
+
const $2899cc29bfcdb86b$export$11a377e7498bb523 = (ctx, size, config)=>{
|
|
1345
|
+
const rng = config?.rng ?? Math.random;
|
|
1346
|
+
const r = size / 2;
|
|
1347
|
+
const k = 2 + Math.floor(rng() * 6); // 2-7 petal parameter
|
|
1348
|
+
const steps = 200;
|
|
1349
|
+
ctx.beginPath();
|
|
1350
|
+
for(let i = 0; i <= steps; i++){
|
|
1351
|
+
const theta = i / steps * Math.PI * 2 * (k % 2 === 0 ? 1 : 2);
|
|
1352
|
+
const rr = Math.cos(k * theta) * r;
|
|
1353
|
+
const x = rr * Math.cos(theta);
|
|
1354
|
+
const y = rr * Math.sin(theta);
|
|
1355
|
+
if (i === 0) ctx.moveTo(x, y);
|
|
1356
|
+
else ctx.lineTo(x, y);
|
|
1357
|
+
}
|
|
1358
|
+
ctx.closePath();
|
|
1359
|
+
};
|
|
1360
|
+
const $2899cc29bfcdb86b$export$40cfb4c637f2fbb5 = {
|
|
1361
|
+
blob: $2899cc29bfcdb86b$export$580f80cfb9de73bc,
|
|
1362
|
+
ngon: $2899cc29bfcdb86b$export$7a6094023f0902a6,
|
|
1363
|
+
lissajous: $2899cc29bfcdb86b$export$ef56b4a8316e47d5,
|
|
1364
|
+
superellipse: $2899cc29bfcdb86b$export$1db9219b4f34658c,
|
|
1365
|
+
spirograph: $2899cc29bfcdb86b$export$b027c64d22b01985,
|
|
1366
|
+
waveRing: $2899cc29bfcdb86b$export$7608ccd03bfb705d,
|
|
1367
|
+
rose: $2899cc29bfcdb86b$export$11a377e7498bb523
|
|
1368
|
+
};
|
|
1369
|
+
|
|
1370
|
+
|
|
1186
1371
|
const $e41b41d8dcf837ad$export$4ff7fc6f1af248b5 = {
|
|
1187
1372
|
...(0, $44f5b87a40c9680b$export$492753207a5258e1),
|
|
1188
1373
|
...(0, $f0f1a7293548e501$export$dbe318a13ce51887),
|
|
1189
|
-
...(0, $77711f013715e6da$export$c2fc138f94dd4b2a)
|
|
1374
|
+
...(0, $77711f013715e6da$export$c2fc138f94dd4b2a),
|
|
1375
|
+
...(0, $2899cc29bfcdb86b$export$40cfb4c637f2fbb5)
|
|
1190
1376
|
};
|
|
1191
1377
|
|
|
1192
1378
|
|
|
@@ -1390,7 +1576,9 @@ function $e0f99502ff383dd8$export$bb35a6995ddbf32d(ctx, shape, x, y, config) {
|
|
|
1390
1576
|
ctx.lineWidth = strokeWidth;
|
|
1391
1577
|
const drawFunction = (0, $e41b41d8dcf837ad$export$4ff7fc6f1af248b5)[shape];
|
|
1392
1578
|
if (drawFunction) {
|
|
1393
|
-
drawFunction(ctx, size
|
|
1579
|
+
drawFunction(ctx, size, {
|
|
1580
|
+
rng: rng
|
|
1581
|
+
});
|
|
1394
1582
|
$e0f99502ff383dd8$var$applyRenderStyle(ctx, renderStyle, fillColor, strokeColor, strokeWidth, size, rng);
|
|
1395
1583
|
}
|
|
1396
1584
|
// Reset shadow so patterns aren't double-glowed
|
|
@@ -1679,6 +1867,15 @@ const $1f63dc64b5593c73$var$SACRED_SHAPES = [
|
|
|
1679
1867
|
"torus",
|
|
1680
1868
|
"eggOfLife"
|
|
1681
1869
|
];
|
|
1870
|
+
const $1f63dc64b5593c73$var$PROCEDURAL_SHAPES = [
|
|
1871
|
+
"blob",
|
|
1872
|
+
"ngon",
|
|
1873
|
+
"lissajous",
|
|
1874
|
+
"superellipse",
|
|
1875
|
+
"spirograph",
|
|
1876
|
+
"waveRing",
|
|
1877
|
+
"rose"
|
|
1878
|
+
];
|
|
1682
1879
|
const $1f63dc64b5593c73$var$COMPOSITION_MODES = [
|
|
1683
1880
|
"radial",
|
|
1684
1881
|
"flow-field",
|
|
@@ -1691,12 +1888,14 @@ function $1f63dc64b5593c73$var$pickShape(rng, layerRatio, shapeNames) {
|
|
|
1691
1888
|
const basicW = 1 - layerRatio * 0.6;
|
|
1692
1889
|
const complexW = 0.3 + layerRatio * 0.3;
|
|
1693
1890
|
const sacredW = 0.1 + layerRatio * 0.4;
|
|
1694
|
-
const
|
|
1891
|
+
const proceduralW = 0.25 + layerRatio * 0.2; // always present, grows with depth
|
|
1892
|
+
const total = basicW + complexW + sacredW + proceduralW;
|
|
1695
1893
|
const roll = rng() * total;
|
|
1696
1894
|
let pool;
|
|
1697
1895
|
if (roll < basicW) pool = $1f63dc64b5593c73$var$BASIC_SHAPES;
|
|
1698
1896
|
else if (roll < basicW + complexW) pool = $1f63dc64b5593c73$var$COMPLEX_SHAPES;
|
|
1699
|
-
else pool = $1f63dc64b5593c73$var$SACRED_SHAPES;
|
|
1897
|
+
else if (roll < basicW + complexW + sacredW) pool = $1f63dc64b5593c73$var$SACRED_SHAPES;
|
|
1898
|
+
else pool = $1f63dc64b5593c73$var$PROCEDURAL_SHAPES;
|
|
1700
1899
|
const available = pool.filter((s)=>shapeNames.includes(s));
|
|
1701
1900
|
if (available.length === 0) return shapeNames[Math.floor(rng() * shapeNames.length)];
|
|
1702
1901
|
return available[Math.floor(rng() * available.length)];
|
|
@@ -1879,6 +2078,8 @@ function $1f63dc64b5593c73$export$29a844702096332e(ctx, gitHash, config = {}) {
|
|
|
1879
2078
|
// ── 1. Background ──────────────────────────────────────────────
|
|
1880
2079
|
const bgRadius = Math.hypot(cx, cy);
|
|
1881
2080
|
$1f63dc64b5593c73$var$drawBackground(ctx, archetype.backgroundStyle, bgStart, bgEnd, width, height, cx, cy, bgRadius, rng, colors);
|
|
2081
|
+
// Compute average background luminance for contrast enforcement
|
|
2082
|
+
const bgLum = ((0, $b5a262d09b87e373$export$5c6e3c2b59b7fbbe)(bgStart) + (0, $b5a262d09b87e373$export$5c6e3c2b59b7fbbe)(bgEnd)) / 2;
|
|
1882
2083
|
// ── 1b. Layered background (Feature G) ─────────────────────────
|
|
1883
2084
|
// Draw large, very faint shapes to give the background texture
|
|
1884
2085
|
const bgShapeCount = 3 + Math.floor(rng() * 4);
|
|
@@ -1990,8 +2191,8 @@ function $1f63dc64b5593c73$export$29a844702096332e(ctx, gitHash, config = {}) {
|
|
|
1990
2191
|
const heroShape = heroPool.filter((s)=>shapeNames.includes(s))[Math.floor(rng() * heroPool.filter((s)=>shapeNames.includes(s)).length)] || shapeNames[Math.floor(rng() * shapeNames.length)];
|
|
1991
2192
|
const heroSize = adjustedMaxSize * (0.8 + rng() * 0.5);
|
|
1992
2193
|
const heroRotation = rng() * 360;
|
|
1993
|
-
const heroFill = (0, $b5a262d09b87e373$export$f2121afcad3d553f)((0, $b5a262d09b87e373$export$59539d800dbe6858)(colors[Math.floor(rng() * colors.length)], rng, 0.05), 0.15 + rng() * 0.2);
|
|
1994
|
-
const heroStroke = (0, $b5a262d09b87e373$export$59539d800dbe6858)(colors[Math.floor(rng() * colors.length)], rng, 0.05);
|
|
2194
|
+
const heroFill = (0, $b5a262d09b87e373$export$f2121afcad3d553f)((0, $b5a262d09b87e373$export$90ad0e6170cf6af5)((0, $b5a262d09b87e373$export$59539d800dbe6858)(colors[Math.floor(rng() * colors.length)], rng, 0.05), bgLum), 0.15 + rng() * 0.2);
|
|
2195
|
+
const heroStroke = (0, $b5a262d09b87e373$export$90ad0e6170cf6af5)((0, $b5a262d09b87e373$export$59539d800dbe6858)(colors[Math.floor(rng() * colors.length)], rng, 0.05), bgLum);
|
|
1995
2196
|
ctx.globalAlpha = 0.5 + rng() * 0.2;
|
|
1996
2197
|
(0, $e0f99502ff383dd8$export$bb35a6995ddbf32d)(ctx, heroShape, heroFocal.x, heroFocal.y, {
|
|
1997
2198
|
fillColor: heroFill,
|
|
@@ -2053,8 +2254,8 @@ function $1f63dc64b5593c73$export$29a844702096332e(ctx, gitHash, config = {}) {
|
|
|
2053
2254
|
if (atmosphericDesat > 0) fillBase = (0, $b5a262d09b87e373$export$fb75607d98509d9)(fillBase, atmosphericDesat);
|
|
2054
2255
|
// Temperature contrast: shift foreground shapes opposite to background
|
|
2055
2256
|
if (fgTempTarget) fillBase = (0, $b5a262d09b87e373$export$51ea55f869b7e0d3)(fillBase, fgTempTarget, 0.15 + layerRatio * 0.1);
|
|
2056
|
-
const fillColor = (0, $b5a262d09b87e373$export$59539d800dbe6858)(fillBase, rng, 0.06);
|
|
2057
|
-
const strokeColor = (0, $b5a262d09b87e373$export$59539d800dbe6858)(strokeBase, rng, 0.05);
|
|
2257
|
+
const fillColor = (0, $b5a262d09b87e373$export$90ad0e6170cf6af5)((0, $b5a262d09b87e373$export$59539d800dbe6858)(fillBase, rng, 0.06), bgLum);
|
|
2258
|
+
const strokeColor = (0, $b5a262d09b87e373$export$90ad0e6170cf6af5)((0, $b5a262d09b87e373$export$59539d800dbe6858)(strokeBase, rng, 0.05), bgLum);
|
|
2058
2259
|
// Semi-transparent fill
|
|
2059
2260
|
const fillAlpha = 0.2 + rng() * 0.5;
|
|
2060
2261
|
const transparentFill = (0, $b5a262d09b87e373$export$f2121afcad3d553f)(fillColor, fillAlpha);
|
|
@@ -2128,7 +2329,7 @@ function $1f63dc64b5593c73$export$29a844702096332e(ctx, gitHash, config = {}) {
|
|
|
2128
2329
|
const steps = 30 + Math.floor(rng() * 40);
|
|
2129
2330
|
const stepLen = (3 + rng() * 5) * scaleFactor;
|
|
2130
2331
|
const startWidth = (1 + rng() * 3) * scaleFactor;
|
|
2131
|
-
const lineColor = (0, $b5a262d09b87e373$export$f2121afcad3d553f)(colors[Math.floor(rng() * colors.length)], 0.4);
|
|
2332
|
+
const lineColor = (0, $b5a262d09b87e373$export$f2121afcad3d553f)((0, $b5a262d09b87e373$export$90ad0e6170cf6af5)(colors[Math.floor(rng() * colors.length)], bgLum), 0.4);
|
|
2132
2333
|
const lineAlpha = 0.06 + rng() * 0.1;
|
|
2133
2334
|
// Draw as individual segments with tapering width
|
|
2134
2335
|
let prevX = fx;
|
|
@@ -2217,7 +2418,7 @@ function $1f63dc64b5593c73$export$29a844702096332e(ctx, gitHash, config = {}) {
|
|
|
2217
2418
|
const cpx = mx + -dy / (dist || 1) * bulge;
|
|
2218
2419
|
const cpy = my + dx / (dist || 1) * bulge;
|
|
2219
2420
|
ctx.globalAlpha = 0.06 + rng() * 0.1;
|
|
2220
|
-
ctx.strokeStyle = (0, $b5a262d09b87e373$export$f2121afcad3d553f)(colors[Math.floor(rng() * colors.length)], 0.3);
|
|
2421
|
+
ctx.strokeStyle = (0, $b5a262d09b87e373$export$f2121afcad3d553f)((0, $b5a262d09b87e373$export$90ad0e6170cf6af5)(colors[Math.floor(rng() * colors.length)], bgLum), 0.3);
|
|
2221
2422
|
ctx.beginPath();
|
|
2222
2423
|
ctx.moveTo(a.x, a.y);
|
|
2223
2424
|
ctx.quadraticCurveTo(cpx, cpy, b.x, b.y);
|