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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c105d9c5a9aab3c6b772c558fbf070788058e929a4ce846e9cbaa5da019e117d
4
- data.tar.gz: '0597cbdb685887b2733b29123aee8704366d96b1bca6781395a7bccf760d3748'
3
+ metadata.gz: 15dc8c56843fbbebfe9e26afc0f48cb54cfc75cc8a9b938db40a0cd9f6cd389d
4
+ data.tar.gz: b7ab70a697bbc9161ec8ccc16dfced4fb4e560763ba020803c682e25a0803d0b
5
5
  SHA512:
6
- metadata.gz: e791021d473f1b0b0246973a2e9dab6add20919b5c96b1e2df0806fa12269fd6ea3053ee20b3094dfa1aa365bcdb38ca5ea3e5f315116ff83fd073429aa40487
7
- data.tar.gz: edd3c2fcad1bbe57e3b87bab8a30b168855865b4ab79a6fc215727d8cbc9a42467da587bde09217798c0eb7bd2b40552db67ca5217ab7de71f7e08bf41a36f0d
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
- [![Test](https://github.com/bamr87/zer0-image-generator/actions/workflows/test.yml/badge.svg)](https://github.com/bamr87/zer0-image-generator/actions/workflows/test.yml)
4
- [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
3
+ [![Test](https://github.com/bamr87/zer0-image-generator/actions/workflows/test.yml/badge.svg)](https://github.com/bamr87/zer0-image-generator/actions/workflows/test.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](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 # 98 unit tests, zero network
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("&", "&amp;").replace("<", "&lt;")
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Zer0ImageGenerator
4
- VERSION = "0.5.0"
4
+ VERSION = "0.6.0"
5
5
  end
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.5.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-15 00:00:00.000000000 Z
11
+ date: 2026-07-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jekyll