git-hash-art 0.1.0 → 0.3.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/.kiro/steering/product.md +16 -0
- package/.kiro/steering/structure.md +40 -0
- package/.kiro/steering/tech.md +24 -0
- package/ALGORITHM.md +198 -0
- package/CHANGELOG.md +19 -0
- package/README.md +165 -57
- package/dist/browser.js +1430 -0
- package/dist/browser.js.map +1 -0
- package/dist/main.js +672 -333
- package/dist/main.js.map +1 -1
- package/dist/module.js +665 -329
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts +2 -9
- package/dist/types.d.ts.map +1 -1
- package/package.json +47 -3
- package/src/__tests__/compatibility.test.ts +42 -0
- package/src/__tests__/generation.test.ts +58 -0
- package/src/__tests__/render.test.ts +81 -0
- package/src/__tests__/shapes.test.ts +71 -0
- package/src/browser.ts +100 -0
- package/src/index.ts +38 -199
- package/src/lib/canvas/colors.ts +90 -66
- package/src/lib/canvas/draw.ts +38 -7
- package/src/lib/canvas/shapes/basic.ts +1 -1
- package/src/lib/canvas/shapes/complex.ts +2 -1
- package/src/lib/render.ts +483 -0
- package/src/lib/utils.ts +33 -6
- package/src/types.ts +35 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Product: git-hash-art
|
|
2
|
+
|
|
3
|
+
A cross-platform library that generates deterministic abstract art from git commit hashes. Given a hex hash string, it produces a unique image using layered geometric shapes, sacred geometry patterns, and harmonious color schemes. Works in both Node.js and browser environments.
|
|
4
|
+
|
|
5
|
+
Key capabilities:
|
|
6
|
+
- Deterministic output: same hash always produces the same image
|
|
7
|
+
- Configurable canvas size, grid density, layers, shape sizes, and opacity
|
|
8
|
+
- Built-in presets for social media (Instagram, Twitter, LinkedIn), device wallpapers, and print sizes
|
|
9
|
+
- CLI for generating art from the current commit or a specific hash
|
|
10
|
+
- Cross-platform: Node.js (via `@napi-rs/canvas`) and browsers (native Canvas 2D API)
|
|
11
|
+
|
|
12
|
+
## Public API
|
|
13
|
+
|
|
14
|
+
- Node entry (`git-hash-art`): `generateImageFromHash` (returns PNG Buffer), `saveImageToFile`, `renderHashArt`
|
|
15
|
+
- Browser entry (`git-hash-art/browser`): `renderToCanvas`, `generateImageBlob`, `generateDataURL`, `renderHashArt`
|
|
16
|
+
- Both re-export `PRESETS`, `DEFAULT_CONFIG`, and the `GenerationConfig` type
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Project Structure
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
src/
|
|
5
|
+
index.ts # Node.js entry: generateImageFromHash, saveImageToFile, re-exports renderHashArt
|
|
6
|
+
browser.ts # Browser entry: renderToCanvas, generateImageBlob, generateDataURL, re-exports renderHashArt
|
|
7
|
+
types.ts # Shared GenerationConfig interface and DEFAULT_CONFIG
|
|
8
|
+
__tests__/ # Vitest test files (*.test.ts)
|
|
9
|
+
lib/
|
|
10
|
+
render.ts # Pure rendering logic (environment-agnostic) — renderHashArt()
|
|
11
|
+
utils.ts # Hash-to-seed conversion, deterministic RNG, PatternCombiner
|
|
12
|
+
constants.ts # PRESETS, default shape config, proportions, pattern presets
|
|
13
|
+
canvas/
|
|
14
|
+
colors.ts # Color scheme generation (generateColorScheme, SacredColorScheme class)
|
|
15
|
+
draw.ts # Shape drawing and enhancement (drawShape, enhanceShapeGeneration)
|
|
16
|
+
shapes/
|
|
17
|
+
index.ts # Aggregates and re-exports all shape draw functions
|
|
18
|
+
basic.ts # Circle, square, triangle, hexagon, star
|
|
19
|
+
complex.ts # Platonic solids, fibonacci, golden ratio shapes
|
|
20
|
+
sacred.ts # Flower of life, tree of life, Metatron's cube, Sri Yantra
|
|
21
|
+
utils.ts # Geometry helpers (transforms, degree conversion)
|
|
22
|
+
bin/
|
|
23
|
+
generateExamples.js # Script to generate example images from PRESETS
|
|
24
|
+
examples/ # Generated example PNGs (gitignored)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Architecture
|
|
28
|
+
|
|
29
|
+
- `src/lib/render.ts` contains the pure rendering core (`renderHashArt`) that only uses the standard `CanvasRenderingContext2D` API — no Node or browser dependencies
|
|
30
|
+
- `src/index.ts` is the Node entry point — wraps `renderHashArt` with `@napi-rs/canvas` for PNG buffer output and `fs` for file saving
|
|
31
|
+
- `src/browser.ts` is the browser entry point — wraps `renderHashArt` with `HTMLCanvasElement`/`OffscreenCanvas` helpers
|
|
32
|
+
- `@napi-rs/canvas` is an optional peer dependency, only required for Node.js usage
|
|
33
|
+
|
|
34
|
+
## Conventions
|
|
35
|
+
|
|
36
|
+
- Shape draw functions follow the `DrawFunction` signature: `(ctx: CanvasRenderingContext2D, size: number, config?: any) => void`
|
|
37
|
+
- Shapes are grouped by category (basic, complex, sacred) and merged via the barrel `shapes/index.ts`
|
|
38
|
+
- All randomness is derived deterministically from the git hash via `getRandomFromHash` — never use `Math.random()`
|
|
39
|
+
- Tests live in `src/__tests__/` and use Vitest (`describe`/`it`/`expect`)
|
|
40
|
+
- The `examples/` directory is gitignored; regenerate with `yarn build:examples`
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Tech Stack
|
|
2
|
+
|
|
3
|
+
- Language: TypeScript (strict mode, ES2020 target)
|
|
4
|
+
- Runtime: Node.js and browsers
|
|
5
|
+
- Canvas (Node): `@napi-rs/canvas` (optional peer dependency)
|
|
6
|
+
- Canvas (Browser): native Canvas 2D API / OffscreenCanvas
|
|
7
|
+
- Color generation: `color-scheme` (declared in `global.d.ts` since it lacks types)
|
|
8
|
+
- Bundler: Parcel (outputs CJS `dist/main.js`, ESM `dist/module.js`, browser `dist/browser.js`, types `dist/types.d.ts`)
|
|
9
|
+
- Test framework: Vitest
|
|
10
|
+
- Formatter: Prettier
|
|
11
|
+
- Release: release-it
|
|
12
|
+
- Package manager: Yarn
|
|
13
|
+
|
|
14
|
+
## Common Commands
|
|
15
|
+
|
|
16
|
+
| Command | Purpose |
|
|
17
|
+
|---|---|
|
|
18
|
+
| `yarn build` | Production build (clears `.parcel-cache` first via `prebuild`) |
|
|
19
|
+
| `yarn watch` | Dev build with file watching |
|
|
20
|
+
| `npx vitest --run` | Run tests once |
|
|
21
|
+
| `yarn format` | Format source files with Prettier |
|
|
22
|
+
| `yarn format:check` | Check formatting without writing |
|
|
23
|
+
| `yarn build:examples` | Generate example images via `bin/generateExamples.js` |
|
|
24
|
+
| `yarn test:publish` | Dry-run npm publish |
|
package/ALGORITHM.md
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Art Generation Algorithm
|
|
2
|
+
|
|
3
|
+
This document describes the deterministic art generation pipeline used by `git-hash-art`. Every step derives its randomness from the input hash via a seeded mulberry32 PRNG, guaranteeing identical output for identical input.
|
|
4
|
+
|
|
5
|
+
## Pipeline Overview
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
Hash String
|
|
9
|
+
│
|
|
10
|
+
├─► Seed (mulberry32 PRNG)
|
|
11
|
+
│
|
|
12
|
+
├─► Color Scheme (analogic + complementary + triadic palettes)
|
|
13
|
+
│
|
|
14
|
+
└─► Rendering Pipeline
|
|
15
|
+
│
|
|
16
|
+
1. Background Layer
|
|
17
|
+
2. Composition Mode Selection
|
|
18
|
+
3. Focal Point Generation
|
|
19
|
+
4. Flow Field Initialization
|
|
20
|
+
5. Shape Layers (× N layers)
|
|
21
|
+
│ ├─ Position (composition mode + focal bias)
|
|
22
|
+
│ ├─ Shape Selection (layer-weighted)
|
|
23
|
+
│ ├─ Styling (transparency, glow, gradients, color jitter)
|
|
24
|
+
│ └─ Recursive Nesting (~15% of large shapes)
|
|
25
|
+
6. Flow-Line Pass
|
|
26
|
+
7. Noise Texture Overlay
|
|
27
|
+
8. Organic Connecting Curves
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 1. Deterministic RNG
|
|
31
|
+
|
|
32
|
+
All randomness flows from a single **mulberry32** PRNG seeded by hashing the full input string:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
seed = hash(gitHash) → mulberry32 state
|
|
36
|
+
rng() → float in [0, 1)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
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.
|
|
40
|
+
|
|
41
|
+
## 2. Color Scheme
|
|
42
|
+
|
|
43
|
+
The `SacredColorScheme` class derives three harmonious palettes from the hash:
|
|
44
|
+
|
|
45
|
+
| Palette | Method | Purpose |
|
|
46
|
+
|---------|--------|---------|
|
|
47
|
+
| Base (analogic) | `color-scheme` lib, hue = seed % 360 | Primary shape colors |
|
|
48
|
+
| Complementary (mono) | hue = seed + 180° | Contrast accents |
|
|
49
|
+
| Triadic | hue = seed + 120° | Additional variety |
|
|
50
|
+
|
|
51
|
+
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.
|
|
52
|
+
|
|
53
|
+
### Color Utilities
|
|
54
|
+
|
|
55
|
+
- **`hexWithAlpha(hex, alpha)`** — converts hex to `rgba()` for transparency
|
|
56
|
+
- **`jitterColor(hex, rng, amount)`** — applies ±amount RGB jitter per channel for organic variation
|
|
57
|
+
- **Positional blending** — shape fill color is biased by canvas position, creating smooth color flow across the image
|
|
58
|
+
|
|
59
|
+
## 3. Background
|
|
60
|
+
|
|
61
|
+
A radial gradient fills the canvas from center to corners using two darkened base-scheme colors. This creates depth before any shapes are drawn.
|
|
62
|
+
|
|
63
|
+
## 4. Composition Modes
|
|
64
|
+
|
|
65
|
+
The hash deterministically selects one of five composition strategies that control how shapes are positioned on the canvas:
|
|
66
|
+
|
|
67
|
+
| Mode | Description |
|
|
68
|
+
|------|-------------|
|
|
69
|
+
| **Radial** | Shapes emanate from the center with distance following a power curve (denser near center) |
|
|
70
|
+
| **Flow-field** | Random positions; shapes are rotated to align with a hash-derived vector field |
|
|
71
|
+
| **Spiral** | Shapes follow a multi-turn spiral path outward from center with slight scatter |
|
|
72
|
+
| **Grid-subdivision** | Canvas is divided into cells; shapes are placed randomly within cells |
|
|
73
|
+
| **Clustered** | 3-5 cluster centers are generated; shapes scatter around the nearest cluster |
|
|
74
|
+
|
|
75
|
+
Each mode produces fundamentally different visual character from the same shape set.
|
|
76
|
+
|
|
77
|
+
## 5. Focal Points
|
|
78
|
+
|
|
79
|
+
1-2 focal points are placed on the canvas (kept away from edges). Every shape position is pulled toward the nearest focal point by a strength factor (30-70%), creating areas of visual density and intentional-looking composition rather than uniform scatter.
|
|
80
|
+
|
|
81
|
+
## 6. Shape Layers
|
|
82
|
+
|
|
83
|
+
The image is built in N layers (default: 4). Each layer has its own characteristics:
|
|
84
|
+
|
|
85
|
+
### Layer Properties
|
|
86
|
+
|
|
87
|
+
| Property | Behavior |
|
|
88
|
+
|----------|----------|
|
|
89
|
+
| Opacity | Decays gently per layer (0.7 → 0.58 → 0.46 → 0.34), minimum 0.15 |
|
|
90
|
+
| Size scale | Later layers use progressively smaller shapes (×0.85, ×0.70, ×0.55) |
|
|
91
|
+
| Shape weights | Early layers favor basic shapes; later layers favor complex/sacred |
|
|
92
|
+
| Per-shape opacity | Additional random jitter (50-100% of layer opacity) |
|
|
93
|
+
|
|
94
|
+
### Shape Selection (Layer-Weighted)
|
|
95
|
+
|
|
96
|
+
Shapes are divided into three categories with weights that shift across layers:
|
|
97
|
+
|
|
98
|
+
| Category | Shapes | Early layers | Late layers |
|
|
99
|
+
|----------|--------|-------------|-------------|
|
|
100
|
+
| **Basic** | circle, square, triangle, hexagon, diamond, cube | High weight | Low weight |
|
|
101
|
+
| **Complex** | star, platonic solid, fibonacci spiral, islamic pattern, celtic knot, merkaba, fractal | Medium | Medium-high |
|
|
102
|
+
| **Sacred** | mandala, flower of life, tree of life, Metatron's cube, Sri Yantra, seed of life, vesica piscis, torus, egg of life | Low | High |
|
|
103
|
+
|
|
104
|
+
### Size Distribution
|
|
105
|
+
|
|
106
|
+
Shape sizes follow a **power distribution** (`Math.pow(rng(), 1.8)`) — producing many small shapes and few large ones, which creates natural visual hierarchy.
|
|
107
|
+
|
|
108
|
+
### Styling Per Shape
|
|
109
|
+
|
|
110
|
+
Each shape receives:
|
|
111
|
+
|
|
112
|
+
- **Semi-transparent fill** — alpha between 0.2-0.7, creating watercolor-style blending where shapes overlap
|
|
113
|
+
- **Color jitter** — ±8% RGB variation on fills, ±5% on strokes, so no two shapes using the "same" palette color are pixel-identical
|
|
114
|
+
- **Positional color** — fill color is biased by the shape's canvas position, creating smooth color flow
|
|
115
|
+
- **Glow effect** — 45% of sacred shapes and 20% of others get a `shadowBlur` glow (8-28px scaled), with glow color at 60% opacity
|
|
116
|
+
- **Gradient fill** — ~30% of shapes get a radial gradient between two jittered palette colors instead of a flat fill
|
|
117
|
+
- **Variable stroke width** — 0.5-2.5px scaled to canvas size
|
|
118
|
+
|
|
119
|
+
### Recursive Nesting
|
|
120
|
+
|
|
121
|
+
~15% of shapes larger than 40% of max size spawn 1-3 inner shapes:
|
|
122
|
+
- Inner shapes are drawn at the parent's position with small random offsets
|
|
123
|
+
- They use more complex/sacred shape types (layer ratio biased +0.3)
|
|
124
|
+
- Sized at 15-40% of the parent
|
|
125
|
+
- More transparent than the parent layer
|
|
126
|
+
|
|
127
|
+
## 7. Flow-Line Pass
|
|
128
|
+
|
|
129
|
+
6-16 flowing curves are drawn across the canvas, following the hash-derived vector field:
|
|
130
|
+
|
|
131
|
+
- Each line starts at a random position and takes 30-70 steps
|
|
132
|
+
- At each step, direction is determined by the flow field angle at that position plus slight random wobble
|
|
133
|
+
- Lines stop if they leave the canvas bounds
|
|
134
|
+
- Drawn at very low opacity (6-16%) with thin strokes for subtle movement
|
|
135
|
+
|
|
136
|
+
The flow field is defined by:
|
|
137
|
+
```
|
|
138
|
+
angle(x, y) = baseAngle + sin(x/w × freq × 2π) × π/2 + cos(y/h × freq × 2π) × π/2
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## 8. Noise Texture Overlay
|
|
142
|
+
|
|
143
|
+
A dedicated noise RNG (seeded separately from the main RNG to avoid affecting shape generation) renders thousands of 1px dots across the canvas:
|
|
144
|
+
|
|
145
|
+
- Density: ~1 dot per 800 square pixels
|
|
146
|
+
- Each dot is either black or white (50/50)
|
|
147
|
+
- Very low opacity (1-4%)
|
|
148
|
+
- Creates subtle film-grain texture that adds organic depth
|
|
149
|
+
|
|
150
|
+
## 9. Organic Connecting Curves
|
|
151
|
+
|
|
152
|
+
Quadratic bezier curves connect nearby shapes:
|
|
153
|
+
|
|
154
|
+
- Number of curves scales with canvas area (~8 per megapixel)
|
|
155
|
+
- Each curve connects two shapes that were drawn near each other in sequence
|
|
156
|
+
- Control points are offset perpendicular to the connecting line with random bulge
|
|
157
|
+
- Drawn at low opacity (6-16%) with palette colors at 30% alpha
|
|
158
|
+
|
|
159
|
+
## Shape Implementations
|
|
160
|
+
|
|
161
|
+
### Basic Shapes
|
|
162
|
+
Standard geometric primitives drawn as canvas paths (beginPath → moveTo/lineTo/arc → closePath). The draw pipeline calls `fill()` and `stroke()` after the path is defined.
|
|
163
|
+
|
|
164
|
+
### Complex Shapes
|
|
165
|
+
More intricate geometry including:
|
|
166
|
+
- **Platonic solids** — 2D projections with all edges drawn between vertices
|
|
167
|
+
- **Fibonacci spiral** — iterative arc segments following the golden ratio
|
|
168
|
+
- **Islamic pattern** — 8-pointed star grid at intersections
|
|
169
|
+
- **Celtic knot** — bezier over/under weaving pattern
|
|
170
|
+
- **Mandala** — concentric circles with radial lines
|
|
171
|
+
- **Fractal tree** — recursive branching at ±30° with 0.7× length decay
|
|
172
|
+
|
|
173
|
+
### Sacred Geometry
|
|
174
|
+
Mathematically precise sacred geometry patterns:
|
|
175
|
+
- **Flower of Life** — 7 overlapping circles in hexagonal arrangement
|
|
176
|
+
- **Tree of Life** — 10 Sephirot nodes with connecting paths
|
|
177
|
+
- **Metatron's Cube** — 13 vertices (center + inner/outer hexagons) fully connected
|
|
178
|
+
- **Sri Yantra** — 9 interlocking triangles at two radii
|
|
179
|
+
- **Seed of Life** — 7 circles (same as Flower of Life, different scale)
|
|
180
|
+
- **Vesica Piscis** — two overlapping circles
|
|
181
|
+
- **Torus** — 2D projection of a torus via line segments
|
|
182
|
+
- **Egg of Life** — 7 circles in tight hexagonal packing
|
|
183
|
+
|
|
184
|
+
## Configuration
|
|
185
|
+
|
|
186
|
+
All parameters are exposed via `GenerationConfig`:
|
|
187
|
+
|
|
188
|
+
| Parameter | Default | Effect |
|
|
189
|
+
|-----------|---------|--------|
|
|
190
|
+
| `width` | 2048 | Canvas width in pixels |
|
|
191
|
+
| `height` | 2048 | Canvas height in pixels |
|
|
192
|
+
| `gridSize` | 5 | Base shape count = gridSize² × 1.5 |
|
|
193
|
+
| `layers` | 4 | Number of rendering layers |
|
|
194
|
+
| `minShapeSize` | 30 | Minimum shape size (scaled to canvas) |
|
|
195
|
+
| `maxShapeSize` | 400 | Maximum shape size (scaled to canvas) |
|
|
196
|
+
| `baseOpacity` | 0.7 | First layer opacity |
|
|
197
|
+
| `opacityReduction` | 0.12 | Opacity decay per layer |
|
|
198
|
+
| `shapesPerLayer` | auto | Override auto-calculated shape count |
|
package/CHANGELOG.md
CHANGED
|
@@ -4,9 +4,28 @@ 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.3.0](https://github.com/gfargo/git-hash-art/compare/0.2.0...0.3.0)
|
|
8
|
+
|
|
9
|
+
- feat: evolve art generation with composition modes, flow fields, nesting, and texture [`#9`](https://github.com/gfargo/git-hash-art/pull/9)
|
|
10
|
+
- refactor(browser): simplify export statement [`dc193c9`](https://github.com/gfargo/git-hash-art/commit/dc193c972511c5b0eb9e6a781c423aa005453007)
|
|
11
|
+
|
|
12
|
+
#### [0.2.0](https://github.com/gfargo/git-hash-art/compare/0.1.0...0.2.0)
|
|
13
|
+
|
|
14
|
+
> 19 March 2026
|
|
15
|
+
|
|
16
|
+
- feat: add cross-platform browser support [`#8`](https://github.com/gfargo/git-hash-art/pull/8)
|
|
17
|
+
- feat: add visual effects for richer art generation [`#6`](https://github.com/gfargo/git-hash-art/pull/6)
|
|
18
|
+
- fix: improve art generation quality [`#5`](https://github.com/gfargo/git-hash-art/pull/5)
|
|
19
|
+
- docs: update README to reflect current algorithm and features [`15879c6`](https://github.com/gfargo/git-hash-art/commit/15879c62480a2d418c4ef8dcb479d912a7160345)
|
|
20
|
+
- chore: release v0.2.0 [`6867e06`](https://github.com/gfargo/git-hash-art/commit/6867e067f6dda0f4a4fd444b412772ddecb01555)
|
|
21
|
+
- fix(shapes): handle missing shape type default [`860bfd3`](https://github.com/gfargo/git-hash-art/commit/860bfd36caab97d6ed44dd441ea1a995863b6068)
|
|
22
|
+
|
|
7
23
|
#### [0.1.0](https://github.com/gfargo/git-hash-art/compare/0.0.4...0.1.0)
|
|
8
24
|
|
|
25
|
+
> 18 March 2026
|
|
26
|
+
|
|
9
27
|
- update shape drawing for platonic solids [`c26decd`](https://github.com/gfargo/git-hash-art/commit/c26decd8df9d7d47615efce37da8fdf554cdfcc4)
|
|
28
|
+
- chore: release v0.1.0 [`f83dce5`](https://github.com/gfargo/git-hash-art/commit/f83dce5de7a03da5432b1bb538643b7fcb9cd29f)
|
|
10
29
|
|
|
11
30
|
#### [0.0.4](https://github.com/gfargo/git-hash-art/compare/0.0.3...0.0.4)
|
|
12
31
|
|
package/README.md
CHANGED
|
@@ -2,15 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
Generate beautiful, deterministic abstract art from git commit hashes. Perfect for creating unique visual representations of your project's commits, generating placeholder images, or creating artistic wallpapers.
|
|
4
4
|
|
|
5
|
+
Works in both Node.js and browser environments.
|
|
6
|
+
|
|
5
7
|
## Features
|
|
6
8
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
9
|
+
- Deterministic output — same hash always produces the same image
|
|
10
|
+
- Hash-derived harmonious color schemes (analogic, complementary, and triadic palettes)
|
|
11
|
+
- 20+ shape types across three categories: basic, complex, and sacred geometry
|
|
12
|
+
- Layered composition with depth — early layers use simple shapes, later layers use intricate ones
|
|
13
|
+
- Watercolor-style transparency with semi-transparent fills and color blending
|
|
14
|
+
- Glow effects on sacred geometry shapes for an ethereal quality
|
|
15
|
+
- Radial gradient fills and organic color jitter for a hand-painted feel
|
|
16
|
+
- Organic bezier curves connecting nearby shapes
|
|
17
|
+
- Configurable canvas size, layers, shape sizes, and opacity
|
|
18
|
+
- Built-in presets for social media, device wallpapers, and print sizes
|
|
19
|
+
- CLI for generating art from the current commit or a specific hash
|
|
20
|
+
- Cross-platform: runs in Node.js (via `@napi-rs/canvas`) and browsers (native Canvas API)
|
|
14
21
|
|
|
15
22
|
## Installation
|
|
16
23
|
|
|
@@ -18,87 +25,170 @@ Generate beautiful, deterministic abstract art from git commit hashes. Perfect f
|
|
|
18
25
|
npm install git-hash-art
|
|
19
26
|
```
|
|
20
27
|
|
|
21
|
-
|
|
28
|
+
For Node.js usage you also need the canvas backend:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install @napi-rs/canvas
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Browser usage requires no additional dependencies — the library uses the native Canvas 2D API.
|
|
35
|
+
|
|
36
|
+
## Node.js Usage
|
|
22
37
|
|
|
23
38
|
```javascript
|
|
24
|
-
import { generateImageFromHash } from 'git-hash-art';
|
|
39
|
+
import { generateImageFromHash, saveImageToFile } from 'git-hash-art';
|
|
25
40
|
|
|
26
|
-
// Generate
|
|
41
|
+
// Generate a PNG buffer from a git hash
|
|
27
42
|
const gitHash = '46192e59d42f741c761cbea79462a8b3815dd905';
|
|
28
|
-
generateImageFromHash(gitHash);
|
|
43
|
+
const imageBuffer = generateImageFromHash(gitHash);
|
|
44
|
+
|
|
45
|
+
// Save to disk
|
|
46
|
+
saveImageToFile(imageBuffer, './output', gitHash, 'my-art', 2048, 2048);
|
|
29
47
|
```
|
|
30
48
|
|
|
31
|
-
|
|
49
|
+
### Advanced Node.js Usage
|
|
32
50
|
|
|
33
51
|
```javascript
|
|
34
|
-
|
|
52
|
+
import { generateImageFromHash } from 'git-hash-art';
|
|
53
|
+
|
|
35
54
|
const config = {
|
|
36
55
|
width: 1920,
|
|
37
56
|
height: 1080,
|
|
38
57
|
gridSize: 6,
|
|
39
|
-
layers:
|
|
40
|
-
shapesPerLayer:
|
|
58
|
+
layers: 5,
|
|
59
|
+
shapesPerLayer: 40,
|
|
41
60
|
minShapeSize: 20,
|
|
42
|
-
maxShapeSize:
|
|
43
|
-
baseOpacity: 0.
|
|
44
|
-
opacityReduction: 0.
|
|
61
|
+
maxShapeSize: 300,
|
|
62
|
+
baseOpacity: 0.7,
|
|
63
|
+
opacityReduction: 0.12
|
|
45
64
|
};
|
|
46
65
|
|
|
47
|
-
generateImageFromHash(gitHash, config);
|
|
66
|
+
const imageBuffer = generateImageFromHash(gitHash, config);
|
|
48
67
|
```
|
|
49
68
|
|
|
50
|
-
##
|
|
69
|
+
## Browser Usage
|
|
51
70
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
| `height` | number | 1024 | Canvas height in pixels |
|
|
56
|
-
| `gridSize` | number | 4 | Number of grid cells (gridSize x gridSize) |
|
|
57
|
-
| `layers` | number | 5 | Number of layers to generate |
|
|
58
|
-
| `shapesPerLayer` | number | - | Base number of shapes per layer (defaults to grid cells * 1.5) |
|
|
59
|
-
| `minShapeSize` | number | 20 | Minimum shape size |
|
|
60
|
-
| `maxShapeSize` | number | 180 | Maximum shape size |
|
|
61
|
-
| `baseOpacity` | number | 0.6 | Starting opacity for first layer |
|
|
62
|
-
| `opacityReduction` | number | 0.1 | How much to reduce opacity per layer |
|
|
71
|
+
```javascript
|
|
72
|
+
import { renderToCanvas, generateDataURL, generateImageBlob } from 'git-hash-art/browser';
|
|
73
|
+
```
|
|
63
74
|
|
|
64
|
-
|
|
75
|
+
### Render onto an existing canvas element
|
|
65
76
|
|
|
66
|
-
|
|
77
|
+
```javascript
|
|
78
|
+
import { renderToCanvas } from 'git-hash-art/browser';
|
|
79
|
+
|
|
80
|
+
const canvas = document.getElementById('art-canvas');
|
|
81
|
+
canvas.width = 1024;
|
|
82
|
+
canvas.height = 1024;
|
|
83
|
+
|
|
84
|
+
renderToCanvas(canvas, '46192e59d42f741c761cbea79462a8b3815dd905');
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Generate a data URL (for `<img>` tags)
|
|
67
88
|
|
|
68
89
|
```javascript
|
|
69
|
-
import {
|
|
90
|
+
import { generateDataURL } from 'git-hash-art/browser';
|
|
70
91
|
|
|
71
|
-
|
|
72
|
-
|
|
92
|
+
const dataUrl = generateDataURL('46192e59d42f741c761cbea79462a8b3815dd905', {
|
|
93
|
+
width: 512,
|
|
94
|
+
height: 512,
|
|
95
|
+
});
|
|
73
96
|
|
|
74
|
-
|
|
75
|
-
generateImageFromHash(gitHash, PRESETS['phone-wallpaper'].config);
|
|
97
|
+
document.getElementById('preview').src = dataUrl;
|
|
76
98
|
```
|
|
77
99
|
|
|
78
|
-
|
|
79
|
-
- Standard (1024x1024)
|
|
80
|
-
- Banner (1920x480)
|
|
81
|
-
- Ultrawide (3440x1440)
|
|
82
|
-
- Instagram (1080x1080)
|
|
83
|
-
- Instagram Story (1080x1920)
|
|
84
|
-
- Twitter Header (1500x500)
|
|
85
|
-
- LinkedIn Banner (1584x396)
|
|
86
|
-
- Phone Wallpaper (1170x2532)
|
|
87
|
-
- Tablet Wallpaper (2048x2732)
|
|
88
|
-
- Print sizes (A4/A3 at 300 DPI)
|
|
100
|
+
### Generate a Blob (for downloads or uploads)
|
|
89
101
|
|
|
90
|
-
|
|
102
|
+
```javascript
|
|
103
|
+
import { generateImageBlob } from 'git-hash-art/browser';
|
|
104
|
+
|
|
105
|
+
const blob = await generateImageBlob('46192e59d42f741c761cbea79462a8b3815dd905', {
|
|
106
|
+
width: 1080,
|
|
107
|
+
height: 1080,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Trigger a download
|
|
111
|
+
const url = URL.createObjectURL(blob);
|
|
112
|
+
const a = document.createElement('a');
|
|
113
|
+
a.href = url;
|
|
114
|
+
a.download = 'hash-art.png';
|
|
115
|
+
a.click();
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Core Renderer (Environment-Agnostic)
|
|
119
|
+
|
|
120
|
+
If you need full control, both entry points re-export `renderHashArt` which
|
|
121
|
+
accepts any standard `CanvasRenderingContext2D` — useful for custom canvas
|
|
122
|
+
setups, Web Workers with `OffscreenCanvas`, or server-side rendering
|
|
123
|
+
frameworks.
|
|
124
|
+
|
|
125
|
+
```javascript
|
|
126
|
+
import { renderHashArt } from 'git-hash-art'; // or 'git-hash-art/browser'
|
|
127
|
+
|
|
128
|
+
const ctx = myCanvas.getContext('2d');
|
|
129
|
+
renderHashArt(ctx, '46192e59d42f741c761cbea79462a8b3815dd905', {
|
|
130
|
+
width: myCanvas.width,
|
|
131
|
+
height: myCanvas.height,
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Configuration Options
|
|
136
|
+
|
|
137
|
+
| Option | Type | Default | Description |
|
|
138
|
+
| ----------------- | ------ | ------- | ---------------------------------------------------- |
|
|
139
|
+
| `width` | number | 2048 | Canvas width in pixels |
|
|
140
|
+
| `height` | number | 2048 | Canvas height in pixels |
|
|
141
|
+
| `gridSize` | number | 5 | Controls base shape count per layer (gridSize² × 1.5)|
|
|
142
|
+
| `layers` | number | 4 | Number of layers to generate |
|
|
143
|
+
| `shapesPerLayer` | number | auto | Base shapes per layer (defaults to gridSize² × 1.5) |
|
|
144
|
+
| `minShapeSize` | number | 30 | Minimum shape size in pixels (scaled to canvas) |
|
|
145
|
+
| `maxShapeSize` | number | 400 | Maximum shape size in pixels (scaled to canvas) |
|
|
146
|
+
| `baseOpacity` | number | 0.7 | Starting opacity for the first layer |
|
|
147
|
+
| `opacityReduction`| number | 0.12 | Opacity reduction per layer |
|
|
148
|
+
|
|
149
|
+
## Shape Categories
|
|
91
150
|
|
|
92
|
-
|
|
151
|
+
Shapes are selected with layer-aware weighting — early layers favor simple shapes for background texture, later layers favor intricate ones for foreground detail.
|
|
152
|
+
|
|
153
|
+
**Basic** — circle, square, triangle, hexagon, star, diamond, cube, heart
|
|
154
|
+
|
|
155
|
+
**Complex** — platonic solids, fibonacci spiral, islamic pattern, celtic knot, merkaba, mandala, fractal
|
|
156
|
+
|
|
157
|
+
**Sacred Geometry** — flower of life, tree of life, Metatron's cube, Sri Yantra, seed of life, vesica piscis, torus, egg of life
|
|
158
|
+
|
|
159
|
+
## Preset Sizes
|
|
160
|
+
|
|
161
|
+
```javascript
|
|
162
|
+
import { PRESETS } from 'git-hash-art';
|
|
163
|
+
|
|
164
|
+
// Use a preset's hash and config
|
|
165
|
+
const preset = PRESETS['instagram-square'];
|
|
166
|
+
const imageBuffer = generateImageFromHash(preset.hash, preset);
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Available presets:
|
|
170
|
+
|
|
171
|
+
- Standard (1024×1024)
|
|
172
|
+
- Banner (1920×480)
|
|
173
|
+
- Ultrawide (3440×1440)
|
|
174
|
+
- Instagram Square (1080×1080)
|
|
175
|
+
- Instagram Story (1080×1920)
|
|
176
|
+
- Twitter Header (1500×500)
|
|
177
|
+
- LinkedIn Banner (1584×396)
|
|
178
|
+
- Phone Wallpaper (1170×2532)
|
|
179
|
+
- Tablet Wallpaper (2048×2732)
|
|
180
|
+
- Minimal, Complex (special configurations)
|
|
181
|
+
|
|
182
|
+
## CLI Usage
|
|
93
183
|
|
|
94
184
|
```bash
|
|
95
|
-
# Generate
|
|
185
|
+
# Generate from the current commit
|
|
96
186
|
npx git-hash-art current
|
|
97
187
|
|
|
98
|
-
# Generate from specific hash
|
|
188
|
+
# Generate from a specific hash
|
|
99
189
|
npx git-hash-art generate <hash>
|
|
100
190
|
|
|
101
|
-
#
|
|
191
|
+
# Custom size
|
|
102
192
|
npx git-hash-art generate <hash> --width 1920 --height 1080
|
|
103
193
|
```
|
|
104
194
|
|
|
@@ -115,7 +205,7 @@ jobs:
|
|
|
115
205
|
steps:
|
|
116
206
|
- uses: actions/checkout@v2
|
|
117
207
|
- uses: actions/setup-node@v2
|
|
118
|
-
- run: npm install git-hash-art-
|
|
208
|
+
- run: npm install git-hash-art @napi-rs/canvas
|
|
119
209
|
- run: npx git-hash-art current --output artwork/
|
|
120
210
|
```
|
|
121
211
|
|
|
@@ -124,15 +214,33 @@ jobs:
|
|
|
124
214
|
```bash
|
|
125
215
|
#!/bin/sh
|
|
126
216
|
# .git/hooks/post-commit
|
|
127
|
-
|
|
128
217
|
hash=$(git rev-parse HEAD)
|
|
129
218
|
npx git-hash-art generate $hash --output .git/artwork/
|
|
130
219
|
```
|
|
131
220
|
|
|
221
|
+
### React Component
|
|
222
|
+
|
|
223
|
+
```jsx
|
|
224
|
+
import { useEffect, useRef } from 'react';
|
|
225
|
+
import { renderToCanvas } from 'git-hash-art/browser';
|
|
226
|
+
|
|
227
|
+
function CommitArt({ hash, width = 256, height = 256 }) {
|
|
228
|
+
const canvasRef = useRef(null);
|
|
229
|
+
|
|
230
|
+
useEffect(() => {
|
|
231
|
+
if (canvasRef.current) {
|
|
232
|
+
renderToCanvas(canvasRef.current, hash, { width, height });
|
|
233
|
+
}
|
|
234
|
+
}, [hash, width, height]);
|
|
235
|
+
|
|
236
|
+
return <canvas ref={canvasRef} width={width} height={height} />;
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
132
240
|
## Contributing
|
|
133
241
|
|
|
134
242
|
Contributions are welcome! Please see our [Contributing Guidelines](CONTRIBUTING.md) for more details.
|
|
135
243
|
|
|
136
244
|
## License
|
|
137
245
|
|
|
138
|
-
MIT License - see [LICENSE](LICENSE) for details.
|
|
246
|
+
MIT License - see [LICENSE](LICENSE) for details.
|