git-hash-art 0.10.1 → 0.12.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/.github/workflows/deploy-www.yml +13 -3
- package/ALGORITHM.md +76 -24
- package/CHANGELOG.md +18 -0
- package/dist/browser.js +938 -251
- package/dist/browser.js.map +1 -1
- package/dist/main.js +940 -251
- package/dist/main.js.map +1 -1
- package/dist/module.js +940 -251
- package/dist/module.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/performance.test.ts +243 -0
- package/src/__tests__/phase-timing.test.ts +260 -0
- package/src/__tests__/profile-pipeline.test.ts +160 -0
- package/src/lib/archetypes.ts +29 -0
- package/src/lib/canvas/colors.ts +30 -11
- package/src/lib/canvas/draw.ts +147 -50
- package/src/lib/canvas/shapes/complex.ts +19 -10
- package/src/lib/canvas/shapes/sacred.ts +16 -17
- package/src/lib/render.ts +663 -204
|
@@ -3,21 +3,30 @@ name: Deploy git-hash-art-www
|
|
|
3
3
|
on:
|
|
4
4
|
release:
|
|
5
5
|
types: [published]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
inputs:
|
|
8
|
+
version:
|
|
9
|
+
description: 'Package version to deploy (e.g. 0.10.0)'
|
|
10
|
+
required: true
|
|
6
11
|
|
|
7
12
|
jobs:
|
|
8
13
|
bump-www:
|
|
9
14
|
runs-on: ubuntu-latest
|
|
10
15
|
steps:
|
|
11
|
-
- name: Extract version
|
|
16
|
+
- name: Extract version
|
|
12
17
|
id: version
|
|
13
18
|
run: |
|
|
14
|
-
|
|
19
|
+
if [ -n "${{ github.event.inputs.version }}" ]; then
|
|
20
|
+
VERSION="${{ github.event.inputs.version }}"
|
|
21
|
+
else
|
|
22
|
+
VERSION="${GITHUB_REF_NAME#v}"
|
|
23
|
+
fi
|
|
15
24
|
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
|
16
25
|
|
|
17
26
|
- name: Clone git-hash-art-www
|
|
18
27
|
uses: actions/checkout@v4
|
|
19
28
|
with:
|
|
20
|
-
repository: gfargo/git-hash-art-www
|
|
29
|
+
repository: gfargo/v0-git-hash-art-www
|
|
21
30
|
token: ${{ secrets.WWW_DEPLOY_PAT }}
|
|
22
31
|
path: www
|
|
23
32
|
|
|
@@ -29,6 +38,7 @@ jobs:
|
|
|
29
38
|
- name: Install pnpm
|
|
30
39
|
uses: pnpm/action-setup@v4
|
|
31
40
|
with:
|
|
41
|
+
version: 9
|
|
32
42
|
run_install: false
|
|
33
43
|
|
|
34
44
|
- name: Update git-hash-art dependency
|
package/ALGORITHM.md
CHANGED
|
@@ -26,14 +26,15 @@ Hash String
|
|
|
26
26
|
0c. Shape Palette (curated via affinity graph)
|
|
27
27
|
0d. Color Grade (hue + intensity for final tone)
|
|
28
28
|
0e. Light Direction (consistent shadow angle)
|
|
29
|
+
0f. Palette Evolution Direction (±20° hue drift across layers)
|
|
29
30
|
1. Background Layer (7 styles: radial, linear, solid, multi-stop)
|
|
30
31
|
└─ Gradient Mesh Overlay (3-4 radial color control points)
|
|
31
32
|
1a. Background Luminance → contrast enforcement threshold
|
|
32
33
|
1b. Layered Background (archetype-coherent shapes + concentric rings)
|
|
33
34
|
1c. Background Pattern Layer (dot grid / diagonal lines / tessellation)
|
|
34
|
-
2. Composition Mode Selection (6 modes including golden-spiral)
|
|
35
|
+
2. Composition Mode Selection (archetype-aware, 6 modes including golden-spiral)
|
|
35
36
|
2b. Symmetry Mode Selection (none / bilateral / quad)
|
|
36
|
-
3. Focal Points (rule-of-thirds biased) + Void Zones
|
|
37
|
+
3. Focal Points (rule-of-thirds biased) + Void Zones (archetype-aware density)
|
|
37
38
|
3b. Void Zone Decoration (halos, scattered dots, concentric rings)
|
|
38
39
|
4. Flow Field Initialization (simplex noise FBM)
|
|
39
40
|
4a. Noise Size Modulation (terrain-like size variation from noise field)
|
|
@@ -54,26 +55,27 @@ Hash String
|
|
|
54
55
|
│ ├─ Shadow & Highlight (drop shadow + specular highlight per shape)
|
|
55
56
|
│ ├─ Organic Edges (~15% watercolor bleed)
|
|
56
57
|
│ ├─ Edge Erosion (watercolor + hand-drawn styles get irregular boundary bites)
|
|
57
|
-
│ ├─ 5a. Tangent Placement (~25% nudge toward nearest shape edge)
|
|
58
|
+
│ ├─ 5a. Tangent Placement (~25% nudge toward nearest shape edge, spatial grid lookup)
|
|
58
59
|
│ ├─ 5b. Shape Mirroring (~40% of basic shapes get reflected copies)
|
|
59
60
|
│ ├─ 5c. Size Echo (~20% of large shapes spawn trailing copies)
|
|
60
61
|
│ ├─ 5d. Recursive Nesting (~15% of large shapes, palette-aware)
|
|
61
|
-
│
|
|
62
|
-
5f.
|
|
63
|
-
|
|
62
|
+
│ ├─ 5e. Shape Constellations (~12% of large shapes, pre-composed groups)
|
|
63
|
+
│ └─ 5f. Rhythm Placement (~12% of medium-large shapes, geometric progressions)
|
|
64
|
+
5g. Layered Masking / Cutout Portals (~18% of images)
|
|
65
|
+
6. Flow-Line Pass (variable color, pressure, branching, void-aware)
|
|
64
66
|
6b. Motion/Energy Lines (directional bursts from shapes)
|
|
65
67
|
6c. Layered Transparency / Glazing (~20% of shapes get multi-pass redraws)
|
|
66
68
|
7. Symmetry Mirroring (bilateral-x, bilateral-y, or quad)
|
|
67
|
-
8. Noise Texture Overlay
|
|
68
|
-
9. Vignette (radial edge darkening)
|
|
69
|
-
10. Organic Connecting Curves
|
|
69
|
+
8. Noise Texture Overlay (batched ImageData buffer)
|
|
70
|
+
9. Vignette (palette-tinted radial edge darkening)
|
|
71
|
+
10. Organic Connecting Curves (proximity-aware)
|
|
70
72
|
11. Post-Processing
|
|
71
73
|
├─ Color Grading (unified tone overlay)
|
|
72
74
|
├─ Chromatic Aberration (neon/cosmic/ethereal only)
|
|
73
75
|
├─ Bloom (neon/cosmic only)
|
|
74
76
|
└─ Gradient Map (~35% chance, luminance-mapped two-color overlay)
|
|
75
77
|
11b. Generative Borders (archetype-driven decorative frames)
|
|
76
|
-
12. Signature Mark (deterministic geometric chop mark)
|
|
78
|
+
12. Signature Mark (density-aware placement, deterministic geometric chop mark)
|
|
77
79
|
```
|
|
78
80
|
|
|
79
81
|
## 1. Deterministic RNG
|
|
@@ -116,6 +118,7 @@ Each archetype controls:
|
|
|
116
118
|
| `heroShape` | Whether to draw a dominant focal shape |
|
|
117
119
|
| `glowMultiplier` | Glow probability scaling (0 = none, 3 = heavy) |
|
|
118
120
|
| `sizePower` | Size distribution curve (0.5 = uniform, 2.8 = many tiny) |
|
|
121
|
+
| `preferredCompositions` | Weighted composition mode selection (e.g., radial, golden-spiral) |
|
|
119
122
|
|
|
120
123
|
### The 17 Archetypes
|
|
121
124
|
|
|
@@ -155,7 +158,7 @@ Each archetype controls:
|
|
|
155
158
|
|
|
156
159
|
- **Blend ratio:** 25–50% (the secondary archetype never dominates)
|
|
157
160
|
- **Numeric parameters** (`gridSize`, `layers`, `baseOpacity`, `minShapeSize`, etc.) are linearly interpolated between the two archetypes
|
|
158
|
-
- **Style arrays** (`preferredStyles`) are merged — the primary's
|
|
161
|
+
- **Style arrays** (`preferredStyles`, `preferredCompositions`) are merged — the primary's entries come first, then any unique entries from the secondary
|
|
159
162
|
- **Categorical parameters** (`backgroundStyle`, `paletteMode`) use the primary's value when the blend ratio is below 50%, otherwise the secondary's
|
|
160
163
|
- **Boolean parameters** (`heroShape`) use the primary's value
|
|
161
164
|
|
|
@@ -192,9 +195,9 @@ Color generation uses the `color-scheme` library seeded from the hash, then appl
|
|
|
192
195
|
|
|
193
196
|
After generating the raw palette, colors are organized into a **hierarchy** with weighted selection:
|
|
194
197
|
|
|
195
|
-
- **Dominant (60%)** — the most-used color, selected as the palette entry closest to the average hue
|
|
196
|
-
- **
|
|
197
|
-
- **
|
|
198
|
+
- **Dominant (60%)** — the most-used color, selected as the palette entry with the highest **chroma** (saturation × lightness vibrancy, where vibrancy peaks at L=0.5). This picks the most visually prominent color rather than the one closest to the average hue.
|
|
199
|
+
- **Accent (15%)** — the color most distant from the dominant in hue, providing maximum contrast for visual punctuation
|
|
200
|
+
- **Secondary (25%)** — the remaining color with the highest saturation
|
|
198
201
|
|
|
199
202
|
`pickHierarchyColor(hierarchy, rng)` rolls against these weights so compositions naturally converge on a dominant tone without being monotonous.
|
|
200
203
|
|
|
@@ -328,7 +331,7 @@ The average luminance of the two background colors is computed and stored. This
|
|
|
328
331
|
|
|
329
332
|
### Composition Modes
|
|
330
333
|
|
|
331
|
-
Each image uses one of
|
|
334
|
+
Each image uses one of 6 composition strategies for shape placement. Composition mode selection is **archetype-aware**: each archetype declares a `preferredCompositions` array, and selection is 70% from the archetype's preferred modes / 30% from the full set. This ensures archetypes get compositions that suit their character while preserving variety.
|
|
332
335
|
|
|
333
336
|
| Mode | Behavior |
|
|
334
337
|
| ---- | -------- |
|
|
@@ -358,7 +361,12 @@ Symmetry is applied by drawing the canvas image onto itself with `scale(-1, 1)`
|
|
|
358
361
|
|
|
359
362
|
1–2 **focal points** are placed with 70% bias toward rule-of-thirds intersections (the remaining 30% are placed randomly within the central 60% of the canvas). Each focal point has a `strength` (0.3–0.7) that pulls nearby shapes toward it via `applyFocalBias`.
|
|
360
363
|
|
|
361
|
-
|
|
364
|
+
**Void zones** are placed with **archetype-aware logic**:
|
|
365
|
+
- **Dense archetypes** (gridSize ≥ 8, e.g., `dense-chaotic`, `cosmic`, `op-art`, `stipple-portrait`): **0 void zones** — these archetypes thrive on density, and voids would undermine their character
|
|
366
|
+
- **Minimal archetypes** (gridSize ≤ 3, e.g., `minimal-spacious`, `bold-graphic`, `watercolor-wash`): 1–2 void zones placed at **golden-ratio positions** (1/φ and 1−1/φ along each axis, with slight jitter) for intentional, harmonious negative space
|
|
367
|
+
- **Other archetypes**: 1–2 void zones placed randomly within the central 70% of the canvas
|
|
368
|
+
|
|
369
|
+
Shapes landing inside a void zone have an 85% chance of being skipped, creating breathing room in the composition.
|
|
362
370
|
|
|
363
371
|
### Void Zone Decoration
|
|
364
372
|
|
|
@@ -410,7 +418,7 @@ For each shape in a layer:
|
|
|
410
418
|
|
|
411
419
|
1. **Position:** Composition mode generates a candidate position, then `applyFocalBias` pulls it toward the nearest focal point
|
|
412
420
|
2. **Void check:** 85% skip chance if inside a void zone
|
|
413
|
-
3. **Density check:**
|
|
421
|
+
3. **Density check:** Uses the **spatial hash grid** (see Performance section) for O(1) lookups — if local density exceeds 15% of `shapesPerLayer`, 60% skip chance
|
|
414
422
|
4. **Size:** Power-curve distribution controlled by `archetype.sizePower` — higher values produce more small shapes
|
|
415
423
|
5. **Shape selection:** `pickShapeFromPalette` with size-constraint filtering
|
|
416
424
|
6. **Rotation:** Flow-field angle in flow-field mode (±15° jitter); random otherwise
|
|
@@ -435,7 +443,7 @@ Every shape receives lighting effects based on a single consistent light directi
|
|
|
435
443
|
**Specular Highlight:**
|
|
436
444
|
- Position: 15% of shape size along the light direction from center
|
|
437
445
|
- Radius: 35% of shape size
|
|
438
|
-
- Gradient:
|
|
446
|
+
- Gradient: **tinted** highlight at 18% opacity → 5% → 0% (radial falloff). The highlight color blends 15% of the shape's fill color RGB with 85% white, producing warm or cool highlights that match the shape rather than pure white spots.
|
|
439
447
|
- Composited via `soft-light` to interact naturally with the shape's fill color
|
|
440
448
|
- Only applied to shapes larger than 15px (tiny shapes don't benefit)
|
|
441
449
|
|
|
@@ -443,7 +451,7 @@ The combination creates a subtle 3D effect where shapes appear to float above th
|
|
|
443
451
|
|
|
444
452
|
### 5a. Tangent Placement
|
|
445
453
|
|
|
446
|
-
~25% of shapes are nudged toward the nearest previously-placed shape so their edges "kiss." The algorithm
|
|
454
|
+
~25% of shapes are nudged toward the nearest previously-placed shape so their edges "kiss." The algorithm uses the **spatial hash grid** for O(1) nearest-neighbor lookup (searching within 3× `adjustedMaxSize`), computes the target distance (sum of half-sizes), and repositions the current shape along the angle between them. This creates organic clustering where shapes feel intentionally arranged rather than randomly scattered.
|
|
447
455
|
|
|
448
456
|
### 5b. Shape Mirroring
|
|
449
457
|
|
|
@@ -480,7 +488,20 @@ The mirror copy is drawn at 70% opacity and 95% size (decreasing for radial-4),
|
|
|
480
488
|
|
|
481
489
|
Each member shape uses hierarchy colors with HSL jitter and affinity-aware render styles. Members that fall outside the canvas bounds are skipped.
|
|
482
490
|
|
|
483
|
-
### 5f.
|
|
491
|
+
### 5f. Rhythm Placement
|
|
492
|
+
|
|
493
|
+
~12% of shapes larger than 25% of `adjustedMaxSize` spawn a **rhythmic sequence** — a deliberate geometric progression of 3–6 copies of the same shape along a line:
|
|
494
|
+
|
|
495
|
+
- **Direction:** Random angle from the parent shape
|
|
496
|
+
- **Spacing:** 80–140% of the parent shape's size between each copy
|
|
497
|
+
- **Size decay:** Each copy is 70–85% the size of the previous one, creating a diminishing progression
|
|
498
|
+
- **Rotation:** Progressive rotation (+12° per step) adds a gentle twist to the sequence
|
|
499
|
+
- **Void awareness:** The sequence stops if a copy would land inside a void zone
|
|
500
|
+
- **Bounds check:** Copies that would fall outside the canvas are skipped, ending the sequence
|
|
501
|
+
|
|
502
|
+
Rhythm placement creates intentional visual patterns — like a trail of stepping stones or a musical crescendo rendered in geometry. The consistent shape and progressive scaling give the eye a clear path to follow.
|
|
503
|
+
|
|
504
|
+
### 5g. Layered Masking / Cutout Portals
|
|
484
505
|
|
|
485
506
|
~18% of images receive 1–3 **portal cutouts** — shape-sized windows that paint over the foreground layers with a background wash, creating a "peek through" depth effect.
|
|
486
507
|
|
|
@@ -587,6 +608,7 @@ Flow lines follow a **simplex noise** vector field defined by `flowAngle(x, y)`.
|
|
|
587
608
|
Each flow line:
|
|
588
609
|
- Starts at a random position
|
|
589
610
|
- Takes 30–70 steps along the flow field (±0.3 radians jitter per step)
|
|
611
|
+
- **Void zone awareness:** Segments that pass through void zones are skipped (the line continues on the other side, maintaining continuity without drawing through negative space)
|
|
590
612
|
- **Variable color:** Interpolates between two hierarchy colors along the stroke length
|
|
591
613
|
- **Pressure simulation:** Line width oscillates sinusoidally (frequency 2–6 cycles, amplitude ±40%) to simulate pen pressure
|
|
592
614
|
- **Taper:** Width and opacity decrease toward the end (80% taper over the stroke length)
|
|
@@ -600,14 +622,22 @@ After all shapes, flow lines, and symmetry mirroring:
|
|
|
600
622
|
|
|
601
623
|
Deterministic noise (separate RNG seeded from hash + salt 777) scatters single-pixel dots across the canvas. Density scales with canvas area (~1 dot per 800px²). Each dot is black or white at 1–4% opacity, adding subtle film grain.
|
|
602
624
|
|
|
625
|
+
The noise is applied via **ImageData buffer manipulation** — reading the canvas pixels into a typed array, alpha-blending each noise dot directly in memory, then writing the buffer back with `putImageData`. This is significantly faster than thousands of individual `fillRect` calls. A try/catch fallback uses the old per-pixel `fillRect` approach for environments where `getImageData` isn't available (e.g., some OffscreenCanvas implementations).
|
|
626
|
+
|
|
603
627
|
### Vignette
|
|
604
628
|
|
|
605
|
-
A radial gradient darkens the edges: transparent at center, ramping to 25–45%
|
|
629
|
+
A radial gradient darkens the edges: transparent at center, ramping to 25–45% opacity at the corners. The vignette color is **palette-tinted** based on background luminance:
|
|
630
|
+
- **Light backgrounds** (luminance > 0.5): warm sepia tone `rgba(80,60,30,...)` — avoids the harsh look of black vignette on light art
|
|
631
|
+
- **Dark backgrounds**: classic black `rgba(0,0,0,...)` — the traditional approach
|
|
632
|
+
|
|
633
|
+
This draws the eye inward toward the focal points while maintaining tonal coherence with the background.
|
|
606
634
|
|
|
607
635
|
### Organic Connecting Curves
|
|
608
636
|
|
|
609
637
|
Quadratic Bézier curves connect random pairs of placed shapes. The control point is offset perpendicular to the line between shapes by up to 40% of their distance, creating organic arcs. Count scales with canvas area (~8 per megapixel). Drawn at 6–16% opacity using hierarchy colors.
|
|
610
638
|
|
|
639
|
+
Connections are **proximity-aware** — only shapes within 20% of the canvas diagonal are connected. Distant pairs are skipped, preventing long straight-ish lines that cross the entire composition and break the organic feel.
|
|
640
|
+
|
|
611
641
|
### Color Grading
|
|
612
642
|
|
|
613
643
|
A `soft-light` overlay in a single hue (random, 40% saturation, 50% lightness) at low intensity (grade intensity × 25% opacity). This unifies the image's color temperature — like applying a photo filter.
|
|
@@ -647,15 +677,37 @@ Border elements use hierarchy colors at very low opacity (10–25%) so they fram
|
|
|
647
677
|
|
|
648
678
|
## 13. Signature Mark
|
|
649
679
|
|
|
650
|
-
The final rendering step places a small deterministic **chop mark** (inspired by East Asian seal stamps) in the
|
|
680
|
+
The final rendering step places a small deterministic **chop mark** (inspired by East Asian seal stamps) in the **least-dense corner** of the canvas:
|
|
651
681
|
|
|
652
682
|
- **RNG isolation:** Uses a separate RNG seeded with a salt of 42, so the signature is independent of all other rendering decisions
|
|
653
|
-
- **Position:**
|
|
683
|
+
- **Position:** The spatial hash grid evaluates all 4 corners (top-left, top-right, bottom-left, bottom-right) via `countNear()` within a 5× signature-size radius. The corner with the lowest shape density is selected. Falls back to bottom-right if all corners are equally empty.
|
|
654
684
|
- **Size:** 1.5–2.5% of the shorter canvas dimension
|
|
655
685
|
- **Structure:**
|
|
656
686
|
1. Outer circle ring (stroke-only) at 12–20% opacity
|
|
657
|
-
2.
|
|
687
|
+
2. 4–7 inner lines crossing the circle at unique angles derived from the hash, creating a distinctive geometric pattern
|
|
658
688
|
3. Center dot at slightly higher opacity
|
|
659
689
|
- **Color:** Uses the accent color from the hierarchy at very low opacity so it's visible but never distracting
|
|
660
690
|
|
|
661
691
|
The signature is unique per hash (different inner line patterns) but always recognizable as a chop mark, giving each generated image a subtle artist's stamp.
|
|
692
|
+
|
|
693
|
+
## 14. Performance
|
|
694
|
+
|
|
695
|
+
Several hot paths in the rendering pipeline are optimized for throughput:
|
|
696
|
+
|
|
697
|
+
### Spatial Hash Grid
|
|
698
|
+
|
|
699
|
+
A `SpatialGrid` class provides O(1) amortized density checks and nearest-neighbor lookups, replacing the original O(n²) linear scans over all placed shapes. The grid cell size matches the density check radius (~8% of the shorter canvas dimension). Three operations are used throughout the pipeline:
|
|
700
|
+
|
|
701
|
+
- `insert(item)` — adds a shape to the grid cell containing its position
|
|
702
|
+
- `countNear(x, y, radius)` — counts shapes within a radius by scanning only the relevant grid cells
|
|
703
|
+
- `findNearest(x, y, searchRadius)` — returns the closest shape within a search radius
|
|
704
|
+
|
|
705
|
+
The grid is used for: density-based shape skipping (step 5), tangent placement nearest-neighbor lookup (step 5a), and signature corner selection (step 12).
|
|
706
|
+
|
|
707
|
+
### Batched Background Patterns
|
|
708
|
+
|
|
709
|
+
The three background pattern types (dot grid, diagonal lines, hexagonal tessellation) batch all geometry into a single `beginPath()` / `fill()` or `stroke()` call instead of issuing per-element draw commands. For a 2048×2048 canvas with a dot grid at 30px spacing, this reduces ~4,600 individual `arc()`+`fill()` calls to a single batched path.
|
|
710
|
+
|
|
711
|
+
### ImageData Noise Overlay
|
|
712
|
+
|
|
713
|
+
The noise texture pass reads the canvas into an `ImageData` buffer, alpha-blends each noise dot directly in the typed array, then writes the buffer back with a single `putImageData()`. This avoids thousands of individual `fillRect()` calls and the associated canvas state changes (globalAlpha, fillStyle). A try/catch fallback preserves compatibility with environments that don't support `getImageData`.
|
package/CHANGELOG.md
CHANGED
|
@@ -4,12 +4,30 @@ 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.12.0](https://github.com/gfargo/git-hash-art/compare/0.11.0...0.12.0)
|
|
8
|
+
|
|
9
|
+
- perf: cross-env rendering optimizations round 2 [`#22`](https://github.com/gfargo/git-hash-art/pull/22)
|
|
10
|
+
- perf: optimize rendering pipeline — batch flow lines, cap clip-heavy styles, cache color parsing [`#21`](https://github.com/gfargo/git-hash-art/pull/21)
|
|
11
|
+
- docs: update ALGORITHM.md to reflect rendering pipeline changes [`2631e0c`](https://github.com/gfargo/git-hash-art/commit/2631e0c10b2b6bfb0a98c6a31d71d7ddaa8e7511)
|
|
12
|
+
|
|
13
|
+
#### [0.11.0](https://github.com/gfargo/git-hash-art/compare/0.10.1...0.11.0)
|
|
14
|
+
|
|
15
|
+
> 19 March 2026
|
|
16
|
+
|
|
17
|
+
- feat: rendering pipeline performance & artistic quality improvements [`#20`](https://github.com/gfargo/git-hash-art/pull/20)
|
|
18
|
+
- Allow manual version input for deployment [`94df05e`](https://github.com/gfargo/git-hash-art/commit/94df05e6d6dddc36f126c9cb0043718aad8f828f)
|
|
19
|
+
- chore: release v0.11.0 [`eadf11e`](https://github.com/gfargo/git-hash-art/commit/eadf11e9b402d35c85ec3e445c82d7d882f63d5c)
|
|
20
|
+
- update deploy workflow to correct repo [`7e89a0f`](https://github.com/gfargo/git-hash-art/commit/7e89a0f92866bc77f7aa1d7f6c5802350031d56f)
|
|
21
|
+
|
|
7
22
|
#### [0.10.1](https://github.com/gfargo/git-hash-art/compare/0.10.0...0.10.1)
|
|
8
23
|
|
|
24
|
+
> 19 March 2026
|
|
25
|
+
|
|
9
26
|
- feat: shadow/highlight system, generative borders, gradient map, edge erosion [`#19`](https://github.com/gfargo/git-hash-art/pull/19)
|
|
10
27
|
- feat: simplex noise flow fields, color harmony modes, golden spiral composition, layered masking [`#18`](https://github.com/gfargo/git-hash-art/pull/18)
|
|
11
28
|
- fix: portal cutouts use clip-and-fill instead of destination-out [`aecdd14`](https://github.com/gfargo/git-hash-art/commit/aecdd14c0d5ddf52d0394c714d2815679263b961)
|
|
12
29
|
- add GitHub Actions workflow for deployment [`4a6ac42`](https://github.com/gfargo/git-hash-art/commit/4a6ac426d1678f5ff83cbe4c4ddc9ce2a2a0c260)
|
|
30
|
+
- chore: release v0.10.1 [`043b86c`](https://github.com/gfargo/git-hash-art/commit/043b86c5d3e85bb3ddc6dabba9e69937ba7155df)
|
|
13
31
|
|
|
14
32
|
#### [0.10.0](https://github.com/gfargo/git-hash-art/compare/0.9.0...0.10.0)
|
|
15
33
|
|