git-hash-art 0.5.0 → 0.6.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 +86 -18
- package/CHANGELOG.md +9 -0
- package/bin/cli.js +155 -0
- package/dist/browser.js +428 -23
- package/dist/browser.js.map +1 -1
- package/dist/main.js +428 -23
- package/dist/main.js.map +1 -1
- package/dist/module.js +428 -23
- package/dist/module.js.map +1 -1
- package/package.json +4 -1
- package/src/lib/archetypes.ts +248 -0
- package/src/lib/canvas/colors.ts +71 -0
- package/src/lib/render.ts +114 -30
package/ALGORITHM.md
CHANGED
|
@@ -9,20 +9,23 @@ Hash String
|
|
|
9
9
|
│
|
|
10
10
|
├─► Seed (mulberry32 PRNG)
|
|
11
11
|
│
|
|
12
|
-
├─►
|
|
12
|
+
├─► Archetype Selection (1 of 10 visual personalities)
|
|
13
13
|
│
|
|
14
|
-
|
|
14
|
+
├─► Color Scheme (palette mode from archetype + temperature mode)
|
|
15
|
+
│
|
|
16
|
+
└─► Rendering Pipeline (parameters overridden by archetype)
|
|
15
17
|
│
|
|
16
|
-
|
|
18
|
+
0. Archetype Override (gridSize, layers, opacity, sizes, styles)
|
|
19
|
+
1. Background Layer (7 styles: radial, linear, solid, multi-stop)
|
|
17
20
|
1b. Layered Background (faint shapes + concentric rings)
|
|
18
21
|
2. Composition Mode Selection
|
|
19
22
|
2b. Symmetry Mode Selection (none / bilateral / quad)
|
|
20
23
|
3. Focal Points (rule-of-thirds biased) + Void Zones
|
|
21
24
|
4. Flow Field Initialization
|
|
22
|
-
4b. Hero Shape (large focal anchor,
|
|
23
|
-
5. Shape Layers (× N layers)
|
|
25
|
+
4b. Hero Shape (large focal anchor, archetype-controlled)
|
|
26
|
+
5. Shape Layers (× N layers, archetype-tuned)
|
|
24
27
|
│ ├─ Blend Mode (per-layer compositing)
|
|
25
|
-
│ ├─ Render Style (
|
|
28
|
+
│ ├─ Render Style (archetype-preferred + random mix)
|
|
26
29
|
│ ├─ Position (composition mode + focal bias + density check)
|
|
27
30
|
│ ├─ Shape Selection (layer-weighted)
|
|
28
31
|
│ ├─ Atmospheric Depth (desaturation on later layers)
|
|
@@ -30,7 +33,7 @@ Hash String
|
|
|
30
33
|
│ ├─ Styling (transparency, glow, gradients, color jitter)
|
|
31
34
|
│ ├─ Organic Edges (~15% watercolor bleed)
|
|
32
35
|
│ └─ Recursive Nesting (~15% of large shapes)
|
|
33
|
-
6. Flow-Line Pass (tapered brush strokes)
|
|
36
|
+
6. Flow-Line Pass (tapered brush strokes, archetype-scaled)
|
|
34
37
|
6b. Symmetry Mirroring (bilateral-x, bilateral-y, or quad)
|
|
35
38
|
7. Noise Texture Overlay
|
|
36
39
|
8. Vignette (radial edge darkening)
|
|
@@ -48,7 +51,44 @@ rng() → float in [0, 1)
|
|
|
48
51
|
|
|
49
52
|
The old approach extracted 2-char hex pairs from the hash (only ~20 unique values in a 40-char hash). Mulberry32 produces a full 32-bit uniform stream from any seed, eliminating correlation artifacts.
|
|
50
53
|
|
|
51
|
-
## 2.
|
|
54
|
+
## 2. Archetype System
|
|
55
|
+
|
|
56
|
+
Before any rendering begins, the hash deterministically selects one of 10 **visual archetypes** — fundamentally different rendering personalities that override key parameters. This is the primary mechanism for visual diversity: two hashes that select different archetypes will look like they came from entirely different generators.
|
|
57
|
+
|
|
58
|
+
Each archetype controls:
|
|
59
|
+
|
|
60
|
+
| Parameter | Effect |
|
|
61
|
+
|-----------|--------|
|
|
62
|
+
| `gridSize` | Shape density (2 = sparse, 9 = packed) |
|
|
63
|
+
| `layers` | Rendering depth (2 = flat, 5 = deep) |
|
|
64
|
+
| `baseOpacity` / `opacityReduction` | Transparency character |
|
|
65
|
+
| `minShapeSize` / `maxShapeSize` | Scale range |
|
|
66
|
+
| `backgroundStyle` | One of 7 background rendering modes |
|
|
67
|
+
| `paletteMode` | One of 7 color palette strategies |
|
|
68
|
+
| `preferredStyles` | Weighted render style selection |
|
|
69
|
+
| `flowLineMultiplier` | Flow line density (0 = none, 4 = heavy) |
|
|
70
|
+
| `heroShape` | Whether to draw a dominant focal shape |
|
|
71
|
+
| `glowMultiplier` | Glow probability scaling (0 = none, 3 = heavy) |
|
|
72
|
+
| `sizePower` | Size distribution curve (0.5 = uniform, 2.5 = many tiny) |
|
|
73
|
+
|
|
74
|
+
### The 10 Archetypes
|
|
75
|
+
|
|
76
|
+
| Archetype | Character | Background | Palette | Key Traits |
|
|
77
|
+
|-----------|-----------|------------|---------|------------|
|
|
78
|
+
| **dense-chaotic** | Packed, energetic | radial-dark | harmonious | 9×9 grid, 5 layers, heavy flow lines, low glow |
|
|
79
|
+
| **minimal-spacious** | Clean, deliberate | solid-light | duotone | 2×2 grid, 2 layers, large shapes, no glow |
|
|
80
|
+
| **organic-flow** | Natural, flowing | radial-dark | earth | Heavy flow lines (4×), watercolor style, no hero |
|
|
81
|
+
| **geometric-precision** | Technical, structured | solid-dark | high-contrast | Stroke-only/dashed/hatched styles, no flow lines |
|
|
82
|
+
| **ethereal** | Dreamy, luminous | radial-light | pastel-light | High glow (2×), watercolor, hero shape |
|
|
83
|
+
| **bold-graphic** | Poster-like, impactful | linear-diagonal | duotone | 2 layers, very large shapes, no flow lines |
|
|
84
|
+
| **neon-glow** | Electric, vibrant | solid-dark | neon | Heavy glow (3×), stroke-heavy styles, hero shape |
|
|
85
|
+
| **monochrome-ink** | Pen-and-ink, textural | solid-light | monochrome | Hatched/incomplete styles, no glow |
|
|
86
|
+
| **cosmic** | Deep space, vast | radial-dark | neon | 8×8 grid, 5 layers, heavy glow, many tiny shapes |
|
|
87
|
+
| **classic** | Balanced, familiar | radial-dark | harmonious | Preserves the original rendering look |
|
|
88
|
+
|
|
89
|
+
Archetype values serve as defaults — explicit user config always wins. The `classic` archetype preserves backward compatibility with the original rendering style.
|
|
90
|
+
|
|
91
|
+
## 3. Color Scheme
|
|
52
92
|
|
|
53
93
|
The `SacredColorScheme` class derives three harmonious palettes from the hash:
|
|
54
94
|
|
|
@@ -60,6 +100,22 @@ The `SacredColorScheme` class derives three harmonious palettes from the hash:
|
|
|
60
100
|
|
|
61
101
|
These are merged and deduplicated into a single 6-8 color palette. Background colors are darkened variants (65% and 55% brightness) of the base scheme, with optional temperature shifting.
|
|
62
102
|
|
|
103
|
+
### Palette Modes
|
|
104
|
+
|
|
105
|
+
The archetype's `paletteMode` reshapes the color palette to match the visual personality:
|
|
106
|
+
|
|
107
|
+
| Mode | Colors | Character |
|
|
108
|
+
|------|--------|-----------|
|
|
109
|
+
| **harmonious** | Full base + complementary + triadic | Rich, balanced (default) |
|
|
110
|
+
| **monochrome** | Single hue, 5 lightness steps | Elegant, focused |
|
|
111
|
+
| **duotone** | Two contrasting hues + tints | Bold, graphic |
|
|
112
|
+
| **neon** | 4 hues at full saturation | Electric, vivid |
|
|
113
|
+
| **pastel-light** | 4 hues at low saturation, high lightness | Soft, dreamy |
|
|
114
|
+
| **earth** | Warm muted naturals (browns, olives, sage) | Organic, grounded |
|
|
115
|
+
| **high-contrast** | Black + white + one accent | Technical, stark |
|
|
116
|
+
|
|
117
|
+
Each mode also provides matching background colors (e.g., neon gets near-black backgrounds, pastel-light gets warm off-whites).
|
|
118
|
+
|
|
63
119
|
### Temperature Contrast
|
|
64
120
|
|
|
65
121
|
The hash deterministically selects a **temperature mode** that creates warm/cool tension across the image:
|
|
@@ -95,9 +151,21 @@ Scheme types also vary: `analogic`, `mono`, `contrast`, `triade`, `tetrade`. The
|
|
|
95
151
|
- **`shiftTemperature(hex, target, amount)`** — shifts hue toward warm (orange) or cool (blue)
|
|
96
152
|
- **Positional blending** — shape fill color is biased by canvas position, creating smooth color flow across the image
|
|
97
153
|
|
|
98
|
-
##
|
|
154
|
+
## 4. Background
|
|
155
|
+
|
|
156
|
+
The archetype's `backgroundStyle` selects one of 7 rendering modes:
|
|
157
|
+
|
|
158
|
+
| Style | Description |
|
|
159
|
+
|-------|-------------|
|
|
160
|
+
| **radial-dark** | Radial gradient from dark center to darker edges (original default) |
|
|
161
|
+
| **radial-light** | Light off-white center fading to the base palette |
|
|
162
|
+
| **linear-horizontal** | Left-to-right gradient between two palette colors |
|
|
163
|
+
| **linear-diagonal** | Corner-to-corner gradient with color reversal |
|
|
164
|
+
| **solid-dark** | Flat dark color fill |
|
|
165
|
+
| **solid-light** | Flat warm off-white fill |
|
|
166
|
+
| **multi-stop** | 3-4 color gradient with a darkened mid-palette accent |
|
|
99
167
|
|
|
100
|
-
|
|
168
|
+
This single change has an outsized impact on visual diversity — a solid-light background with monochrome shapes looks nothing like a radial-dark background with neon glow.
|
|
101
169
|
|
|
102
170
|
### Layered Background
|
|
103
171
|
|
|
@@ -108,7 +176,7 @@ After the gradient, a second pass adds visual texture to the background:
|
|
|
108
176
|
|
|
109
177
|
This prevents the background from feeling flat and gives the image depth before the main shape layers begin.
|
|
110
178
|
|
|
111
|
-
##
|
|
179
|
+
## 5. Composition Modes
|
|
112
180
|
|
|
113
181
|
The hash deterministically selects one of five composition strategies that control how shapes are positioned on the canvas:
|
|
114
182
|
|
|
@@ -135,7 +203,7 @@ Each mode produces fundamentally different visual character from the same shape
|
|
|
135
203
|
|
|
136
204
|
Symmetry is applied after shape layers and flow lines but before post-processing (noise, vignette, connecting curves). This means the mirrored content gets the same noise texture and vignette as the original, maintaining visual consistency. Symmetrical generative art is disproportionately appealing to humans due to our innate preference for bilateral symmetry.
|
|
137
205
|
|
|
138
|
-
##
|
|
206
|
+
## 6. Focal Points & Negative Space
|
|
139
207
|
|
|
140
208
|
1-2 focal points are placed on the canvas. **70% of the time**, focal points snap to **rule-of-thirds intersection points** (with slight jitter to avoid a mechanical look), creating compositions that feel intentionally designed. The remaining 30% use free placement within the central 60% of the canvas. Every shape position is pulled toward the nearest focal point by a strength factor (30-70%).
|
|
141
209
|
|
|
@@ -156,7 +224,7 @@ Symmetry is applied after shape layers and flow lines but before post-processing
|
|
|
156
224
|
|
|
157
225
|
Before placing each shape, the renderer checks how many shapes already exist nearby. If local density exceeds ~15% of the per-layer shape count, there's a 60% chance the shape is skipped. This prevents areas from becoming an opaque blob and creates natural visual rhythm.
|
|
158
226
|
|
|
159
|
-
##
|
|
227
|
+
## 7. Shape Layers
|
|
160
228
|
|
|
161
229
|
The image is built in N layers (default: 4). Each layer has its own characteristics:
|
|
162
230
|
|
|
@@ -169,7 +237,7 @@ The image is built in N layers (default: 4). Each layer has its own characterist
|
|
|
169
237
|
| Shape weights | Early layers favor basic shapes; later layers favor complex/sacred |
|
|
170
238
|
| Per-shape opacity | Additional random jitter (50-100% of layer opacity) |
|
|
171
239
|
| Blend mode | Each layer gets a hash-derived `globalCompositeOperation` (see below) |
|
|
172
|
-
| Render style | Each layer has a dominant render style; 30% of shapes pick their own |
|
|
240
|
+
| Render style | Each layer has a dominant render style (60% from archetype preferences, 40% random); 30% of shapes pick their own |
|
|
173
241
|
| Atmospheric depth | Later layers desaturate colors by up to 30%, simulating distance |
|
|
174
242
|
|
|
175
243
|
### Blend Modes (Per-Layer Compositing)
|
|
@@ -230,7 +298,7 @@ Each shape receives:
|
|
|
230
298
|
- Sized at 15-40% of the parent
|
|
231
299
|
- More transparent than the parent layer
|
|
232
300
|
|
|
233
|
-
##
|
|
301
|
+
## 8. Flow-Line Pass (Tapered Brush Strokes)
|
|
234
302
|
|
|
235
303
|
6-16 flowing curves are drawn across the canvas, following the hash-derived vector field:
|
|
236
304
|
|
|
@@ -246,7 +314,7 @@ The flow field is defined by:
|
|
|
246
314
|
angle(x, y) = baseAngle + sin(x/w × freq × 2π) × π/2 + cos(y/h × freq × 2π) × π/2
|
|
247
315
|
```
|
|
248
316
|
|
|
249
|
-
##
|
|
317
|
+
## 9. Noise Texture Overlay
|
|
250
318
|
|
|
251
319
|
A dedicated noise RNG (seeded separately from the main RNG to avoid affecting shape generation) renders thousands of 1px dots across the canvas:
|
|
252
320
|
|
|
@@ -255,7 +323,7 @@ A dedicated noise RNG (seeded separately from the main RNG to avoid affecting sh
|
|
|
255
323
|
- Very low opacity (1-4%)
|
|
256
324
|
- Creates subtle film-grain texture that adds organic depth
|
|
257
325
|
|
|
258
|
-
##
|
|
326
|
+
## 9b. Vignette
|
|
259
327
|
|
|
260
328
|
A radial gradient overlay darkens the edges of the canvas, drawing the viewer's eye toward the center:
|
|
261
329
|
|
|
@@ -264,7 +332,7 @@ A radial gradient overlay darkens the edges of the canvas, drawing the viewer's
|
|
|
264
332
|
- Applied after noise but before connecting curves, so the curves remain visible at edges
|
|
265
333
|
- Creates a natural "spotlight" effect that makes compositions feel more focused and photographic
|
|
266
334
|
|
|
267
|
-
##
|
|
335
|
+
## 10. Organic Connecting Curves
|
|
268
336
|
|
|
269
337
|
Quadratic bezier curves connect nearby shapes:
|
|
270
338
|
|
package/CHANGELOG.md
CHANGED
|
@@ -4,8 +4,17 @@ 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.6.0](https://github.com/gfargo/git-hash-art/compare/0.5.0...0.6.0)
|
|
8
|
+
|
|
9
|
+
- feat: archetype system, palette modes, background variety, and CLI [`#12`](https://github.com/gfargo/git-hash-art/pull/12)
|
|
10
|
+
- feat: archetype system for dramatically different visual personalities [`2a1b919`](https://github.com/gfargo/git-hash-art/commit/2a1b919c51d3bfbd9d5c7a381ea5e104f81df2f6)
|
|
11
|
+
- feat: add CLI for generating art from terminal [`184372a`](https://github.com/gfargo/git-hash-art/commit/184372a584f68031bf44379f385f2e78691f98aa)
|
|
12
|
+
- docs: update ALGORITHM.md with archetype system, palette modes, and background styles [`4eccd07`](https://github.com/gfargo/git-hash-art/commit/4eccd077be9469c27caf60a0d8c463124ad7f9fa)
|
|
13
|
+
|
|
7
14
|
#### [0.5.0](https://github.com/gfargo/git-hash-art/compare/0.4.1...0.5.0)
|
|
8
15
|
|
|
16
|
+
> 19 March 2026
|
|
17
|
+
|
|
9
18
|
- feat: visual improvements — composition, color, and rendering upgrades [`#11`](https://github.com/gfargo/git-hash-art/pull/11)
|
|
10
19
|
- feat: warm/cool temperature contrast in color system [`550bc6a`](https://github.com/gfargo/git-hash-art/commit/550bc6a87929d7ebafa973079845e688a00de929)
|
|
11
20
|
- docs: update ALGORITHM.md with all new visual features [`a05de15`](https://github.com/gfargo/git-hash-art/commit/a05de1586684b91266f5a26ea7279fc601dd2202)
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { execSync } = require("child_process");
|
|
4
|
+
const { generateImageFromHash, saveImageToFile } = require("../dist/main.js");
|
|
5
|
+
const { PRESETS } = require("../dist/main.js");
|
|
6
|
+
|
|
7
|
+
const HELP = `
|
|
8
|
+
git-hash-art — Generate deterministic abstract art from git hashes.
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
git-hash-art current [options] Generate art from HEAD commit
|
|
12
|
+
git-hash-art generate <hash> [options] Generate art from a specific hash
|
|
13
|
+
|
|
14
|
+
Options:
|
|
15
|
+
--width <n> Canvas width in pixels (default: 2048)
|
|
16
|
+
--height <n> Canvas height in pixels (default: 2048)
|
|
17
|
+
--output <dir> Output directory (default: ./output)
|
|
18
|
+
--preset <name> Use a built-in preset (overrides width/height)
|
|
19
|
+
--layers <n> Number of layers (default: 4)
|
|
20
|
+
--grid <n> Grid density (default: 5)
|
|
21
|
+
--list-presets List available presets
|
|
22
|
+
|
|
23
|
+
Examples:
|
|
24
|
+
npx git-hash-art current
|
|
25
|
+
npx git-hash-art current --preset instagram-square
|
|
26
|
+
npx git-hash-art generate abc123ff --width 1920 --height 1080
|
|
27
|
+
`;
|
|
28
|
+
|
|
29
|
+
function parseArgs(argv) {
|
|
30
|
+
const args = argv.slice(2);
|
|
31
|
+
const command = args[0];
|
|
32
|
+
const parsed = { command, hash: null, options: {} };
|
|
33
|
+
|
|
34
|
+
let i = 1;
|
|
35
|
+
if (command === "generate") {
|
|
36
|
+
parsed.hash = args[1];
|
|
37
|
+
i = 2;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
while (i < args.length) {
|
|
41
|
+
const arg = args[i];
|
|
42
|
+
if (arg === "--width" && args[i + 1]) {
|
|
43
|
+
parsed.options.width = parseInt(args[i + 1], 10);
|
|
44
|
+
i += 2;
|
|
45
|
+
} else if (arg === "--height" && args[i + 1]) {
|
|
46
|
+
parsed.options.height = parseInt(args[i + 1], 10);
|
|
47
|
+
i += 2;
|
|
48
|
+
} else if (arg === "--output" && args[i + 1]) {
|
|
49
|
+
parsed.options.output = args[i + 1];
|
|
50
|
+
i += 2;
|
|
51
|
+
} else if (arg === "--preset" && args[i + 1]) {
|
|
52
|
+
parsed.options.preset = args[i + 1];
|
|
53
|
+
i += 2;
|
|
54
|
+
} else if (arg === "--layers" && args[i + 1]) {
|
|
55
|
+
parsed.options.layers = parseInt(args[i + 1], 10);
|
|
56
|
+
i += 2;
|
|
57
|
+
} else if (arg === "--grid" && args[i + 1]) {
|
|
58
|
+
parsed.options.gridSize = parseInt(args[i + 1], 10);
|
|
59
|
+
i += 2;
|
|
60
|
+
} else if (arg === "--list-presets") {
|
|
61
|
+
parsed.command = "list-presets";
|
|
62
|
+
i += 1;
|
|
63
|
+
} else if (arg === "--help" || arg === "-h") {
|
|
64
|
+
parsed.command = "help";
|
|
65
|
+
i += 1;
|
|
66
|
+
} else {
|
|
67
|
+
i += 1;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return parsed;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function getHeadHash() {
|
|
75
|
+
try {
|
|
76
|
+
return execSync("git rev-parse HEAD", { encoding: "utf-8" }).trim();
|
|
77
|
+
} catch {
|
|
78
|
+
console.error("Error: Not a git repository or git is not installed.");
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function listPresets() {
|
|
84
|
+
console.log("\nAvailable presets:\n");
|
|
85
|
+
for (const [name, config] of Object.entries(PRESETS)) {
|
|
86
|
+
console.log(` ${name.padEnd(20)} ${config.width}x${config.height}`);
|
|
87
|
+
}
|
|
88
|
+
console.log("");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function run() {
|
|
92
|
+
const { command, hash, options } = parseArgs(process.argv);
|
|
93
|
+
|
|
94
|
+
if (!command || command === "help") {
|
|
95
|
+
console.log(HELP);
|
|
96
|
+
process.exit(0);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (command === "list-presets") {
|
|
100
|
+
listPresets();
|
|
101
|
+
process.exit(0);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (command !== "current" && command !== "generate") {
|
|
105
|
+
console.error(`Unknown command: ${command}\n`);
|
|
106
|
+
console.log(HELP);
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
let gitHash;
|
|
111
|
+
if (command === "current") {
|
|
112
|
+
gitHash = getHeadHash();
|
|
113
|
+
console.log(`Using HEAD: ${gitHash}`);
|
|
114
|
+
} else {
|
|
115
|
+
if (!hash) {
|
|
116
|
+
console.error("Error: Please provide a hash.\n");
|
|
117
|
+
console.log("Usage: git-hash-art generate <hash> [options]");
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
gitHash = hash;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Build config from preset + overrides
|
|
124
|
+
let config = {};
|
|
125
|
+
if (options.preset) {
|
|
126
|
+
const preset = PRESETS[options.preset];
|
|
127
|
+
if (!preset) {
|
|
128
|
+
console.error(`Unknown preset: ${options.preset}`);
|
|
129
|
+
console.log("Use --list-presets to see available presets.");
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
config = { ...preset };
|
|
133
|
+
delete config.hash;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (options.width) config.width = options.width;
|
|
137
|
+
if (options.height) config.height = options.height;
|
|
138
|
+
if (options.layers) config.layers = options.layers;
|
|
139
|
+
if (options.gridSize) config.gridSize = options.gridSize;
|
|
140
|
+
|
|
141
|
+
const outputDir = options.output || "./output";
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
const buffer = generateImageFromHash(gitHash, config);
|
|
145
|
+
const w = config.width || 2048;
|
|
146
|
+
const h = config.height || 2048;
|
|
147
|
+
const outputPath = saveImageToFile(buffer, outputDir, gitHash, "", w, h);
|
|
148
|
+
console.log(`Done! Image saved to ${outputPath}`);
|
|
149
|
+
} catch (error) {
|
|
150
|
+
console.error("Generation failed:", error.message);
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
run();
|