aicodewith-image-generation-skill 1.0.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.
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env node
2
+ import fs from "node:fs";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import readline from "node:readline/promises";
6
+ import { stdin as input, stdout as output } from "node:process";
7
+ import { fileURLToPath } from "node:url";
8
+
9
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
10
+ const packageRoot = path.resolve(__dirname, "..");
11
+ const sourceSkillDir = path.join(packageRoot, "skill");
12
+ const targetSkillDir = path.join(
13
+ os.homedir(),
14
+ ".codex",
15
+ "skills",
16
+ "aicodewith-image-generation",
17
+ );
18
+ const codexEnvPath = path.join(os.homedir(), ".codex", ".env");
19
+
20
+ function installSkill() {
21
+ if (!fs.existsSync(path.join(sourceSkillDir, "SKILL.md"))) {
22
+ throw new Error(`Skill source not found: ${sourceSkillDir}`);
23
+ }
24
+
25
+ fs.rmSync(targetSkillDir, { recursive: true, force: true });
26
+ fs.mkdirSync(path.dirname(targetSkillDir), { recursive: true });
27
+ fs.cpSync(sourceSkillDir, targetSkillDir, { recursive: true });
28
+ }
29
+
30
+ function upsertEnvValue(filePath, key, value) {
31
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
32
+
33
+ const nextLine = `${key}=${value}`;
34
+ if (!fs.existsSync(filePath)) {
35
+ fs.writeFileSync(filePath, `${nextLine}\n`, { mode: 0o600 });
36
+ return;
37
+ }
38
+
39
+ const existing = fs.readFileSync(filePath, "utf8");
40
+ const lines = existing.split(/\r?\n/);
41
+ let replaced = false;
42
+ const updated = lines.map((line) => {
43
+ if (line.startsWith(`${key}=`)) {
44
+ replaced = true;
45
+ return nextLine;
46
+ }
47
+ return line;
48
+ });
49
+
50
+ if (!replaced) {
51
+ if (updated.length > 0 && updated[updated.length - 1] === "") {
52
+ updated[updated.length - 1] = nextLine;
53
+ updated.push("");
54
+ } else {
55
+ updated.push(nextLine, "");
56
+ }
57
+ }
58
+
59
+ fs.writeFileSync(filePath, updated.join("\n"), { mode: 0o600 });
60
+ fs.chmodSync(filePath, 0o600);
61
+ }
62
+
63
+ async function configureKey() {
64
+ const rl = readline.createInterface({ input, output });
65
+ try {
66
+ const answer = await rl.question("请输入 AICodeWith API Key: ");
67
+ const apiKey = answer.trim();
68
+ if (!apiKey) {
69
+ console.log("未配置 API key。之后可重新运行安装命令进行配置。");
70
+ return false;
71
+ }
72
+
73
+ upsertEnvValue(codexEnvPath, "AICODEWITH_API_KEY", apiKey);
74
+ return true;
75
+ } finally {
76
+ rl.close();
77
+ }
78
+ }
79
+
80
+ async function main() {
81
+ installSkill();
82
+ const configured = await configureKey();
83
+
84
+ console.log("");
85
+ console.log("AICodeWith image generation skill installed.");
86
+ console.log(`Skill: ${targetSkillDir}`);
87
+ if (configured) {
88
+ console.log(`API key saved to: ${codexEnvPath}`);
89
+ }
90
+ console.log("请重启 Codex,然后直接提出生图需求。");
91
+ }
92
+
93
+ main().catch((error) => {
94
+ console.error(error instanceof Error ? error.message : String(error));
95
+ process.exit(1);
96
+ });
package/package.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "aicodewith-image-generation-skill",
3
+ "version": "1.0.0",
4
+ "description": "Installer for the AICodeWith image generation Codex skill.",
5
+ "type": "module",
6
+ "bin": {
7
+ "aicodewith-image-generation-skill": "bin/install.mjs"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "skill"
12
+ ],
13
+ "license": "UNLICENSED",
14
+ "private": false
15
+ }
package/skill/SKILL.md ADDED
@@ -0,0 +1,234 @@
1
+ ---
2
+ name: aicodewith-image-generation
3
+ description: Mandatory skill for ALL image-generation related requests. Always use this skill whenever the user asks to 生图, 生成图片, 画图, 做图, 出图, 海报, logo, icon, illustration, poster, product shot, edit an image, image-to-image, reference image editing, or any task whose deliverable is a generated/edited image. Use AICodeWith image generation API to create images, edit images from reference URLs, poll async image tasks, and return generated image URLs. Do not use generic image generation tools or answer with only prompts unless this skill/API is unavailable or the user explicitly asks only for a prompt.
4
+ ---
5
+
6
+ # AICodeWith Image Generation
7
+
8
+ This is the mandatory workflow for any image-generation or image-editing task. If the user asks for 生图/生成图片/画图/做图/出图/海报/logo/icon/illustration/poster/product shot/image editing, load and follow this skill before using any image tool. Prefer the AICodeWith API path below; only fall back to a generic prompt or another image provider if this API is unavailable, lacks credentials, or the user explicitly requests a different provider/prompt-only output.
9
+
10
+ Use this skill whenever the user wants image generation through `https://api.aicodewith.com`, including text-to-image and image-to-image with reference URLs.
11
+
12
+ ## Credentials
13
+
14
+ - API key is stored in environment variable `AICODEWITH_API_KEY`.
15
+ - Do not print, reveal, or write the raw key in responses, logs, or generated files.
16
+ - If `AICODEWITH_API_KEY` is missing from the subprocess environment, check these `.env` files in order and load only the value needed for the request:
17
+ 1. `~/.codex/.env`
18
+ 2. `~/.aicodewith/.env`
19
+ - Never echo the key value. If it is missing from all locations, tell the user to run `npx aicodewith-image-generation-skill` and configure the key before using this skill.
20
+
21
+ ## API summary
22
+
23
+ Base URL: `https://api.aicodewith.com`
24
+
25
+ Create task:
26
+
27
+ ```http
28
+ POST /v1/images/generations
29
+ Authorization: Bearer $AICODEWITH_API_KEY
30
+ Content-Type: application/json
31
+ ```
32
+
33
+ Query task:
34
+
35
+ ```http
36
+ GET /v1/tasks/{task_id}
37
+ Authorization: Bearer $AICODEWITH_API_KEY
38
+ ```
39
+
40
+ Completion result images are in `result_data[].url`.
41
+
42
+ ## Supported request fields
43
+
44
+ - `model`: required. Prefer `gpt-image-2` unless user explicitly asks for `gpt-image-2-beta`.
45
+ - `prompt`: required, non-empty.
46
+ - `size`: optional. Recommended values: `auto`, `1:1`, `2:1`, `1:2`, `3:1`, `1:3`, `3:2`, `2:3`, `4:3`, `3:4`, `5:4`, `4:5`, `16:9`, `9:16`, `21:9`, `9:21`.
47
+ - `resolution`: optional. `1K`, `2K`, `4K`; only for `gpt-image-2` when `size` is a ratio.
48
+ - `n`: optional. `1-10`; only `gpt-image-2` supports multiple images. `gpt-image-2-beta` must use `n=1`.
49
+ - `quality`: optional. `low`, `medium`, `high`; only for `gpt-image-2`.
50
+ - `image_urls`: optional list of public reference image URLs. Use for image-to-image/reference editing/outpainting.
51
+ - `background`: optional; use `auto` by default.
52
+
53
+ ## Interaction rules — mandatory confirmation gate
54
+
55
+ Before creating any image-generation task, the assistant MUST get explicit user confirmation for these fields, even if the user's message already implies some of them:
56
+
57
+ - 模型 / `model`
58
+ - 比例 / `size`
59
+ - 数量 / `n`
60
+ - 质量 / `quality`
61
+ - 分辨率 / `resolution`
62
+
63
+ The assistant may propose values, but must not start the API request until the user confirms the full option set.
64
+
65
+ Required confirmation format:
66
+
67
+ ```text
68
+ 请确认本次生图参数:
69
+ - 模型:...
70
+ - 比例:...
71
+ - 数量:...
72
+ - 质量:...
73
+ - 分辨率:...
74
+
75
+ 确认后我再开始生成。
76
+ ```
77
+
78
+ Model-specific rules:
79
+
80
+ 1. Always ask/confirm the model first or include it in the parameter confirmation:
81
+ - `gpt-image-2`
82
+ - `gpt-image-2-beta`
83
+ 2. If using `gpt-image-2`, the confirmation must include actual selectable values for:
84
+ - quality: `low`, `medium`, `high`
85
+ - size/aspect ratio: `auto`, `1:1`, `16:9`, `9:16`, etc.
86
+ - resolution: `1K`, `2K`, `4K` when size is a ratio; use `不适用(auto 比例)` when size is `auto`
87
+ - image count `n`: `1-10`
88
+ 3. If using `gpt-image-2-beta`, the confirmation must still show all five fields, but mark unsupported fields as fixed/not applicable:
89
+ - 模型:`gpt-image-2-beta`
90
+ - 比例:user-selected or proposed size
91
+ - 数量:`1(beta 固定)`
92
+ - 质量:`不适用(beta 不支持)`
93
+ - 分辨率:`不适用(beta 不支持)`
94
+ 4. If the user's prompt is missing or too vague, ask for the image prompt before or together with the parameter confirmation.
95
+ 5. Do not silently apply defaults. Even when the user says “默认 / 随便 / 你决定”, propose the default values in the five-field confirmation and wait for the user to confirm.
96
+ 6. Only proceed to API creation after the user clearly confirms, e.g. “确认”, “可以”, “就按这个”, “开始生成”.
97
+
98
+ ## Defaults
99
+
100
+ Defaults are suggestions only. They are never permission to skip confirmation.
101
+
102
+ - `model`: `gpt-image-2`
103
+ - `size`: `1:1`
104
+ - `resolution`: `1K`
105
+ - `n`: `1`
106
+ - `quality`: `medium`
107
+ - `background`: `auto`
108
+
109
+ For quick/cheap drafts, suggest `quality: low`.
110
+ For high quality/final artwork, suggest `quality: high`.
111
+
112
+ ## Workflow
113
+
114
+ 1. Parse the user's generation request into API parameters.
115
+ 1b. **Reference image analysis** — when the user provides a reference image (local file, URL, or Telegram image cache path) and asks to create a derivative visual asset, analyze the reference FIRST before proceeding to parameter confirmation:
116
+ - Extract dominant colors, color distribution, and palette
117
+ - Assess composition: symmetry, visual weight distribution (top/bottom/left/right density)
118
+ - Identify edge density patterns and shape distribution
119
+ - Summarize findings and discuss design direction with the user
120
+ - Only when aligned, continue to parameter confirmation in step 2
121
+ - **Fallback**: when `vision_analyze` is unavailable (missing vision provider), use the programmatic Pillow+NumPy approach in `references/programmatic-image-analysis.md` to extract color, composition, and shape data from the image file directly.
122
+ 2. Before creating the task, run the interaction rules above and collect missing choices.
123
+ 3. If reference images are provided as URLs, put up to 16 URLs in `image_urls`.
124
+ 4. If the user attaches or references a local image file, first make sure it is available as a public URL before using this external API. The API expects public `image_urls`, not local file paths.
125
+ 5. Normalize model-specific fields:
126
+ - For `gpt-image-2-beta`: set `n=1`; omit `quality` and `resolution`.
127
+ - For `gpt-image-2`: include `quality`; include `resolution` only when `size` is a ratio, not `auto`.
128
+ 6. Create the task with `POST /v1/images/generations`.
129
+ 7. Read the returned `id` as `task_id`. If no `id` exists, treat task creation as failed and report the raw non-secret error details.
130
+ 8. Poll `GET /v1/tasks/{task_id}` every 3-5 seconds.
131
+ - If polling hits a transient network/TLS timeout, do not assume the task failed. Retry the task-status query later using the same `task_id`.
132
+ - If a 5-minute script/tool timeout kills the polling loop, make one separate lightweight status query for the same `task_id` before reporting timeout; tasks may complete after the polling process died.
133
+ 9. Stop polling when:
134
+ - `status == completed`: return every `result_data[].url`.
135
+ - `status == failed`: report the error code/message and whether retry is reasonable.
136
+ - 5 minutes elapsed with follow-up status still not completed: report timeout and include the `task_id` so the user can ask to continue checking.
137
+ 10. In the final response, include:
138
+ - task id
139
+ - status
140
+ - generated image URLs
141
+ - selected model/options
142
+
143
+ ## Python helper pattern
144
+
145
+ Use `terminal` or `execute_code` to run an actual request. Example structure:
146
+
147
+ ```python
148
+ import os, time, requests
149
+
150
+ api_key = os.environ["AICODEWITH_API_KEY"]
151
+ base_url = "https://api.aicodewith.com"
152
+ headers = {"Authorization": f"Bearer {api_key}"}
153
+
154
+ body = {
155
+ "model": "gpt-image-2",
156
+ "prompt": prompt,
157
+ "size": size,
158
+ "resolution": resolution,
159
+ "n": n,
160
+ "quality": quality,
161
+ "background": "auto",
162
+ }
163
+ if image_urls:
164
+ body["image_urls"] = image_urls[:16]
165
+
166
+ resp = requests.post(
167
+ f"{base_url}/v1/images/generations",
168
+ headers={**headers, "Content-Type": "application/json"},
169
+ json=body,
170
+ timeout=60,
171
+ )
172
+ resp.raise_for_status()
173
+ task_id = resp.json()["id"]
174
+
175
+ start = time.time()
176
+ while True:
177
+ result = requests.get(f"{base_url}/v1/tasks/{task_id}", headers=headers, timeout=60).json()
178
+ if result.get("status") == "completed":
179
+ urls = [item.get("url") for item in result.get("result_data", []) if item.get("url")]
180
+ break
181
+ if result.get("status") == "failed":
182
+ raise RuntimeError(result.get("error"))
183
+ if time.time() - start > 300:
184
+ raise TimeoutError(task_id)
185
+ time.sleep(3)
186
+ ```
187
+
188
+ ## Error handling
189
+
190
+ Transient network errors can happen on both create and poll requests. If task creation fails with a transport/TLS error (for example `SSLEOFError`, timeout, reset, or temporary connection failure) and no task id was returned, retry the same create request once before reporting failure. If a task id was already returned, never create a duplicate task just because polling failed; continue querying the existing task id.
191
+
192
+ Common HTTP status meanings:
193
+
194
+ - `400`: parameter error, unsupported size, prompt too long, invalid image.
195
+ - `401`: invalid API key.
196
+ - `402`: insufficient balance.
197
+ - `404`: task not found or unauthorized.
198
+ - `503`: no available channel.
199
+
200
+ Known upstream error codes:
201
+
202
+ - `content_policy_violation`: content violates policy; ask user to revise prompt.
203
+ - `invalid_parameters`: check prompt length, image size, or parameter values.
204
+ - `image_processing_error`: reference image inaccessible/unsupported/corrupt.
205
+ - `image_dimension_mismatch`: reference image dimensions mismatch request.
206
+ - `request_cancelled`: task cancelled.
207
+ - `generation_failed_no_content`: model produced no image; optimize prompt and retry.
208
+ - `service_error`, `service_unavailable`: temporary service issue; retry later.
209
+ - `generation_timeout`: generation timed out; retry later.
210
+ - `resource_exhausted`: resources busy; retry is reasonable.
211
+ - `quota_exceeded`: too frequent; wait before retrying.
212
+ - `resource_not_found`: task expired/not found.
213
+
214
+ ## Pitfalls
215
+
216
+ - Never expose the raw API key.
217
+ - **Skipping reference analysis**: when the user provides a reference image and asks to create a derivative visual asset, do not jump straight to generation or parameter confirmation. Analyze the reference first (colors, composition, style), discuss findings with the user, then proceed. The user's expected workflow is: analyze → discuss → plan → confirm → generate. Skipping analysis wastes iterations and frustrates the user.
218
+ - Do not use local file paths in `image_urls`; they must be public URLs.
219
+ - Do not pass `quality` or `resolution` with `gpt-image-2-beta`.
220
+ - Do not set `n > 1` for `gpt-image-2-beta`.
221
+ - For `gpt-image-2`, only include `resolution` for ratio sizes like `1:1` or `16:9`; omit it for `auto`.
222
+ - If generating multiple images or high resolution, it can help to also mention count/resolution requirements in the prompt.
223
+ - For IP/reference-style illustration tasks, preserve concrete IP recognition anchors and reference style constraints explicitly; do not let the prompt drift into a generic product illustration. See `references/ip-style-controlled-generation.md`.
224
+ - When the user asks for an IP-only asset from a busy scene/reference image, explicitly strip every non-IP element in the prompt: no background, no ground, no game/world props, no UI, no text, no icons, and request an isolated centered transparent/alpha-ready PNG-style mascot. If the reference is only available as a local Telegram cache path and no public URL exists, use the visible image description/recognition anchors rather than passing the local path to `image_urls`. See `references/ip-only-transparent-assets.md`.
225
+ - For iterative campaign/banner variants, reuse the approved visual recipe: original IP recognition anchors + prior accepted 3D style + new business theme. Keep the style constant unless the user asks to change it; only swap the thematic objects/actions (e.g. server, recharge, analytics dashboard). See `references/session-notes-2026-06-17.md` for a concrete run pattern and transient API retry notes.
226
+ - For AI model/logo mascot banners, preserve official-logo recognition before adding cuteness. Do not substitute Codex with the OpenAI/GPT knot or a generic black terminal; use the Codex rounded-square app icon with purple-blue cloud/blob and `>_` terminal glyph. See `references/ai-model-logo-mascot-banners.md`.
227
+ - For iterative website/hero banner variants based on an approved mascot set, treat the existing IP/mascots as locked. Explicitly instruct: preserve the exact original mascot identities, silhouettes, and recognition anchors; do not redesign, replace, merge, or invent new mascots; only improve layout, background, glassmorphism UI, lighting, spacing, and composition. When the user says the design needs “more design sense/设计感”, improve hierarchy, UI framing, depth, gradients, and polish rather than swapping characters.
228
+ - For landing-page hero covers derived from busy game/fantasy reference art, first study the target template style and convert the reference into a web-usable brand hero background: reserve top navigation space, left-side low-detail text space, center/right focal mascot placement, and reduce clutter/protected-IP-like game props. See `references/landing-page-hero-banners.md`.
229
+ - For cute website/banner assets derived from a generated image, especially when the user asks to remove background/text/buttons while keeping mascot artwork, follow the cleaned-banner edit pattern in `references/token-leaderboard-banner-edits.md`.
230
+ - On Telegram and similar messaging platforms, markdown image syntax `![alt](url)` is delivered as a native image. Do not repeat the same markdown image in follow-up confirmations unless the user explicitly asks to resend/download it; otherwise it looks like multiple images were generated. For follow-ups, mention the task id/options and use a plain URL or say “上一条那张”.
231
+
232
+ ## Verification
233
+
234
+ A successful run is verified only when the task status is `completed` and at least one URL exists in `result_data[].url`.
@@ -0,0 +1,39 @@
1
+ # AI model logo mascot banners
2
+
3
+ Session learning from a 3:1 token leaderboard banner iteration.
4
+
5
+ ## Class of task
6
+
7
+ When generating cute/3D/jelly mascot banners for AI model leaderboards, users may expect strong official-logo recognition, not loose brand-color inspiration. If the user asks for model IPs like Claude, Codex, DeepSeek, Gemini, clarify whether they want:
8
+
9
+ - brand-inspired mascots, or
10
+ - official-logo-recognizable mascots made cuter.
11
+
12
+ If they say “一看就知道是 X” or “官方 logo 复刻然后可爱一点”, preserve the logo silhouette and core marks first; add cuteness second.
13
+
14
+ ## Codex logo anchors
15
+
16
+ Do **not** represent Codex with the OpenAI/GPT knot logo, and do not default to a generic black terminal/code block. The user corrected that this is visually wrong.
17
+
18
+ Use these anchors for Codex:
19
+
20
+ - app-style rounded-square icon
21
+ - white/light-gray icon base with large rounded corners and soft shadow
22
+ - inner cloud/blob terminal symbol
23
+ - smooth purple/violet-to-deep-blue gradient on the inner blob
24
+ - pale lavender/white terminal glyphs: `>_`
25
+ - developer-terminal feeling, but still app-icon clean
26
+
27
+ Good prompt fragment:
28
+
29
+ > Codex mascot must match an app-style rounded-square white/light-gray icon with large rounded corners and soft shadow; inside it a rounded cloud/blob terminal symbol with smooth purple/violet at the top to deep blue at the bottom; inside the cloud are pale lavender/white terminal prompt marks like `>_`. Make it cute and glossy 3D, but do not obscure the cloud shape or `>_`. It should look like the Codex logo reference, not the OpenAI knot, GPT logo, or a generic black terminal.
30
+
31
+ ## Iteration pattern
32
+
33
+ For incremental edits:
34
+
35
+ 1. Reuse the previous generated public image URL as `image_urls` when available.
36
+ 2. If the user provides a local Telegram/cache image as logo reference, do not pass the local path to AICodeWith; describe its visual anchors in the prompt unless a public URL is available.
37
+ 3. Preserve approved parts explicitly: “Keep Claude, DeepSeek, Gemini as close as possible; ONLY fix Codex.”
38
+ 4. State negative constraints explicitly: “not OpenAI knot, not GPT logo, not black terminal, no text, no buttons.”
39
+ 5. Keep the web banner constraints: `3:1`, no background/card/text/buttons if the user has already removed them, open space above for website overlay text.
@@ -0,0 +1,31 @@
1
+ # IP-only transparent asset generation
2
+
3
+ Use this reference when the user supplies a busy scene/image but asks for only the mascot/IP as a web asset.
4
+
5
+ ## Durable pattern
6
+
7
+ 1. Confirm whether the user wants the whole scene or only the IP. If they say “只要 IP / 不要背景”, treat every environmental element as negative prompt material.
8
+ 2. Preserve concrete recognition anchors from the IP reference:
9
+ - species/character type
10
+ - face/body colors
11
+ - ear/limb colors
12
+ - expression details
13
+ - body proportions
14
+ - material/style, e.g. toy-like 3D, chibi, polished platform-game look
15
+ 3. Convert the business intent into pose/action only, not into background clutter. Example: for a workspace empty state, use “waving hello” and “subtly pointing down-right toward a Create Workspace button” while keeping the image itself free of UI/text.
16
+ 4. Explicitly strip all non-IP elements from the source scene.
17
+ 5. Request web-asset suitability: isolated, centered, clean edges, transparent/alpha-ready PNG-style output.
18
+
19
+ ## Prompt skeleton
20
+
21
+ ```text
22
+ Create a standalone transparent-background PNG-style 3D mascot character only, based on this IP description: [recognition anchors].
23
+ Pose: [business intent as gesture/action].
24
+ No background, no ground, no grass, no blocks, no stars, no mushrooms, no coins, no UI, no text, no icons, no scene props, no environment. Isolated character centered with clean edges, web empty-state illustration asset, friendly, minimal, high quality, transparent or plain alpha-ready background.
25
+ ```
26
+
27
+ ## Pitfalls
28
+
29
+ - Do not pass local Telegram cache paths to external image APIs as `image_urls`; the AICodeWith API expects public URLs. If no public URL exists, use the image description/recognition anchors in the prompt.
30
+ - Do not let the model recreate the busy reference scene when the user asks for “IP only”. Name every unwanted prop/category explicitly.
31
+ - Avoid adding readable UI labels inside the PNG even if the asset points toward a button; button text belongs in the web UI, not the mascot image.
@@ -0,0 +1,48 @@
1
+ # IP/style-controlled image generation notes
2
+
3
+ Use when the user provides a character/IP reference and says the generated image must follow that style.
4
+
5
+ ## Lesson
6
+
7
+ If the user asks for an illustration based on an IP/reference image, do not only describe the task category (e.g. “AI Agent illustration”). The prompt must explicitly preserve the IP’s recognizable visual anchors and the reference image’s style constraints.
8
+
9
+ ## Prompt structure
10
+
11
+ 1. State the deliverable and usage context.
12
+ 2. Add a hard requirement: “core IP must be visually recognizable.”
13
+ 3. List concrete IP anchors from the reference image:
14
+ - body/head orientation
15
+ - color blocks
16
+ - ears/eyes/nose/mouth shape
17
+ - distinctive patches/accessories
18
+ - expression/personality
19
+ 4. List style constraints from the reference image:
20
+ - palette
21
+ - background
22
+ - flat/vector/3D/photographic style
23
+ - line weight, cards, nodes, icons, decoration
24
+ - forbidden style drift (e.g. no blue-purple tech glow, no 3D)
25
+ 5. Then add the new product/theme content.
26
+ 6. For multiple images, define different compositions while keeping the same IP and visual system.
27
+
28
+ ## Example skeleton
29
+
30
+ ```text
31
+ Generate N website illustrations for [product/context].
32
+
33
+ Core IP must be very recognizable: [specific character orientation, colors, ear/face/body markings, expression, silhouette]. Do not transform the IP into a generic mascot, robot, or different species. Preserve [top 3 most recognizable anchors].
34
+
35
+ Visual style must strictly follow the reference: [palette], [background], [flat/vector/etc.], [shape language], [UI motif]. Avoid [style drift].
36
+
37
+ Theme/content: [agent/workflow/product concept].
38
+
39
+ Composition variants:
40
+ 1. ...
41
+ 2. ...
42
+
43
+ No readable text, no logos, no watermark.
44
+ ```
45
+
46
+ ## Pitfall
47
+
48
+ Do not rely on “based on this IP” alone. If the generated image loses recognizability, the prompt was underspecified even if the product theme was correct.
@@ -0,0 +1,47 @@
1
+ # Landing Page Hero Banner Adaptation Notes
2
+
3
+ Use when a user provides a busy fantasy/game reference image and wants a website hero/landing-page cover, especially for a premium ecommerce template such as v0 Evasion.
4
+
5
+ ## Design sequence
6
+
7
+ 1. **Do not generate immediately.** First analyze the reference image and the target template/page style.
8
+ 2. For premium ecommerce templates, convert the reference into a **brand hero background**, not a game screenshot or poster.
9
+ 3. Preserve the reference's emotional anchors while reducing clutter:
10
+ - keep: cute mascot, fantasy/adventure mood, floating islands, waterfalls, atmospheric depth
11
+ - reduce/replace: classic game props that resemble protected IP, dense collectibles, obvious question blocks, excessive coins
12
+ 4. Reserve composition zones for web use:
13
+ - left 35–40%: darker, low-detail negative space for title/navigation
14
+ - top band: clean sky/gradient for nav overlay
15
+ - center-right: main mascot/focal island
16
+ - right side: brighter fantasy world detail
17
+ - bottom: calm water/grass transition for crop tolerance
18
+ 5. Discuss style before generation. A useful balanced target is: **premium brand feel 60% + game adventure feel 40%**.
19
+ 6. Only after style is agreed, confirm the mandatory generation parameters.
20
+
21
+ ## Prompt recipe
22
+
23
+ Core wording:
24
+
25
+ ```text
26
+ A cinematic 16:9 hero banner for a premium landing page, a whimsical fantasy adventure world in polished stylized 3D illustration. The left 40% of the image is a calm dark blue misty valley with distant cliffs, soft fog, subtle water reflections and low-detail negative space for website text and navigation. The center-right features a cute dog adventurer mascot standing confidently on a small floating grassy island with flowers, vines and soft glowing particles. The right side opens into a bright colorful fairytale world with floating islands, waterfalls, clouds, lush greenery, delicate flowers, a charming mushroom house and a distant ivy-covered stone tower.
27
+
28
+ Premium website hero composition, clean top area for navigation overlay, strong depth, atmospheric perspective, soft cinematic lighting, vibrant but refined color palette, high-end 3D game promotional art, cute but not childish, adventurous and joyful mood.
29
+
30
+ No text, no logo, no UI, no buttons, no captions, no watermark, no classic question blocks, no Mario-style objects, no pixel art, no flat vector, no anime.
31
+ ```
32
+
33
+ ## Recommended option set
34
+
35
+ For a first high-quality hero master:
36
+
37
+ - model: `gpt-image-2`
38
+ - size: `16:9` when 21:9 is uncertain or not desired
39
+ - n: `1`
40
+ - quality: `high`
41
+ - resolution: `2K`
42
+
43
+ If the final page needs an ultra-wide crop, generate 16:9 as a flexible master first, then crop/extend after visual approval.
44
+
45
+ ## Implementation note
46
+
47
+ If the runtime does not have `requests`, do not stop. Use Python stdlib `urllib.request` to call the AICodeWith API and poll the task. The lesson is to have a dependency-free fallback, not to assume the image API is unavailable.
@@ -0,0 +1,126 @@
1
+ # Programmatic Image Analysis (Pillow + NumPy fallback)
2
+
3
+ When `vision_analyze` fails (missing vision provider, model doesn't support vision), use this
4
+ approach to extract actionable visual data from an image file without seeing it.
5
+
6
+ ## Dependencies
7
+
8
+ ```bash
9
+ uv pip install Pillow numpy
10
+ ```
11
+
12
+ If already in venv, runs with `/opt/hermes/.venv/bin/python`.
13
+
14
+ ## Analysis recipe
15
+
16
+ Run these analyses in order — each builds on the previous:
17
+
18
+ ### 1. Basic info + dominant colors
19
+
20
+ ```python
21
+ from PIL import Image
22
+ import collections
23
+
24
+ img = Image.open('/path/to/image.jpg')
25
+ print(f'Format: {img.format}')
26
+ print(f'Size: {img.size[0]}x{img.size[1]}')
27
+ print(f'Mode: {img.mode}')
28
+
29
+ img_small = img.resize((100, 100))
30
+ pixels = list(img_small.getdata())
31
+ color_counts = collections.Counter(pixels)
32
+
33
+ for color, count in color_counts.most_common(20):
34
+ pct = count / len(pixels) * 100
35
+ if pct > 0.5:
36
+ r, g, b = color[0], color[1], color[2] if len(color) >= 3 else (color[0],)*3
37
+ print(f' #{r:02x}{g:02x}{b:02x} RGB({r},{g},{b}) = {pct:.1f}%')
38
+ ```
39
+
40
+ ### 2. Composition: content bounding box + quadrant density
41
+
42
+ ```python
43
+ import numpy as np
44
+ arr = np.array(img)
45
+ mask = ~((arr[:,:,0] > 240) & (arr[:,:,1] > 240) & (arr[:,:,2] > 240))
46
+ rows = np.any(mask, axis=1)
47
+ cols = np.any(mask, axis=0)
48
+
49
+ if rows.any():
50
+ rmin, rmax = np.where(rows)[0][[0, -1]]
51
+ cmin, cmax = np.where(cols)[0][[0, -1]]
52
+ print(f'Content region: ({cmin},{rmin}) to ({cmax},{rmax})')
53
+
54
+ crop = arr[rmin:rmax, cmin:cmax]
55
+ h, w = crop.shape[0], crop.shape[1]
56
+ for qname, q in [('top-left', crop[:h//2,:w//2]),
57
+ ('top-right', crop[:h//2,w//2:]),
58
+ ('bot-left', crop[h//2:,:w//2]),
59
+ ('bot-right', crop[h//2:,w//2:])]:
60
+ non_white = ((q[:,:,0] < 240) | (q[:,:,1] < 240) | (q[:,:,2] < 240)).mean()
61
+ print(f' {qname}: {non_white*100:.0f}% non-white')
62
+
63
+ # Row-by-row density profile
64
+ for r in range(rmin, rmax+1, max(1, (rmax-rmin)//15)):
65
+ content_pct = mask[r, cmin:cmax].mean()
66
+ bar = '#' * int(content_pct * 50)
67
+ print(f' row {r:4d}: {bar} ({content_pct*100:.0f}%)')
68
+ ```
69
+
70
+ ### 3. Edge density (shape/contour distribution)
71
+
72
+ ```python
73
+ from PIL import ImageFilter
74
+ edges = np.array(img.filter(ImageFilter.FIND_EDGES))
75
+ edge_mask = (edges[:,:,0] > 30) | (edges[:,:,1] > 30) | (edges[:,:,2] > 30)
76
+
77
+ h, w = arr.shape[:2]
78
+ dh, dw = h//8, w//8
79
+ print('Edge density grid (8x8):')
80
+ for row in range(8):
81
+ line = ''
82
+ for col in range(8):
83
+ density = edge_mask[row*dh:(row+1)*dh, col*dw:(col+1)*dw].mean()
84
+ if density > 0.20: line += '██'
85
+ elif density > 0.10: line += '▓▓'
86
+ elif density > 0.05: line += '▒▒'
87
+ elif density > 0.01: line += '░░'
88
+ else: line += ' '
89
+ print(f' {line}')
90
+ ```
91
+
92
+ ### 4. Symmetry check
93
+
94
+ ```python
95
+ mid = w // 2
96
+ left = arr[:, :mid]
97
+ right = arr[:, mid:][:, ::-1] # flipped
98
+ diff = np.abs(left.astype(float) - right.astype(float)).mean()
99
+ print(f'Left-right avg diff: {diff:.0f} (0=perfect symmetry)')
100
+ ```
101
+
102
+ ### 5. Color banding (horizontal slices)
103
+
104
+ ```python
105
+ for r in range(50, arr.shape[0], 50):
106
+ strip = arr[r:r+10, 50:-50]
107
+ avg = strip.mean(axis=(0,1))
108
+ rc, gc, bc = int(avg[0]), int(avg[1]), int(avg[2])
109
+ label = 'DARK' if rc<100 and gc<100 and bc<100 else \
110
+ 'WARM' if rc>150 and gc>100 and bc<170 else \
111
+ 'LITE' if rc>200 and gc>200 and bc>200 else 'GRAY'
112
+ print(f' row {r:4d}: #{rc:02x}{gc:02x}{bc:02x} [{label}]')
113
+ ```
114
+
115
+ ## What to infer from these outputs
116
+
117
+ - **Color palette** → the brand's color language; guides hero background palette
118
+ - **Composition quadrants** → where the visual weight sits; asymmetrical logos need backgrounds that balance them
119
+ - **Edge density grid** → locates complex/detailed regions vs. flat areas
120
+ - **Symmetry** → low diff = centered/symmetric logo; high diff = dynamic/off-center
121
+ - **Color banding** → reveals gradients and transitions across the image
122
+
123
+ ## When to use this
124
+
125
+ Only when `vision_analyze` fails with a provider error. If vision works, prefer it —
126
+ it gives richer results including text recognition and semantic understanding.
@@ -0,0 +1,7 @@
1
+ # Session notes: AICodeWith image generation
2
+
3
+ - During task creation, a transient TLS/SSL transport error can occur before any task id is returned (`SSLEOFError: [SSL: UNEXPECTED_EOF_WHILE_READING]`).
4
+ - If that happens on the *create* request, retry the same create request once before declaring failure.
5
+ - If a task id has already been returned, never create a duplicate task just because polling hits a transport error; keep polling the same task id.
6
+ - Polling can also see intermittent SSL EOFs; treat them as transient and continue polling.
7
+ - This session successfully generated multiple banners with `gpt-image-2` using 3:1 / 2K / high and one square variant with 1:1 / 1K / medium.
@@ -0,0 +1,30 @@
1
+ # Token leaderboard banner edit pattern
2
+
3
+ Use this reference for iterative website/banner image generation where the user starts from a cute promotional graphic and asks for a cleaned banner asset.
4
+
5
+ ## Durable pattern
6
+
7
+ 1. Confirm required AICodeWith parameters before generation, even for edits:
8
+ - model, size/aspect ratio, n, quality, resolution.
9
+ 2. For website hero banners, ask/propose a wide ratio such as `3:1` when the user wants a horizontal banner.
10
+ 3. If the prior generated image already has a public URL, reuse it in `image_urls` for the next edit. Do not attempt to pass local Telegram cache paths to the API.
11
+ 4. When the user says to remove background/text/buttons, explicitly enumerate all removals in the prompt:
12
+ - remove beige/yellow/background card if requested
13
+ - remove all text, typography, headline, subtitle, badges with words, brand text
14
+ - remove CTA buttons and UI controls
15
+ - preserve only mascot/illustration/ranking decorative elements
16
+ 5. Ask the model to leave empty space for the site to overlay its own title later if it is a banner asset.
17
+
18
+ ## Prompt recipe
19
+
20
+ ```text
21
+ Edit the provided 3:1 website banner image.
22
+ Remove the pale beige/yellow background entirely. Remove ALL text, typography, labels, badges with words, brand text, headline, subtitle, and remove the CTA button.
23
+ Keep and improve only the cute glossy token/blob mascot illustration elements: colorful jelly-like blob characters, token coins, small flames, trophy, upward arrows, rank badges like #1 #2 #3 only if they are decorative, and cheerful leaderboard/AI usage energy.
24
+ Create a clean transparent-background or pure white-background banner asset suitable for placing over a website hero section. No words, no sentences, no UI button. Preserve the playful glossy vector/soft-3D style, saturated colors, polished highlights, cute expressions, wide horizontal composition, bottom-heavy mascot cluster with empty space above for the website to overlay its own title later.
25
+ Important: output should be a 3:1 horizontal banner illustration, no watermark, no photorealism, no visible text.
26
+ ```
27
+
28
+ ## Final response
29
+
30
+ Return the task id, completion status, selected options, and one markdown image URL only. Avoid resending prior images unless requested.