mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-07-25 06:54:43 +00:00
[ai] Use vectosolve service for svg gen.
This commit is contained in:
+173
-197
@@ -1,44 +1,77 @@
|
||||
---
|
||||
description: Generate an SVG icon from a text description with iterative visual review
|
||||
allowed-tools: Read, Write, Edit, Glob, Grep, Bash, Agent, Task, AskUserQuestion, TodoWrite
|
||||
description: Generate an SVG icon from a design mockup using vectosolve vectorization
|
||||
allowed-tools: Read, Write, Edit, Glob, Grep, Bash, Agent, AskUserQuestion, TodoWrite, mcp__vectosolve__vectorize
|
||||
---
|
||||
|
||||
# Icon - SVG Icon Generation Workflow
|
||||
# Icon - SVG Icon Generation from Design Mockup
|
||||
|
||||
You generate production-quality SVG icons for Telegram Desktop through an iterative generate/review loop with visual feedback.
|
||||
You generate production-quality SVG icons for Telegram Desktop by vectorizing design mockup screenshots using the vectosolve MCP service, then post-processing the result to match the Telegram icon format.
|
||||
|
||||
**Arguments:** `$ARGUMENTS` = "$ARGUMENTS"
|
||||
|
||||
If `$ARGUMENTS` is empty, ask the user to describe the icon they want.
|
||||
If `$ARGUMENTS` is empty, ask the user to describe the icon they want and paste a cropped screenshot of it.
|
||||
|
||||
## Overview
|
||||
|
||||
The workflow generates SVG menu icons (24x24, white monocolor outlines on transparent background) matching the Telegram Desktop icon set style. Each iteration is rendered to a PNG for visual review by a fresh subagent that decides whether to approve or improve.
|
||||
The workflow takes a cropped screenshot of an icon from a design mockup (grabbed from the Windows clipboard), vectorizes it via the vectosolve MCP, then post-processes the SVG (recolor to white-on-transparent, restructure to minimal format, set 24x24 output size).
|
||||
|
||||
Working directory: `.ai/icon_{name}/` with iterations `a.svg`, `b.svg`, ..., their renders `render_a.png`, `render_b.png`, ..., review notes `b-review.md`, `c-review.md`, ..., and `context.md` tracking the request.
|
||||
Working directory: `.ai/icon_{name}/` with iterations labeled by letter (`a/`, `b/`, ...), each containing `source.png`. Output SVGs are in the icon root: `a.svg`, `b.svg`, etc.
|
||||
|
||||
Follow-ups are supported: `/icon {icon_name} make the lines thicker` continues from where the previous run left off.
|
||||
Follow-ups are supported: `/icon {icon_name} <description>` continues from where the previous run left off.
|
||||
|
||||
## Phase 0: Setup
|
||||
|
||||
**Record the current time** (using `Get-Date` in PowerShell or equivalent) as `$START_TIME`.
|
||||
|
||||
### Step 0a: Follow-up detection (MANDATORY — do this FIRST)
|
||||
### Step 0a: Clipboard grab (MUST be the VERY FIRST action)
|
||||
|
||||
If there is an image attached to the user's message:
|
||||
|
||||
1. Generate a random 8-character hex string for `HASH` (use `openssl rand -hex 4` or similar).
|
||||
2. **IMMEDIATELY** — before any other processing — run this Bash command to save the clipboard image:
|
||||
```bash
|
||||
HASH=$(openssl rand -hex 4) && powershell -ExecutionPolicy Bypass -File .claude/grab_clipboard.ps1 ".ai/icon_${HASH}.png"
|
||||
```
|
||||
The script `.claude/grab_clipboard.ps1` grabs the current clipboard image and saves it to the specified path.
|
||||
|
||||
3. If the command fails (exit 1 / no image on clipboard):
|
||||
- Tell the user: **"Clipboard doesn't contain an image. Please copy the icon area first (Win+Shift+S), then retry."**
|
||||
- **STOP IMMEDIATELY. Do NOT continue.** You cannot use the image pasted in the conversation — it exists only as pixels in the chat, not as a file you can send to vectosolve. The clipboard grab is the ONLY way to get the image to disk. Do not attempt any workaround.
|
||||
|
||||
4. Read back the saved `.ai/icon_HASH.png` using the Read tool.
|
||||
5. Compare it visually with the image pasted in the conversation. They should depict the same thing.
|
||||
- If they look **completely different**: delete `.ai/icon_HASH.png` and fail:
|
||||
> "The clipboard image doesn't match what you pasted. Please re-copy and retry."
|
||||
- If they look the same (or close enough): proceed. Store the temp path.
|
||||
|
||||
If NO image is attached to the message, skip this step entirely.
|
||||
|
||||
### Step 0b: Fail-fast — verify vectosolve MCP
|
||||
|
||||
Check that the `mcp__vectosolve__vectorize` tool is available by looking at your available tools list. If it is NOT available, fail immediately with:
|
||||
|
||||
> vectosolve MCP is not configured. Set it up with:
|
||||
> ```
|
||||
> claude mcp add vectosolve --scope user -e VECTOSOLVE_API_KEY=vs_xxx -- npx @vectosolve/mcp
|
||||
> ```
|
||||
> Then restart Claude Code.
|
||||
|
||||
### Step 0c: Follow-up detection
|
||||
|
||||
Extract the first word/token from `$ARGUMENTS` (everything before the first space or newline). Call it `FIRST_TOKEN`.
|
||||
|
||||
Run these TWO commands using the Bash tool, IN PARALLEL:
|
||||
Run these TWO commands using the Bash tool, **IN PARALLEL**:
|
||||
1. `ls .ai/` — to see all existing icon project names
|
||||
2. `ls .ai/icon_{FIRST_TOKEN}/context.md` — to check if this specific icon project exists
|
||||
|
||||
**Evaluate the results:**
|
||||
- If command 2 **succeeds** (context.md exists): this is a **follow-up**. The icon name is `FIRST_TOKEN`. The follow-up description is everything in `$ARGUMENTS` AFTER `FIRST_TOKEN` (strip leading whitespace).
|
||||
- If command 2 **succeeds** (context.md exists): this is a **follow-up**. The icon name is `FIRST_TOKEN`. The follow-up description is everything in `$ARGUMENTS` after `FIRST_TOKEN`.
|
||||
- If command 2 **fails** (not found): this is a **new icon**. The full `$ARGUMENTS` is the icon description.
|
||||
|
||||
### Step 0b: New icon setup
|
||||
### Step 0d: New icon setup
|
||||
|
||||
1. Parse `$ARGUMENTS` to determine:
|
||||
- **Icon description**: what the icon should depict (the full text prompt, possibly with image attachments)
|
||||
- **Icon description**: what the icon should depict
|
||||
- **Icon type**: default is `menu` (24x24 menu/button icon). User may specify otherwise.
|
||||
- **Target subfolder**: `menu/` by default, or another subfolder if specified.
|
||||
|
||||
@@ -48,7 +81,7 @@ Run these TWO commands using the Bash tool, IN PARALLEL:
|
||||
- Must NOT conflict with existing icons
|
||||
- Must NOT collide with existing `.ai/icon_{name}/` directories
|
||||
|
||||
3. Create `.ai/icon_{name}/`.
|
||||
3. Create `.ai/icon_{name}/` and `.ai/icon_{name}/a/`.
|
||||
|
||||
4. Write `.ai/icon_{name}/context.md` with:
|
||||
```
|
||||
@@ -65,23 +98,32 @@ Run these TWO commands using the Bash tool, IN PARALLEL:
|
||||
|
||||
5. Set `LETTER` to `a`.
|
||||
|
||||
### Step 0c: Follow-up setup
|
||||
### Step 0e: Follow-up setup
|
||||
|
||||
1. Read `.ai/icon_{name}/context.md` to get the icon type, subfolder, and full history.
|
||||
|
||||
2. Find the latest existing SVG in `.ai/icon_{name}/` (highest letter).
|
||||
|
||||
3. Set `LETTER` to the next letter after the latest SVG.
|
||||
|
||||
4. Update `.ai/icon_{name}/context.md` — append the follow-up description to the `## Follow-ups` section:
|
||||
2. Find the latest existing letter folder in `.ai/icon_{name}/` (highest letter).
|
||||
3. Set `LETTER` to the next letter after the latest.
|
||||
4. Create `.ai/icon_{name}/{LETTER}/`.
|
||||
5. Update `.ai/icon_{name}/context.md` — append the follow-up description to the `## Follow-ups` section:
|
||||
```
|
||||
### Follow-up (starting at letter {LETTER})
|
||||
{follow-up description}
|
||||
```
|
||||
|
||||
### Step 0d: Verify renderer
|
||||
### Step 0f: Place source image
|
||||
|
||||
**Locate the render tool**. The `codegen_style` binary has a `--render-svg` mode that renders SVGs to PNG using the same Qt SVG renderer used at runtime. Find it:
|
||||
If a clipboard image was grabbed in Step 0a:
|
||||
1. Copy (or move) `.ai/icon_HASH.png` → `.ai/icon_{name}/source.png` (overwrite if exists — this is always the latest source).
|
||||
2. Copy it to `.ai/icon_{name}/{LETTER}/source.png` (archive per-iteration source).
|
||||
3. Delete the temp `.ai/icon_HASH.png` if it was copied (not moved).
|
||||
|
||||
If NO image was grabbed:
|
||||
- **New icon with no image**: Ask the user to provide a screenshot. STOP.
|
||||
- **Follow-up with no image**: The existing `source.png` in the icon root carries forward. Copy it to `.ai/icon_{name}/{LETTER}/source.png`. If no source.png exists at all, ask the user for an image.
|
||||
|
||||
### Step 0g: Verify renderer
|
||||
|
||||
Locate the render tool (`codegen_style` with `--render-svg` mode):
|
||||
|
||||
```bash
|
||||
ls out/Telegram/codegen/codegen/style/Debug/codegen_style.exe
|
||||
@@ -89,237 +131,171 @@ ls out/Telegram/codegen/codegen/style/Debug/codegen_style.exe
|
||||
|
||||
If missing, build it: `cmake --build out --config Debug --target codegen_style`
|
||||
|
||||
**Test the renderer** on a known good SVG:
|
||||
|
||||
Test on a known good SVG:
|
||||
```bash
|
||||
out/Telegram/codegen/codegen/style/Debug/codegen_style.exe --render-svg Telegram/Resources/icons/menu/tag_add.svg .ai/icon_{name}/test_render.png 512
|
||||
```
|
||||
|
||||
If it works, delete the test render and set `RENDER_AVAILABLE = true`. If it fails, set `RENDER_AVAILABLE = false`.
|
||||
If works → delete test render, set `RENDER_AVAILABLE = true`. If fails → `RENDER_AVAILABLE = false`.
|
||||
|
||||
## Phase 1: Iterative Generation Loop
|
||||
## Phase 1: Vectorize & Post-process
|
||||
|
||||
Each run (new or follow-up) allows up to **8 iterations**. Track the starting letter as `START_LETTER`.
|
||||
### Step 1a: Call vectosolve
|
||||
|
||||
Set `MAX_ITERATIONS` to 8. If `RENDER_AVAILABLE` is false, reduce to 3.
|
||||
Use the `mcp__vectosolve__vectorize` tool with `file_path` set to the **absolute path** of `.ai/icon_{name}/{LETTER}/source.png`.
|
||||
|
||||
### Loop body
|
||||
**If this fails, STOP IMMEDIATELY.** Do NOT try to generate the SVG manually or by any other means. Report the error to the user and let them fix the issue (bad API key, no credits, network error, etc.).
|
||||
|
||||
Repeat until APPROVED or `LETTER` >= `START_LETTER + MAX_ITERATIONS`:
|
||||
Save the returned SVG content to `.ai/icon_{name}/{LETTER}/raw_vectosolve.svg`.
|
||||
|
||||
**Step 1 — Render previous iteration** (skip when LETTER is `a` or no SVGs exist yet)
|
||||
The MCP tool calls the vectosolve API ($0.20/call). The API key is stored in `~/.claude.json` MCP config (never in the repository).
|
||||
|
||||
If there is at least one SVG in the folder, render the latest one:
|
||||
### Step 1b: Post-process the SVG
|
||||
|
||||
```bash
|
||||
out/Telegram/codegen/codegen/style/Debug/codegen_style.exe --render-svg ".ai/icon_{name}/{prev_letter}.svg" ".ai/icon_{name}/render_{prev_letter}.png" 512
|
||||
```
|
||||
The vectosolve SVG will have colors from the mockup, arbitrary dimensions, and possibly a non-square aspect ratio from a non-square screenshot crop. Post-processing fixes this by adjusting the **viewBox** — leave path coordinates untouched.
|
||||
|
||||
If rendering fails, set `RENDER_AVAILABLE = false` and proceed.
|
||||
**Do NOT transform path coordinates.** Vectosolve's paths are correct — the only thing wrong is the framing. All geometry adjustments are done by manipulating the `viewBox` and the `width`/`height` attributes.
|
||||
|
||||
**Step 2 — Spawn subagent**
|
||||
#### Sub-step 1: Read the request and determine parameters
|
||||
|
||||
Spawn an agent (Agent tool, subagent_type=`general-purpose`) with the prompt built from the **Subagent Prompt Template** below. Pass to it:
|
||||
Before touching the SVG, determine these from the user's request and context.md:
|
||||
|
||||
- The full context from `.ai/icon_{name}/context.md` (original request + any follow-ups)
|
||||
- The icon name and current letter
|
||||
- Whether this is the first generation (no SVGs exist) or a review iteration
|
||||
- Paths to ALL previous `.svg` iterations in `.ai/icon_{name}/`
|
||||
- Paths to ALL previous `*-review.md` files
|
||||
- Path to the rendered PNG of the latest iteration (if `RENDER_AVAILABLE` and SVGs exist)
|
||||
1. **Output size** (`OUT_W × OUT_H`): default is `24px × 24px` for menu icons. The user may request different dimensions (e.g., 36×36, 48×48, or non-square). Always check the request.
|
||||
2. **Content padding**: default is ~2px equivalent on each side at the output scale (so content fills roughly (OUT_W-4) × (OUT_H-4)). The user may request different padding or edge-to-edge.
|
||||
3. **Centering**: default is centered both horizontally and vertically. The user may request specific alignment (e.g., "align to bottom").
|
||||
|
||||
**Step 3 — Parse result**
|
||||
#### Sub-step 2: Parse the raw SVG
|
||||
|
||||
The subagent's response will end with either `GENERATED` or `APPROVED` on the last line.
|
||||
1. Extract the `viewBox`: `viewBox="VB_X VB_Y VB_W VB_H"` (typically `0 0 W H`).
|
||||
2. Identify ALL paths. Classify each:
|
||||
- **Background**: a rect or path spanning the full viewBox (first path that's a simple rectangle matching the viewBox bounds). **Remove it entirely.**
|
||||
- **Content**: the actual icon shapes. **Keep these, paths unchanged.**
|
||||
3. If paths have `transform="translate(TX,TY)"` attributes, that's fine — keep them as-is. The viewBox framing will work regardless.
|
||||
|
||||
- **GENERATED**: the subagent wrote `.ai/icon_{name}/{letter}.svg`
|
||||
- Verify the file exists and contains `<svg`
|
||||
- Advance LETTER to next in sequence
|
||||
- If iterations used >= MAX_ITERATIONS → break
|
||||
- Otherwise → continue loop
|
||||
#### Sub-step 3: Compute the content bounding box
|
||||
|
||||
- **APPROVED**: the subagent found the latest render satisfactory
|
||||
- The final SVG is the **previously rendered** one (`{prev_letter}.svg`)
|
||||
- Break out of loop
|
||||
Estimate the bounding box of the content paths (after removing the background). You can either:
|
||||
- Eyeball it from the path coordinates (look at first/last M commands and extremes of curves)
|
||||
- Or for precision, write a quick script to parse the paths and find min/max X/Y
|
||||
|
||||
- **Neither / unclear**: if the new SVG file exists, treat as GENERATED. Otherwise ask the user.
|
||||
Call the result: `CX_MIN, CY_MIN, CX_MAX, CY_MAX`. Content dimensions: `CW = CX_MAX - CX_MIN`, `CH = CY_MAX - CY_MIN`.
|
||||
|
||||
## Phase 2: Output
|
||||
#### Sub-step 4: Compute the new viewBox
|
||||
|
||||
1. Determine the final SVG file:
|
||||
- If APPROVED: the SVG from the letter before the current one (the one that was rendered and approved)
|
||||
- If loop ended by max iterations or last GENERATED: the latest written SVG
|
||||
The viewBox determines what part of the SVG coordinate space maps to the output rectangle. By expanding the viewBox beyond the content bounds, we add padding. By making the viewBox aspect ratio match the output aspect ratio, we prevent stretching.
|
||||
|
||||
2. Read the `Target:` line from `.ai/icon_{name}/context.md` to get the output path.
|
||||
1. **Output aspect ratio**: `OUT_AR = OUT_W / OUT_H` (for 24×24 this is 1.0).
|
||||
2. **Padding in SVG coordinates**: we want ~2px padding at output scale. The scale factor is `OUT_W / VB_CONTENT_W` approximately, so padding in SVG coords = `2 * (CW / (OUT_W - 4))` (or similar — the exact formula depends on which dimension is dominant). Simpler approach: aim for content to occupy ~83% of the viewBox (≈ 20/24), so:
|
||||
- `PADDED_W = CW / 0.83`
|
||||
- `PADDED_H = CH / 0.83`
|
||||
3. **Match output aspect ratio**: the viewBox aspect ratio must equal `OUT_AR` to avoid stretching.
|
||||
- If `PADDED_W / PADDED_H > OUT_AR`: width is dominant → `VB_W = PADDED_W`, `VB_H = VB_W / OUT_AR`
|
||||
- If `PADDED_W / PADDED_H < OUT_AR`: height is dominant → `VB_H = PADDED_H`, `VB_W = VB_H * OUT_AR`
|
||||
- If equal: `VB_W = PADDED_W`, `VB_H = PADDED_H`
|
||||
4. **Center the content** in the new viewBox:
|
||||
- `VB_X = CX_MIN - (VB_W - CW) / 2`
|
||||
- `VB_Y = CY_MIN - (VB_H - CH) / 2`
|
||||
- (Adjust if the user requested non-centered alignment)
|
||||
|
||||
3. Copy the final SVG to that target path (e.g., `Telegram/Resources/icons/menu/{icon_name}.svg`).
|
||||
The new viewBox is: `viewBox="VB_X VB_Y VB_W VB_H"`.
|
||||
|
||||
4. Update `.ai/icon_{name}/context.md` — append to the end:
|
||||
```
|
||||
## Latest Output
|
||||
Letter: {final_letter}
|
||||
Written to: {target_path}
|
||||
```
|
||||
#### Sub-step 5: Recolor to white-on-transparent
|
||||
|
||||
5. Report to the user:
|
||||
- Final icon file path
|
||||
- Number of iterations taken (in this run)
|
||||
- Suggest opening the SVG in a browser to verify visually
|
||||
- Mention the working directory `.ai/icon_{name}/` has all iterations and renders
|
||||
- Calculate and display elapsed time since `$START_TIME` (format `Xm Ys`)
|
||||
- Remind the user they can follow up: `/icon {icon_name} <description of what to change>`
|
||||
- Replace ALL `fill` color values (anything that isn't `none`) with `#FFFFFF`.
|
||||
- Remove ALL `stroke` and `stroke-width` attributes entirely.
|
||||
- Remove `opacity` attributes if present.
|
||||
|
||||
---
|
||||
#### Sub-step 6: Determine path composition
|
||||
|
||||
## Subagent Prompt Template
|
||||
Look at the icon's visual structure and decide how paths should combine:
|
||||
- **Outlined shape** (e.g., circle outline with something inside): combine outer + inner cutout into one `<path>` with `fill-rule="evenodd"`.
|
||||
- **Separate distinct parts** (e.g., magnifying glass + checkmark): keep as separate `<path>` elements.
|
||||
- **Filled shape with cutout** (e.g., filled circle with checkmark punched out): combine into one path with `fill-rule="evenodd"`.
|
||||
|
||||
Build the subagent prompt by filling in `{placeholders}`. The prompt structure differs slightly for first generation vs review iterations.
|
||||
|
||||
~~~
|
||||
You are an expert SVG icon designer for Telegram Desktop.
|
||||
|
||||
{IF no SVGs exist yet (first generation)}
|
||||
## Task
|
||||
Generate a NEW SVG icon based on the description below. There are no previous attempts.
|
||||
|
||||
{IF SVGs exist (review/improve)}
|
||||
## Task
|
||||
Review the latest rendered icon and decide whether it is acceptable or needs improvement.
|
||||
|
||||
**Default to APPROVED** unless there is a clear, specific problem. The icon does NOT need to be perfect — it needs to be recognizable, have correct visual weight, and look like it belongs in the Telegram icon set. Minor imperfections are acceptable. If you've seen previous review notes that show the same issues being raised repeatedly, that means the issues likely can't be fixed through iteration — APPROVE and move on.
|
||||
{END IF}
|
||||
|
||||
## Icon Description
|
||||
|
||||
{Paste the full contents of .ai/icon_{name}/context.md here — this includes the original request and any follow-up instructions.}
|
||||
|
||||
{If user attached an image, add: "Read the attached image at {path} — it shows a reference/mockup of the desired icon."}
|
||||
|
||||
## Output Target
|
||||
|
||||
- Icon name: `{icon_name}`
|
||||
- Write new SVG to: `.ai/icon_{name}/{letter}.svg`
|
||||
- Write review notes to: `.ai/icon_{name}/{letter}-review.md` (only when generating a new iteration, not when approving)
|
||||
|
||||
## Style Requirements
|
||||
|
||||
You are generating a **{menu/other}** icon for Telegram Desktop. These icons have VERY specific characteristics you MUST match exactly.
|
||||
|
||||
### SVG Structure (follow exactly)
|
||||
|
||||
The SVG must be minimal — no title, no id attributes, no xlink namespace, no version. These icons are embedded as-is in the app binary, so every unnecessary byte matters.
|
||||
#### Sub-step 7: Assemble final SVG
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24px" height="24px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg width="{OUT_W}px" height="{OUT_H}px" viewBox="{VB_X} {VB_Y} {VB_W} {VB_H}" xmlns="http://www.w3.org/2000/svg">
|
||||
<g stroke="none" fill="none" fill-rule="evenodd">
|
||||
<path d="..." fill="#FFFFFF" fill-rule="nonzero"></path>
|
||||
<path d="..." fill="#FFFFFF"></path>
|
||||
</g>
|
||||
</svg>
|
||||
```
|
||||
|
||||
Do NOT include: `<title>`, `id` attributes, `xmlns:xlink`, `version="1.1"`, or any other metadata.
|
||||
- `width`/`height` = the output size from the request (default `24px`/`24px`).
|
||||
- `viewBox` = the computed viewBox from Sub-step 4. The SVG renderer maps this coordinate region to the output size.
|
||||
- Path `d` attributes are **unchanged** from vectosolve output (just background removed, colors replaced).
|
||||
- No `<title>`, `id`, `xmlns:xlink`, `version`, `class`, `style`, XML comments, `<metadata>`, or `preserveAspectRatio`.
|
||||
- No `<circle>`, `<rect>`, `<line>` — only `<path>`.
|
||||
|
||||
### Visual Style Rules
|
||||
Write the final SVG to `.ai/icon_{name}/{LETTER}.svg`.
|
||||
|
||||
1. **White on transparent**: All visible content is `fill="#FFFFFF"`. Background is transparent.
|
||||
2. **Outline appearance through fill paths**: Icons look like outlined/stroked line drawings, but this is achieved ENTIRELY through filled `<path>` elements — **NOT** through `stroke` attributes. The "outline" effect comes from paths that define both the outer and inner edges of each visible line.
|
||||
3. **Consistent line weight**: Apparent stroke width is approximately **1.2px at 24x24 scale**. Study the reference icons carefully to match this exactly.
|
||||
4. **fill-rule**: Use `fill-rule="evenodd"` on the `<g>` wrapper (so overlapping sub-paths create transparent holes — this is how outlines of shapes like circles, rectangles are drawn). Individual paths may use `fill-rule="nonzero"` when appropriate.
|
||||
5. **Canvas**: 24x24 viewBox with content centered, approximately 2-3px padding from edges.
|
||||
6. **Recognizable at small size**: The icon is displayed at just 24x24 CSS pixels. It must read clearly.
|
||||
7. **Professional quality**: Smooth curves, precise coordinates, balanced composition. No jagged edges.
|
||||
### Step 1c: Render
|
||||
|
||||
### Technical Rules
|
||||
If `RENDER_AVAILABLE`:
|
||||
```bash
|
||||
out/Telegram/codegen/codegen/style/Debug/codegen_style.exe --render-svg ".ai/icon_{name}/{LETTER}.svg" ".ai/icon_{name}/render_{LETTER}.png" 512
|
||||
```
|
||||
|
||||
- High-precision decimal coordinates (like the references — they use 6+ decimal places)
|
||||
- Cubic bezier curves (`C`/`c` commands) for smooth curves
|
||||
- Standard SVG path commands: `M`, `L`, `C`, `Q`, `A`, `Z`
|
||||
- **NO** `stroke` or `stroke-width` attributes anywhere
|
||||
- **NO** transforms — bake all positions into path coordinates
|
||||
- **NO** external references, filters, gradients, or `<use>` elements
|
||||
- **NO** basic shape elements (`<circle>`, `<rect>`, `<line>`) — use only `<path>` (and `<polygon>` only when trivially simple), matching the reference style
|
||||
- Multiple `<path>` elements within the `<g>` are fine for icons with distinct visual parts
|
||||
Read the render to visually verify the result.
|
||||
|
||||
### Reference Icons (READ ALL OF THESE)
|
||||
## Phase 2: Review
|
||||
|
||||
Read ALL of the following SVG files. They define the exact style you must match — study their structure, path complexity, visual weight, and how they achieve the outline appearance:
|
||||
After rendering, assess the result:
|
||||
|
||||
1. `Telegram/Resources/icons/menu/tag_add.svg` — tag shape with plus sign
|
||||
2. `Telegram/Resources/icons/menu/tag_edit.svg` — tag shape with pencil
|
||||
3. `Telegram/Resources/icons/menu/craft_random.svg` — dice with dots
|
||||
4. `Telegram/Resources/icons/menu/craft_chance.svg` — circle with arrows
|
||||
5. `Telegram/Resources/icons/menu/craft_start.svg` — forge/hammer tools
|
||||
6. `Telegram/Resources/icons/menu/reorder.svg` — grid with arrow
|
||||
7. `Telegram/Resources/icons/menu/rating_refund.svg` — circular arrow + dollar sign
|
||||
8. `Telegram/Resources/icons/menu/rating_gifts.svg` — gift box
|
||||
9. `Telegram/Resources/icons/menu/users_stars.svg` — people with stars
|
||||
1. **Recognizable?** The icon should be clearly identifiable as the intended symbol.
|
||||
2. **Scale reasonable?** Should fill the space appropriately with ~2-3px padding.
|
||||
3. **Clean lines?** No broken paths, artifacts, or unwanted elements.
|
||||
4. **Correct colors?** All white on transparent (no leftover colors from the mockup).
|
||||
|
||||
Pay close attention to:
|
||||
- The apparent line thickness and how it's achieved through fill paths
|
||||
- How shapes have "holes" (e.g., the inside of circles, rectangles) via overlapping sub-paths + even-odd fill rule
|
||||
- The overall visual density and balance within the 24x24 space
|
||||
If the result looks good → proceed to Phase 3 (Output).
|
||||
|
||||
NOTE: The reference icons contain `<title>`, `id`, `xmlns:xlink`, and `version` attributes — IGNORE those. Your output must use the minimal SVG structure shown above (no title, no ids, no xlink, no version).
|
||||
If there are fixable issues (stray element, missed color, etc.) → fix the SVG directly, re-render, and re-check.
|
||||
|
||||
{IF SVGs exist (previous iterations)}
|
||||
## Previous Iterations
|
||||
If the result is poor (vectosolve couldn't handle the input well) → report to the user and suggest:
|
||||
- Trying a cleaner/larger crop of the icon
|
||||
- Providing a different screenshot
|
||||
- Following up: `/icon {icon_name} <description of what to change>`
|
||||
|
||||
SVG files (read these to see what was tried):
|
||||
{For each existing letter:}
|
||||
- `.ai/icon_{name}/{letter}.svg`
|
||||
{End for}
|
||||
## Phase 3: Output
|
||||
|
||||
Review notes from previous iterations (read these to understand what was changed and why — if the same issues keep appearing, they likely can't be fixed through further iteration):
|
||||
{For each existing {letter}-review.md:}
|
||||
- `.ai/icon_{name}/{letter}-review.md`
|
||||
{End for}
|
||||
1. Read the `Target:` line from `.ai/icon_{name}/context.md` to get the output path.
|
||||
|
||||
{IF RENDER_AVAILABLE}
|
||||
## Latest Render
|
||||
2. Copy the final SVG to that target path (e.g., `Telegram/Resources/icons/menu/{icon_name}.svg`).
|
||||
|
||||
Read this image to see how the latest iteration looks when rendered (white on black, 512x512):
|
||||
`.ai/icon_{name}/render_{prev_letter}.png`
|
||||
3. Update `.ai/icon_{name}/context.md` — append to the end:
|
||||
```
|
||||
## Latest Output
|
||||
Letter: {LETTER}
|
||||
Written to: {target_path}
|
||||
```
|
||||
|
||||
The render shows the icon upscaled to 512x512 for visibility. Review it:
|
||||
- Does it match the description? Is the depicted object recognizable?
|
||||
- Are proportions and visual weight reasonable compared to the reference icons?
|
||||
- Are there broken paths, artifacts, or major visual glitches?
|
||||
4. Report to the user:
|
||||
- Final icon file path
|
||||
- Number of vectosolve calls made (cost at $0.20/call)
|
||||
- Suggest verifying visually
|
||||
- Working directory `.ai/icon_{name}/` has all iterations
|
||||
- Elapsed time since `$START_TIME` (format `Xm Ys`)
|
||||
- Follow-up: `/icon {icon_name} <description of what to change>`
|
||||
|
||||
**APPROVE unless there is a clear, nameable problem.** Do not reject for minor imperfections or subjective style preferences. If previous reviews show the same issue being raised 2+ times, APPROVE — further iteration won't help.
|
||||
{END IF}
|
||||
{END IF}
|
||||
## Text-only Follow-ups (no new image)
|
||||
|
||||
## Your Output
|
||||
When a follow-up has no attached image, the user wants to refine the existing SVG based on text feedback. In this case:
|
||||
|
||||
{IF no SVGs exist (first generation)}
|
||||
Generate the SVG icon and write it to `.ai/icon_{name}/{letter}.svg`.
|
||||
Briefly describe what you drew and your design approach.
|
||||
Your LAST LINE must be exactly: GENERATED
|
||||
1. Skip Phase 1 (no vectosolve call needed).
|
||||
2. Read the latest SVG (`.ai/icon_{name}/{prev_letter}.svg`).
|
||||
3. Read the latest render if available.
|
||||
4. Apply the user's requested changes by editing the SVG directly.
|
||||
5. Save as `.ai/icon_{name}/{LETTER}.svg`.
|
||||
6. Render, review, and output as normal (Phases 1c → 3).
|
||||
|
||||
{IF SVGs exist (review/improve)}
|
||||
Either:
|
||||
|
||||
a) **APPROVED** — The icon is acceptable (recognizable, correct weight, no major issues).
|
||||
Briefly say why it's good enough. Your LAST LINE must be exactly: APPROVED
|
||||
|
||||
b) **GENERATED** — There is a specific, clear problem that you can fix.
|
||||
First write `.ai/icon_{name}/{letter}-review.md` with:
|
||||
- What specific problem you see in the current render
|
||||
- What you are changing and why
|
||||
- Whether this issue was raised in previous reviews (if so, acknowledge it)
|
||||
Then write the improved SVG to `.ai/icon_{name}/{letter}.svg`.
|
||||
Your LAST LINE must be exactly: GENERATED
|
||||
|
||||
**Bias toward APPROVED.** The icon doesn't need to be perfect. If the object is recognizable and the visual weight is reasonable, approve it. Only reject for clear problems: broken/missing shapes, wrong object depicted, severely wrong line weight, visible artifacts.
|
||||
{END IF}
|
||||
|
||||
CRITICAL: Your absolute last line of output MUST be exactly the word `GENERATED` or `APPROVED` with nothing else on that line.
|
||||
~~~
|
||||
If the changes are too complex for manual SVG editing, suggest the user provide a new screenshot instead.
|
||||
|
||||
## Error Handling
|
||||
|
||||
- If the render helper fails, proceed with SVG-code-only review and reduce max iterations to 3.
|
||||
- If a subagent fails or produces garbled output, retry once with a reminder to follow the format.
|
||||
- If the subagent writes invalid SVG (missing `<svg` tag), discard it and retry.
|
||||
- If after all iterations the result is still poor, report to the user and suggest manual refinement or a follow-up with specific feedback.
|
||||
- If clipboard grab fails → tell user to re-copy and retry.
|
||||
- If vectosolve returns an error → report it and suggest a different/cleaner screenshot.
|
||||
- If vectosolve returns SVG that can't be parsed → save raw output for debugging, report to user.
|
||||
- If the render helper fails → set `RENDER_AVAILABLE = false`, continue with SVG-only review.
|
||||
- If post-processing produces a broken SVG → fall back to the raw vectosolve output and do lighter cleanup.
|
||||
|
||||
Reference in New Issue
Block a user