zer0-image-generator 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +42 -57
- data/lib/zer0_image_generator/preview_generator.py +4 -1
- data/lib/zer0_image_generator/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 15dc8c56843fbbebfe9e26afc0f48cb54cfc75cc8a9b938db40a0cd9f6cd389d
|
|
4
|
+
data.tar.gz: b7ab70a697bbc9161ec8ccc16dfced4fb4e560763ba020803c682e25a0803d0b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 187f71882b0092c5d99c1df0b1685d941770bbc1dbaf62dfa330a9ec17433248423669327f6188a957b1a9ec31ece5b12b1e00f04c274828c17572d9a2a94952
|
|
7
|
+
data.tar.gz: 2db8e40e2698daba7d05ad47f3c981f608ad118841f3efcb21661616295d9b62f1d1a1788a2509ae7c45e1f538685f1baa6f7505a1b7702bc701fea9ad9ffcc3
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.6.0](https://github.com/bamr87/zer0-image-generator/compare/zer0-image-generator/v0.5.0...zer0-image-generator/v0.6.0) (2026-07-23)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* **svg:** adopt the svg-art-kit authoring loop (hook, lint, sweep, critic) ([#6](https://github.com/bamr87/zer0-image-generator/issues/6)) ([d45b28f](https://github.com/bamr87/zer0-image-generator/commit/d45b28f1a8192bc154f4f8c79f433769d4e95e12))
|
|
14
|
+
|
|
8
15
|
## [0.5.0](https://github.com/bamr87/zer0-image-generator/compare/zer0-image-generator-v0.4.0...zer0-image-generator/v0.5.0) (2026-07-15)
|
|
9
16
|
|
|
10
17
|
|
data/README.md
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
# zer0-image-generator
|
|
2
2
|
|
|
3
|
-
[](https://github.com/bamr87/zer0-image-generator/actions/workflows/test.yml)
|
|
4
|
-
[](LICENSE)
|
|
3
|
+
[](https://github.com/bamr87/zer0-image-generator/actions/workflows/test.yml) [](LICENSE)
|
|
5
4
|
|
|
6
|
-
AI preview/social images for **any Jekyll site** — Claude directs and reviews,
|
|
7
|
-
an image model renders, and your front matter gets wired up automatically.
|
|
5
|
+
AI preview/social images for **any Jekyll site** — Claude directs and reviews, an image model renders, and your front matter gets wired up automatically.
|
|
8
6
|
|
|
9
|
-
Extracted from the [zer0-mistakes](https://github.com/bamr87/zer0-mistakes)
|
|
10
|
-
theme's consolidated engine and generalized: every theme-specific assumption
|
|
11
|
-
is now a config knob with zer0-compatible defaults, so the theme and this
|
|
12
|
-
plugin stay **separate but portable**.
|
|
7
|
+
Extracted from the [zer0-mistakes](https://github.com/bamr87/zer0-mistakes) theme's consolidated engine and generalized: every theme-specific assumption is now a config knob with zer0-compatible defaults, so the theme and this plugin stay **separate but portable**.
|
|
13
8
|
|
|
14
9
|
## How it works
|
|
15
10
|
|
|
@@ -29,9 +24,7 @@ Each post/page without a preview goes through a three-stage pipeline:
|
|
|
29
24
|
| gemini | gemini-2.5-flash-image | `GEMINI_API_KEY` |
|
|
30
25
|
| local | deterministic template SVG → PNG | none (CI-safe) |
|
|
31
26
|
|
|
32
|
-
Claude never renders pixels (the Anthropic API has no image endpoint); without
|
|
33
|
-
a Claude credential the analyze/review stages degrade gracefully to a template
|
|
34
|
-
prompt and the renderer still runs.
|
|
27
|
+
Claude never renders pixels (the Anthropic API has no image endpoint); without a Claude credential the analyze/review stages degrade gracefully to a template prompt and the renderer still runs.
|
|
35
28
|
|
|
36
29
|
## Install
|
|
37
30
|
|
|
@@ -44,8 +37,7 @@ group :jekyll_plugins do
|
|
|
44
37
|
end
|
|
45
38
|
```
|
|
46
39
|
|
|
47
|
-
Requires `python3` (3.9+) with PyYAML — the command checks and tells you if
|
|
48
|
-
either is missing:
|
|
40
|
+
Requires `python3` (3.9+) with PyYAML — the command checks and tells you if either is missing:
|
|
49
41
|
|
|
50
42
|
```bash
|
|
51
43
|
python3 -m pip install pyyaml
|
|
@@ -61,8 +53,7 @@ bundle exec jekyll preview-images # generate them
|
|
|
61
53
|
|
|
62
54
|
### Standalone (no Ruby required)
|
|
63
55
|
|
|
64
|
-
The engine is one dependency-light Python file. Copy it anywhere and run it
|
|
65
|
-
from your site root:
|
|
56
|
+
The engine is one dependency-light Python file. Copy it anywhere and run it from your site root:
|
|
66
57
|
|
|
67
58
|
```bash
|
|
68
59
|
curl -o preview_generator.py \
|
|
@@ -72,8 +63,7 @@ python3 preview_generator.py --dry-run
|
|
|
72
63
|
|
|
73
64
|
## Configuration
|
|
74
65
|
|
|
75
|
-
Everything lives under `preview_images:` in your `_config.yml`. Shown with
|
|
76
|
-
defaults:
|
|
66
|
+
Everything lives under `preview_images:` in your `_config.yml`. Shown with defaults:
|
|
77
67
|
|
|
78
68
|
```yaml
|
|
79
69
|
preview_images:
|
|
@@ -101,13 +91,9 @@ preview_images:
|
|
|
101
91
|
auto_prefix: true # ... and it is re-added for existence checks
|
|
102
92
|
```
|
|
103
93
|
|
|
104
|
-
Priority per file: author overrides → collection styles → CLI flags →
|
|
105
|
-
environment variables → `_config.yml` → built-in defaults.
|
|
94
|
+
Priority per file: author overrides → collection styles → CLI flags → environment variables → `_config.yml` → built-in defaults.
|
|
106
95
|
|
|
107
|
-
Jekyll's own top-level `source:` key is honored automatically: on a site with
|
|
108
|
-
`source: pages` (content, assets, and `_data` under `pages/`), every disk path
|
|
109
|
-
above resolves inside `pages/` while front-matter values keep their site-URL
|
|
110
|
-
form. No extra configuration needed.
|
|
96
|
+
Jekyll's own top-level `source:` key is honored automatically: on a site with `source: pages` (content, assets, and `_data` under `pages/`), every disk path above resolves inside `pages/` while front-matter values keep their site-URL form. No extra configuration needed.
|
|
111
97
|
|
|
112
98
|
### Recipe: standard Jekyll site with jekyll-seo-tag
|
|
113
99
|
|
|
@@ -120,8 +106,7 @@ preview_images:
|
|
|
120
106
|
authors_file: ''
|
|
121
107
|
```
|
|
122
108
|
|
|
123
|
-
Generated front matter: `image: /assets/images/previews/my-post.png` — exactly
|
|
124
|
-
what `jekyll-seo-tag` turns into `og:image`.
|
|
109
|
+
Generated front matter: `image: /assets/images/previews/my-post.png` — exactly what `jekyll-seo-tag` turns into `og:image`.
|
|
125
110
|
|
|
126
111
|
### Recipe: zer0-mistakes theme
|
|
127
112
|
|
|
@@ -133,28 +118,38 @@ preview_images:
|
|
|
133
118
|
# front_matter_key/preview + /assets prefixing are already the defaults
|
|
134
119
|
```
|
|
135
120
|
|
|
121
|
+
### Recipe: children's book collections (drsai)
|
|
122
|
+
|
|
123
|
+
The [drsai storybook platform](https://github.com/bamr87/drsai) publishes picture books through the zer0-mistakes `books` collection and uses this gem for each story's social/preview banner. Match the banner style to the book's illustration bible so cards and pages read as one book:
|
|
124
|
+
|
|
125
|
+
```yaml
|
|
126
|
+
preview_images:
|
|
127
|
+
provider: openai
|
|
128
|
+
collections: [books]
|
|
129
|
+
# each story's `preview` starts as its first illustration plate; this gem
|
|
130
|
+
# fills banners for pages that don't have one yet
|
|
131
|
+
style: >-
|
|
132
|
+
cozy warm digital watercolor storybook art, soft colored-pencil outlines,
|
|
133
|
+
rounded friendly shapes, sun-baked desert palette, gentle golden-hour light
|
|
134
|
+
style_modifiers: kid-friendly, never photorealistic, never dark or scary
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Note the division of labor: this gem renders **one banner per page** keyed on front matter; the *in-story* illustration plates (several per story, tracked in each page's `illustrations:` list) are rendered by drsai's own `tools/generate_illustrations.py` against the same OpenAI credential.
|
|
138
|
+
|
|
136
139
|
### Batch performance
|
|
137
140
|
|
|
138
|
-
The engine parallelizes **within one invocation** (4 workers by default, `-j N`
|
|
139
|
-
to change). For many files, one collection run beats a loop of single-file
|
|
140
|
-
runs — the loop pays process startup per file and never engages the pool:
|
|
141
|
+
The engine parallelizes **within one invocation** (4 workers by default, `-j N` to change). For many files, one collection run beats a loop of single-file runs — the loop pays process startup per file and never engages the pool:
|
|
141
142
|
|
|
142
143
|
```bash
|
|
143
144
|
bundle exec jekyll preview-images --collection posts --parallel 6 # ✓ parallel
|
|
144
145
|
for f in ...; do jekyll preview-images -f "$f"; done # ✗ serial
|
|
145
146
|
```
|
|
146
147
|
|
|
147
|
-
Claude orchestration runs at `claude_effort: low` by default — right-sized for
|
|
148
|
-
a short art brief and a render verdict. Raise it (or set `claude_model`) if you
|
|
149
|
-
want deeper art direction at the cost of latency.
|
|
148
|
+
Claude orchestration runs at `claude_effort: low` by default — right-sized for a short art brief and a render verdict. Raise it (or set `claude_model`) if you want deeper art direction at the cost of latency.
|
|
150
149
|
|
|
151
150
|
### Per-collection styles
|
|
152
151
|
|
|
153
|
-
Give each collection its own visual identity — tutorials render differently
|
|
154
|
-
from field notes, docs differently from reviews. Any of `style`,
|
|
155
|
-
`style_modifiers`, `size`, `quality`, and `model` can be set per collection;
|
|
156
|
-
everything else inherits the global config. A file's collection comes from its
|
|
157
|
-
`_<name>` directory; author overrides still win over collection styles.
|
|
152
|
+
Give each collection its own visual identity — tutorials render differently from field notes, docs differently from reviews. Any of `style`, `style_modifiers`, `size`, `quality`, and `model` can be set per collection; everything else inherits the global config. A file's collection comes from its `_<name>` directory; author overrides still win over collection styles.
|
|
158
153
|
|
|
159
154
|
```yaml
|
|
160
155
|
preview_images:
|
|
@@ -171,8 +166,7 @@ preview_images:
|
|
|
171
166
|
|
|
172
167
|
### Per-author style overrides
|
|
173
168
|
|
|
174
|
-
If `authors_file` points at a YAML map, an author's `preview:` block overrides
|
|
175
|
-
`style`, `style_modifiers`, `size`, `quality`, and `model` for their pages:
|
|
169
|
+
If `authors_file` points at a YAML map, an author's `preview:` block overrides `style`, `style_modifiers`, `size`, `quality`, and `model` for their pages:
|
|
176
170
|
|
|
177
171
|
```yaml
|
|
178
172
|
# _data/authors.yml
|
|
@@ -184,8 +178,7 @@ cassandra:
|
|
|
184
178
|
|
|
185
179
|
## Credentials
|
|
186
180
|
|
|
187
|
-
The renderer needs its own key (default: `OPENAI_API_KEY`). Claude
|
|
188
|
-
orchestration accepts any ONE of, in order — it is optional:
|
|
181
|
+
The renderer needs its own key (default: `OPENAI_API_KEY`). Claude orchestration accepts any ONE of, in order — it is optional:
|
|
189
182
|
|
|
190
183
|
```bash
|
|
191
184
|
export CLAUDE_CODE_OAUTH_TOKEN="..." # 1. from `claude setup-token` (Pro/Max)
|
|
@@ -194,14 +187,11 @@ export ANTHROPIC_API_KEY="..." # 3. console.anthropic.com
|
|
|
194
187
|
# 4. nothing — a logged-in `claude` CLI is used automatically
|
|
195
188
|
```
|
|
196
189
|
|
|
197
|
-
Keys are read from the environment or a git-ignored `.env` at the site root.
|
|
198
|
-
On a Claude Pro/Max subscription the orchestration costs nothing extra; only
|
|
199
|
-
the renderer bills per image.
|
|
190
|
+
Keys are read from the environment or a git-ignored `.env` at the site root. On a Claude Pro/Max subscription the orchestration costs nothing extra; only the renderer bills per image.
|
|
200
191
|
|
|
201
192
|
## CLI reference
|
|
202
193
|
|
|
203
|
-
`jekyll preview-images` exposes the engine's flags (Jekyll claims `-s/-d/-p`
|
|
204
|
-
globally, so use long forms there; the Python CLI keeps all short flags):
|
|
194
|
+
`jekyll preview-images` exposes the engine's flags (Jekyll claims `-s/-d/-p` globally, so use long forms there; the Python CLI keeps all short flags):
|
|
205
195
|
|
|
206
196
|
```text
|
|
207
197
|
--dry-run --verbose --force --list-missing
|
|
@@ -214,9 +204,7 @@ globally, so use long forms there; the Python CLI keeps all short flags):
|
|
|
214
204
|
--assets-prefix PREFIX --no-auto-prefix --batch N --log-file FILE
|
|
215
205
|
```
|
|
216
206
|
|
|
217
|
-
The `local` provider rasterizes its SVG via the first available of
|
|
218
|
-
`rsvg-convert` (`brew install librsvg` / `apt install librsvg2-bin`),
|
|
219
|
-
`inkscape`, ImageMagick, or a vendored Playwright helper.
|
|
207
|
+
The `local` provider rasterizes its SVG via the first available of `rsvg-convert` (`brew install librsvg` / `apt install librsvg2-bin`), `inkscape`, ImageMagick, or a vendored Playwright helper.
|
|
220
208
|
|
|
221
209
|
## CI usage
|
|
222
210
|
|
|
@@ -228,28 +216,25 @@ The `local` provider rasterizes its SVG via the first available of
|
|
|
228
216
|
run: bundle exec jekyll preview-images
|
|
229
217
|
```
|
|
230
218
|
|
|
231
|
-
Generation is script-driven on demand — it is never part of `jekyll build`
|
|
232
|
-
(builds stay fast, deterministic, and secret-free; GitHub Pages safe mode is
|
|
233
|
-
irrelevant to it).
|
|
219
|
+
Generation is script-driven on demand — it is never part of `jekyll build` (builds stay fast, deterministic, and secret-free; GitHub Pages safe mode is irrelevant to it).
|
|
234
220
|
|
|
235
221
|
## Relationship to zer0-mistakes
|
|
236
222
|
|
|
237
|
-
The [zer0-mistakes](https://github.com/bamr87/zer0-mistakes) theme renders
|
|
238
|
-
`preview:` values with a pure-Liquid include (GitHub-Pages-safe, no plugin
|
|
239
|
-
needed) and currently vendors this engine at `scripts/lib/preview_generator.py`.
|
|
240
|
-
This repo is the portable home: the theme is expected to consume the gem (or
|
|
241
|
-
curl the engine from here) in a follow-up, so there is exactly ONE engine.
|
|
223
|
+
The [zer0-mistakes](https://github.com/bamr87/zer0-mistakes) theme renders `preview:` values with a pure-Liquid include (GitHub-Pages-safe, no plugin needed) and currently vendors this engine at `scripts/lib/preview_generator.py`. This repo is the portable home: the theme is expected to consume the gem (or curl the engine from here) in a follow-up, so there is exactly ONE engine.
|
|
242
224
|
|
|
243
225
|
## Development
|
|
244
226
|
|
|
245
227
|
```bash
|
|
246
|
-
python3 test/test_preview_generator.py #
|
|
228
|
+
python3 test/test_preview_generator.py # 108 unit tests, zero network
|
|
229
|
+
python3 test/test_freesvg.py # FreeSVG client/cache tests, network mocked
|
|
247
230
|
python3 -m py_compile lib/zer0_image_generator/preview_generator.py
|
|
248
231
|
gem build zer0-image-generator.gemspec
|
|
249
232
|
cd test/fixture-site && bundle install
|
|
250
233
|
bundle exec jekyll preview-images --dry-run # integration fixture
|
|
251
234
|
```
|
|
252
235
|
|
|
236
|
+
When touching SVG code (the local template, sanitizer, rasterizer chain), use the authoring loop in [tools/svg/](tools/svg/README.md): a PostToolUse hook lints and rasterizes every `.svg` write so the agent sees what it drew, `banner-seed.py` sweeps the engine's real template across seeds into a contact sheet, and the `svg-critic` subagent keeps render/critique churn out of the main context. The [showcase](docs/showcase/README.md) walks the whole pipeline with the intermediate images each piece iterated through.
|
|
237
|
+
|
|
253
238
|
Conventional Commits drive releases via release-please. One concern per PR.
|
|
254
239
|
|
|
255
240
|
## License
|
|
@@ -1295,8 +1295,11 @@ def render_local_svg(title: str, seed: int) -> str:
|
|
|
1295
1295
|
return rng % max(bound, 1)
|
|
1296
1296
|
|
|
1297
1297
|
w, h = SVG_WIDTH, SVG_HEIGHT
|
|
1298
|
+
safe_title = title.replace("&", "&").replace("<", "<")
|
|
1298
1299
|
parts = [
|
|
1299
|
-
f'<svg xmlns="{SVG_NS}" viewBox="0 0 {w} {h}" width="{w}" height="{h}"
|
|
1300
|
+
f'<svg xmlns="{SVG_NS}" viewBox="0 0 {w} {h}" width="{w}" height="{h}" '
|
|
1301
|
+
f'role="img">',
|
|
1302
|
+
f'<title>Preview banner: {safe_title}</title>',
|
|
1300
1303
|
f'<rect width="{w}" height="{h}" fill="{pal[0]}"/>',
|
|
1301
1304
|
]
|
|
1302
1305
|
# Sky bands
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: zer0-image-generator
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Amr Abdel
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-07-
|
|
11
|
+
date: 2026-07-23 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: jekyll
|