Compare commits

...

20 Commits

Author SHA1 Message Date
Jim Liu 宝玉 809fb29ca9 chore: release v1.28.1 2026-02-02 09:11:49 -06:00
Jim Liu 宝玉 be20bdf0be refactor(baoyu-article-illustrator): simplify SKILL.md and add Core Styles tier
- Extract detailed workflow to references/workflow.md
- Add Core Styles for quick selection (vector, minimal-flat, sci-fi, hand-drawn, editorial, scene)
- Add vector-illustration as recommended default style
- Add Illustration Purpose (information/visualization/imagination)
- Add default composition, character rendering, text styling to prompts
2026-02-02 09:11:43 -06:00
Jim Liu 宝玉 7c36b2a6a5 chore: release v1.28.0 2026-02-01 19:49:49 -06:00
Jim Liu 宝玉 7979cb9dde chore: ignore baoyu-skill-evolution directory 2026-02-01 19:49:22 -06:00
Jim Liu 宝玉 e563bbae7b feat(baoyu-post-to-wechat): add newspic article type support
- Add ArticleOptions interface with news/newspic types
- Track all image media IDs for newspic format
- Restructure publishToDraft for dual article type handling
2026-02-01 19:49:14 -06:00
Jim Liu 宝玉 c63d1eec69 refactor(baoyu-xhs-images): enforce blocking first-time setup
- Mark preferences loading as BLOCKING operation
- Update workflow flow diagram and checklist
2026-02-01 19:49:05 -06:00
Jim Liu 宝玉 78d6d23359 refactor(baoyu-comic): enforce blocking first-time setup
- Mark preferences loading as BLOCKING operation
- Update workflow flow diagram
2026-02-01 19:48:56 -06:00
Jim Liu 宝玉 ec6781a231 feat(baoyu-article-illustrator): add reference image support
- Add reference image handling with direct/style/palette usage types
- Enhance first-time setup as blocking operation
- Update prompt construction with reference frontmatter format
2026-02-01 19:48:46 -06:00
Jim Liu 宝玉 edf9030675 feat(baoyu-cover-image): add reference image support and visual elements library
- Add --ref parameter for reference images (style/palette/direct usage)
- Add visual-elements.md with icon vocabulary by topic
- Enhance first-time setup as blocking operation
- Remove character limits from titles, use original source titles
- Update prompt template with reference handling
2026-02-01 19:48:37 -06:00
Jim Liu 宝玉 10e1c426a0 chore: release v1.27.0 2026-02-01 02:15:08 -06:00
Jim Liu 宝玉 dbab83ff82 feat(baoyu-markdown-to-html): add remark-cjk-friendly for CJK emphasis
Preprocess markdown with remark-cjk-friendly to properly handle
CJK emphasis markers before HTML conversion.
2026-02-01 02:14:12 -06:00
Jim Liu 宝玉 478e66a93a docs(baoyu-infographic): clarify AskUserQuestion usage
Emphasize combining multiple questions into single call.
2026-02-01 02:14:06 -06:00
Jim Liu 宝玉 3a5866eb4b refactor(baoyu-format-markdown): use remark-cjk-friendly for CJK emphasis
Replace custom CJK emphasis handling with remark-cjk-friendly library,
significantly simplifying the codebase.
2026-02-01 02:13:58 -06:00
Jim Liu 宝玉 c0162bb3af chore: release v1.26.1 2026-01-29 22:02:42 -06:00
Jim Liu 宝玉 e9342a16f8 fix(baoyu-xhs-images): remove notebook style, add backup rules for prompts and images 2026-01-29 22:01:47 -06:00
Jim Liu 宝玉 5cb86d8e51 feat(baoyu-slide-deck): add backup rules for source, prompt, and slide image files 2026-01-29 22:01:42 -06:00
Jim Liu 宝玉 66ed08f010 feat(baoyu-infographic): add backup rules for source, analysis, prompt, and image files 2026-01-29 22:01:22 -06:00
Jim Liu 宝玉 b179166d28 feat(baoyu-cover-image): add backup rules for source and prompt files 2026-01-29 22:01:17 -06:00
Jim Liu 宝玉 4805526649 feat(baoyu-comic): add backup rules for source, character sheet, prompts, and page images 2026-01-29 22:00:59 -06:00
Jim Liu 宝玉 89159bf86e feat(baoyu-article-illustrator): add backup rules for source, prompt, and image files 2026-01-29 22:00:37 -06:00
33 changed files with 4009 additions and 764 deletions
+1 -1
View File
@@ -6,7 +6,7 @@
}, },
"metadata": { "metadata": {
"description": "Skills shared by Baoyu for improving daily work efficiency", "description": "Skills shared by Baoyu for improving daily work efficiency",
"version": "1.26.0" "version": "1.28.1"
}, },
"plugins": [ "plugins": [
{ {
+2
View File
@@ -157,3 +157,5 @@ comic/
*.iws *.iws
*.iml *.iml
*.ipr *.ipr
.claude/skills/baoyu-skill-evolution
+24
View File
@@ -2,6 +2,30 @@
English | [中文](./CHANGELOG.zh.md) English | [中文](./CHANGELOG.zh.md)
## 1.28.1 - 2026-02-02
### Refactor
- `baoyu-article-illustrator`: simplify main SKILL.md by extracting detailed procedures to `workflow.md`; add Core Styles tier (vector, minimal-flat, sci-fi, hand-drawn, editorial, scene) for quick selection; add `vector-illustration` as recommended default style; add Illustration Purpose (information/visualization/imagination) for better type/style recommendations; add default composition requirements, character rendering guidelines, and text styling rules to prompt construction.
## 1.28.0 - 2026-02-01
### Features
- `baoyu-cover-image`: add reference image support (`--ref` parameter) with direct/style/palette usage types; add visual elements library with icon vocabulary by topic.
- `baoyu-article-illustrator`: add reference image support with direct/style/palette usage types.
- `baoyu-post-to-wechat`: add `newspic` article type for image-text posts.
### Refactor
- `baoyu-cover-image`, `baoyu-article-illustrator`, `baoyu-comic`, `baoyu-xhs-images`: enforce first-time setup as blocking operation before any other workflow steps.
- `baoyu-cover-image`: remove character limits from titles, use original source titles.
## 1.26.1 - 2026-01-29
### Features
- `baoyu-article-illustrator`, `baoyu-comic`, `baoyu-cover-image`, `baoyu-infographic`, `baoyu-slide-deck`, `baoyu-xhs-images`: add backup rules for existing files—automatically renames source, prompt, and image files with timestamp suffix before overwriting.
### Fixes
- `baoyu-xhs-images`: remove `notebook` style (10 styles remaining).
## 1.26.0 - 2026-01-29 ## 1.26.0 - 2026-01-29
### Features ### Features
+24
View File
@@ -2,6 +2,30 @@
[English](./CHANGELOG.md) | 中文 [English](./CHANGELOG.md) | 中文
## 1.28.1 - 2026-02-02
### 重构
- `baoyu-article-illustrator`:简化主 SKILL.md,将详细步骤提取到 `workflow.md`;新增 Core Styles 快速选择层(vector、minimal-flat、sci-fi、hand-drawn、editorial、scene);新增 `vector-illustration` 作为推荐默认风格;新增插图目的(information/visualization/imagination)以优化类型/风格推荐;在提示词构建中新增默认构图要求、人物渲染指南和文本样式规则。
## 1.28.0 - 2026-02-01
### 新功能
- `baoyu-cover-image`:新增参考图片支持(`--ref` 参数),支持 direct/style/palette 三种用法;新增视觉元素库,按主题分类图标词汇。
- `baoyu-article-illustrator`:新增参考图片支持,支持 direct/style/palette 三种用法。
- `baoyu-post-to-wechat`:新增 `newspic` 图文消息类型支持。
### 重构
- `baoyu-cover-image``baoyu-article-illustrator``baoyu-comic``baoyu-xhs-images`:强化首次设置为阻塞操作,必须在其他工作流步骤之前完成。
- `baoyu-cover-image`:移除标题字符数限制,使用原始来源标题。
## 1.26.1 - 2026-01-29
### 新功能
- `baoyu-article-illustrator``baoyu-comic``baoyu-cover-image``baoyu-infographic``baoyu-slide-deck``baoyu-xhs-images`:新增文件备份规则,覆盖前自动将现有源文件、提示词和图片重命名为带时间戳后缀的备份文件。
### 修复
- `baoyu-xhs-images`:移除 `notebook` 风格(保留 10 种风格)。
## 1.26.0 - 2026-01-29 ## 1.26.0 - 2026-01-29
### 新功能 ### 新功能
+57 -188
View File
@@ -16,6 +16,16 @@ Analyze articles, identify illustration positions, generate images with Type ×
Type × Style can be freely combined. Example: `--type infographic --style blueprint` Type × Style can be freely combined. Example: `--type infographic --style blueprint`
## Illustration Purpose
Auto-detected during content analysis. Influences type/style recommendations.
| Purpose | Description | Best Types |
|---------|-------------|------------|
| **information** | Help understand abstract concepts | infographic, flowchart, comparison |
| **visualization** | Turn abstract ideas into concrete visuals | framework, comparison, infographic |
| **imagination** | Create atmosphere, spark imagination | scene, timeline |
## Type Gallery ## Type Gallery
| Type | Best For | | Type | Best For |
@@ -27,92 +37,37 @@ Type × Style can be freely combined. Example: `--type infographic --style bluep
| `framework` | Methodologies, models, architecture | | `framework` | Methodologies, models, architecture |
| `timeline` | History, progress, evolution | | `timeline` | History, progress, evolution |
## Style Gallery ## Styles
| Style | Best For | See [references/styles.md](references/styles.md) for:
|-------|----------| - **Core Styles**: Simplified tier for quick selection (vector, minimal-flat, sci-fi, hand-drawn, editorial, scene)
| `notion` (Default) | Knowledge sharing, SaaS, productivity | - **Style Gallery**: Full 20+ style options with descriptions
| `elegant` | Business, thought leadership | - **Auto Selection**: Content signals → Type/Style recommendations
| `warm` | Personal growth, lifestyle, education | - **Compatibility Matrix**: Type × Style combinations
| `minimal` | Philosophy, core concepts |
| `blueprint` | Architecture, system design |
| `watercolor` | Lifestyle, travel, creative |
| `editorial` | Tech explainers, journalism |
| `scientific` | Academic, technical research |
Full styles: [references/styles.md](references/styles.md)
## Auto Selection
| Content Signals | Type | Style |
|-----------------|------|-------|
| API, metrics, data, numbers | infographic | blueprint, notion |
| Story, emotion, journey | scene | warm, watercolor |
| How-to, steps, workflow | flowchart | notion, minimal |
| vs, pros/cons, before/after | comparison | notion, elegant |
| Framework, model, architecture | framework | blueprint, notion |
| History, timeline, progress | timeline | elegant, warm |
## Workflow ## Workflow
Copy this checklist and track progress:
``` ```
Progress: Progress:
- [ ] Step 1: Pre-check - [ ] Step 1: Pre-check
- [ ] 1.5 Load preferences (EXTEND.md) ⛔ BLOCKING
- [ ] 1.0 Reference images ⚠️ (if provided)
- [ ] 1.2-1.4 Config questions (1 AskUserQuestion, max 4 Qs)
- [ ] Step 2: Setup & Analyze - [ ] Step 2: Setup & Analyze
- [ ] Step 3: Confirm Settings ⚠️ REQUIRED - [ ] Step 3: Confirm Settings (1 AskUserQuestion, max 4 Qs)
- [ ] Q1: Type ⚠️
- [ ] Q2: Density ⚠️ MUST ASK
- [ ] Q3: Style ⚠️
- [ ] Step 4: Generate Outline - [ ] Step 4: Generate Outline
- [ ] Step 5: Generate Images - [ ] Step 5: Generate Images
- [ ] Step 6: Finalize - [ ] Step 6: Finalize
``` ```
---
### Step 1: Pre-check ### Step 1: Pre-check
**1.1 Determine Input Type** **1.5 Load Preferences (EXTEND.md) ⛔ BLOCKING**
| Input | Output Directory | Next | **CRITICAL**: If EXTEND.md not found, MUST complete first-time setup before ANY other steps.
|-------|------------------|------|
| File path | Ask user (1.2) | → 1.2 |
| Pasted content | `illustrations/{topic-slug}/` | → 1.4 |
**1.2 Determine Output Directory** (file path input only)
Check `default_output_dir` in preferences:
| Preference Value | Action |
|------------------|--------|
| `same-dir` | Use `{article-dir}/`, display "Output: {path}" |
| `imgs-subdir` | Use `{article-dir}/imgs/`, display "Output: {path}" |
| `illustrations-subdir` | Use `{article-dir}/illustrations/`, display "Output: {path}" |
| `independent` | Use `illustrations/{topic-slug}/`, display "Output: {path}" |
| Not configured | **MUST** ask with AskUserQuestion ↓ |
**AskUserQuestion** (when no preference):
- `{article-dir}/` - Same directory as article
- `{article-dir}/imgs/` - Images subdirectory
- `{article-dir}/illustrations/` - Illustrations subdirectory (Recommended)
- `illustrations/{topic-slug}/` - Independent directory
- Save as default - Remember this choice for future runs
**1.3 Check Existing Images**
Scan target directory for `.png/.jpg/.webp` files.
If images exist → AskUserQuestion: How to handle?
- `supplement` - Keep existing, generate only new positions
- `overwrite` - Overwrite same-name files
- `regenerate` - Clear all and regenerate
**1.4 Confirm Article Update Method** (file path input only)
AskUserQuestion: How to update article?
- `update` - Modify original file directly
- `copy` - Create `{name}-illustrated.md` copy
**1.5 Load Preferences (EXTEND.md)**
```bash ```bash
test -f .baoyu-skills/baoyu-article-illustrator/EXTEND.md && echo "project" test -f .baoyu-skills/baoyu-article-illustrator/EXTEND.md && echo "project"
@@ -121,166 +76,86 @@ test -f "$HOME/.baoyu-skills/baoyu-article-illustrator/EXTEND.md" && echo "user"
| Result | Action | | Result | Action |
|--------|--------| |--------|--------|
| Found | Read, parse, display summary | | Found | Read, parse, display summary → Continue |
| Not found | Ask with AskUserQuestion (see references/config/first-time-setup.md) | | Not found | ⛔ Run first-time setup ([references/config/first-time-setup.md](references/config/first-time-setup.md)) |
**Supports**: Watermark | Preferred type/style | Custom styles | Language | Output directory **Supports**: Watermark | Preferred type/style | Custom styles | Language | Output directory
**1.0-1.4**: Handle reference images, determine input type, ask config questions.
Full procedures: [references/workflow.md](references/workflow.md#step-1-pre-check)
--- ---
### Step 2: Setup & Analyze ### Step 2: Setup & Analyze
**2.1 Analyze Content**
| Analysis | Description | | Analysis | Description |
|----------|-------------| |----------|-------------|
| Content type | Technical / Tutorial / Methodology / Narrative | | Content type | Technical / Tutorial / Methodology / Narrative |
| Illustration purpose | information / visualization / imagination |
| Core arguments | 2-5 main points to visualize | | Core arguments | 2-5 main points to visualize |
| Visual opportunities | Positions where illustrations add value | | Visual opportunities | Positions where illustrations add value |
| Recommended type | Based on content signals |
| Recommended density | Based on length and complexity |
**2.2 Extract Core Arguments** **CRITICAL**: If article uses metaphors, do NOT illustrate literally. Visualize the **underlying concept**.
- Main thesis Full procedures: [references/workflow.md](references/workflow.md#step-2-setup--analyze)
- Key concepts reader needs
- Comparisons/contrasts
- Framework/model proposed
**CRITICAL**: If article uses metaphors (e.g., "电锯切西瓜"), do NOT illustrate literally. Visualize the **underlying concept**.
**2.3 Identify Positions**
**Illustrate**:
- Core arguments (REQUIRED)
- Abstract concepts
- Data comparisons
- Processes, workflows
**Do NOT Illustrate**:
- Metaphors literally
- Decorative scenes
- Generic illustrations
--- ---
### Step 3: Confirm Settings ⚠️ ### Step 3: Confirm Settings ⚠️
**Do NOT skip.** Use AskUserQuestion with 3-4 questions in ONE call. **Do NOT skip.** Use ONE AskUserQuestion call with max 4 questions. **Q1, Q2, Q3 are ALL REQUIRED.**
**Q1: Illustration Type** | Question | Options |
- [Recommended based on analysis] (Recommended) |----------|---------|
- infographic / scene / flowchart / comparison / framework / timeline / mixed | **Q1: Type** ⚠️ | [Recommended], infographic, scene, flowchart, comparison, framework, timeline, mixed |
| **Q2: Density** ⚠️ | minimal (1-2), balanced (3-5), per-section (Recommended), rich (6+) |
| **Q3: Style** ⚠️ | [Recommended], minimal-flat, sci-fi, hand-drawn, editorial, scene, Other |
| **Q4: Language** | When article language ≠ EXTEND.md setting |
**Q2: Density** Full procedures: [references/workflow.md](references/workflow.md#step-3-confirm-settings-)
- minimal (1-2) - Core concepts only
- balanced (3-5) (Recommended) - Major sections
- rich (6+) - Comprehensive support
**Q3: Style** (ALWAYS ask, even with preferred_style in EXTEND.md)
If EXTEND.md has `preferred_style`:
- [Custom style name + brief description] (Recommended)
- [Top compatible built-in style 1]
- [Top compatible built-in style 2]
- [Top compatible built-in style 3]
If no `preferred_style`:
- [Best compatible from matrix] (Recommended)
- [Other ✓✓ style 1]
- [Other ✓✓ style 2]
- [Other ✓ style]
Style selection based on Type × Style compatibility matrix (references/styles.md).
Full specs: `references/styles/<style>.md`
**Q4** (only if source ≠ user language):
- Language: Source / User language
--- ---
### Step 4: Generate Outline ### Step 4: Generate Outline
Save as `outline.md`: Save as `outline.md` with frontmatter (type, density, style, image_count, references) and illustration entries:
```yaml ```yaml
---
type: infographic
density: balanced
style: blueprint
image_count: 4
---
## Illustration 1 ## Illustration 1
**Position**: [section] / [paragraph] **Position**: [section] / [paragraph]
**Purpose**: [why this helps] **Purpose**: [why this helps]
**Visual Content**: [what to show] **Visual Content**: [what to show]
**Type Application**: [how type applies]
**Filename**: 01-infographic-concept-name.png **Filename**: 01-infographic-concept-name.png
## Illustration 2
...
``` ```
**Requirements**: Full template: [references/workflow.md](references/workflow.md#step-4-generate-outline)
- Each position justified by content needs
- Type applied consistently
- Style reflected in descriptions
- Count matches density
--- ---
### Step 5: Generate Images ### Step 5: Generate Images
**5.1 Create Prompts** 1. **Create Prompts**: Follow [references/prompt-construction.md](references/prompt-construction.md)
2. **Select Generation Skill**: Check available skills
3. **Process References**: Handle `direct`/`style`/`palette` usage
4. **Apply Watermark**: If enabled in EXTEND.md
5. **Generate**: Sequential, retry once on failure
Follow [references/prompt-construction.md](references/prompt-construction.md). Save to `prompts/illustration-{slug}.md`. Full procedures: [references/workflow.md](references/workflow.md#step-5-generate-images)
**5.2 Select Generation Skill**
Check available skills. If multiple, ask user.
**5.3 Apply Watermark** (if enabled)
Add: `Include a subtle watermark "[content]" at [position].`
**5.4 Generate**
1. Generate sequentially
2. After each: "Generated X/N"
3. On failure: retry once, then log and continue
--- ---
### Step 6: Finalize ### Step 6: Finalize
**6.1 Update Article** **Update Article**: Insert `![description](path/NN-{type}-{slug}.png)` after corresponding paragraphs.
Insert after corresponding paragraph:
```markdown
![description](illustrations/{slug}/NN-{type}-{slug}.png)
```
Alt text: concise description in article's language.
**6.2 Output Summary**
**Output Summary**:
``` ```
Article Illustration Complete! Article Illustration Complete!
Article: [path] | Type: [type] | Density: [level] | Style: [style]
Article: [path]
Type: [type] | Density: [level] | Style: [style]
Location: [directory]
Images: X/N generated Images: X/N generated
Positions: Positions:
- 01-xxx.png → After "[Section]" - 01-xxx.png → After "[Section]"
- 02-yyy.png → After "[Section]"
[If failures]
Failed:
- NN-zzz.png: [reason]
``` ```
--- ---
@@ -290,6 +165,8 @@ Failed:
``` ```
illustrations/{topic-slug}/ illustrations/{topic-slug}/
├── source-{slug}.{ext} ├── source-{slug}.{ext}
├── references/ # Only if references provided
│ └── NN-ref-{slug}.png
├── outline.md ├── outline.md
├── prompts/ ├── prompts/
│ └── illustration-{slug}.md │ └── illustration-{slug}.md
@@ -303,26 +180,18 @@ illustrations/{topic-slug}/
| Action | Steps | | Action | Steps |
|--------|-------| |--------|-------|
| **Edit** | **Update prompt file FIRST** → Regenerate → Update reference | | **Edit** | Update prompt file FIRST → Regenerate → Update reference |
| **Add** | Identify position → Create prompt → Generate → Update outline → Insert | | **Add** | Identify position → Create prompt → Generate → Update outline → Insert |
| **Delete** | Delete files → Remove reference → Update outline | | **Delete** | Delete files → Remove reference → Update outline |
**IMPORTANT**: When updating illustrations, ALWAYS update the prompt file (`prompts/illustration-{slug}.md`) FIRST before regenerating. This ensures:
1. Changes are documented and reproducible
2. The prompt reflects the new requirements
3. Future regeneration uses the correct prompt
## References ## References
| File | Content | | File | Content |
|------|---------| |------|---------|
| [references/workflow.md](references/workflow.md) | Detailed workflow procedures |
| [references/usage.md](references/usage.md) | Command syntax and options | | [references/usage.md](references/usage.md) | Command syntax and options |
| [references/styles.md](references/styles.md) | Style gallery & compatibility | | [references/styles.md](references/styles.md) | Style gallery & compatibility |
| [references/prompt-construction.md](references/prompt-construction.md) | Prompt templates | | [references/prompt-construction.md](references/prompt-construction.md) | Prompt templates |
| `references/styles/<style>.md` | Full style specifications | | `references/styles/<style>.md` | Full style specifications |
| `references/config/preferences-schema.md` | EXTEND.md schema | | `references/config/preferences-schema.md` | EXTEND.md schema |
| `references/config/first-time-setup.md` | First-time setup flow | | `references/config/first-time-setup.md` | First-time setup flow |
## Extension Support
Custom configurations via EXTEND.md. See **Step 1.5** for paths and supported options.
@@ -9,6 +9,14 @@ description: First-time setup flow for baoyu-article-illustrator preferences
When no EXTEND.md is found, guide user through preference setup. When no EXTEND.md is found, guide user through preference setup.
**⛔ BLOCKING OPERATION**: This setup MUST complete before ANY other workflow steps. Do NOT:
- Ask about reference images
- Ask about content/article
- Ask about type or style preferences
- Proceed to content analysis
ONLY ask the questions in this setup flow, save EXTEND.md, then continue.
## Setup Flow ## Setup Flow
``` ```
@@ -1,5 +1,102 @@
# Prompt Construction # Prompt Construction
## Prompt File Format
Each prompt file uses YAML frontmatter + content:
```yaml
---
illustration_id: 01
type: infographic
style: blueprint
references: # ⚠️ ONLY if files EXIST in references/ directory
- ref_id: 01
filename: 01-ref-diagram.png
usage: direct # direct | style | palette
---
[Type-specific template content below...]
```
**⚠️ CRITICAL - When to include `references` field**:
| Situation | Action |
|-----------|--------|
| Reference file saved to `references/` | Include in frontmatter ✓ |
| Style extracted verbally (no file) | DO NOT include in frontmatter, append to prompt body instead |
| File path in frontmatter but file doesn't exist | ERROR - remove references field |
**Reference Usage Types** (only when file exists):
| Usage | Description | Generation Action |
|-------|-------------|-------------------|
| `direct` | Primary visual reference | Pass to `--ref` parameter |
| `style` | Style characteristics only | Describe style in prompt text |
| `palette` | Color palette extraction | Include colors in prompt |
**If no reference file but style/palette extracted verbally**, append directly to prompt body:
```
COLORS (from reference):
- Primary: #E8756D coral
- Secondary: #7ECFC0 mint
...
STYLE (from reference):
- Clean lines, minimal shadows
- Gradient backgrounds
...
```
---
## Default Composition Requirements
**Apply to ALL prompts by default**:
| Requirement | Description |
|-------------|-------------|
| **Clean composition** | Simple layouts, no visual clutter |
| **White space** | Generous margins, breathing room around elements |
| **No complex backgrounds** | Solid colors or subtle gradients only, avoid busy textures |
| **Centered or content-appropriate** | Main visual elements centered or positioned by content needs |
| **Matching graphics** | Use graphic elements that align with content theme |
| **Highlight core info** | White space draws attention to key information |
**Add to ALL prompts**:
> Clean composition with generous white space. Simple or no background. Main elements centered or positioned by content needs.
---
## Character Rendering
When depicting people:
| Guideline | Description |
|-----------|-------------|
| **Style** | Simplified cartoon silhouettes or symbolic expressions |
| **Avoid** | Realistic human portrayals, detailed faces |
| **Diversity** | Varied body types when showing multiple people |
| **Emotion** | Express through posture and simple gestures |
**Add to ALL prompts with human figures**:
> Human figures: simplified stylized silhouettes or symbolic representations, not photorealistic.
---
## Text in Illustrations
| Element | Guideline |
|---------|-----------|
| **Size** | Large, prominent, immediately readable |
| **Style** | Handwritten fonts preferred for warmth |
| **Content** | Concise keywords and core concepts only |
| **Language** | Match article language |
**Add to prompts with text**:
> Text should be large and prominent with handwritten-style fonts. Keep minimal, focus on keywords.
---
## Principles ## Principles
Good prompts must include: Good prompts must include:
@@ -31,6 +128,13 @@ STYLE: [style characteristics]
ASPECT: 16:9 ASPECT: 16:9
``` ```
**Infographic + vector-illustration**:
```
Flat vector illustration infographic. Clean black outlines on all elements.
COLORS: Cream background (#F5F0E6), Coral Red (#E07A5F), Mint Green (#81B29A), Mustard Yellow (#F2CC8F)
ELEMENTS: Geometric simplified icons, no gradients, playful decorative elements (dots, stars)
```
### Scene ### Scene
``` ```
@@ -61,6 +165,13 @@ STYLE: [style characteristics]
ASPECT: 16:9 ASPECT: 16:9
``` ```
**Flowchart + vector-illustration**:
```
Flat vector flowchart with bold arrows and geometric step containers.
COLORS: Cream background (#F5F0E6), steps in Coral/Mint/Mustard, black outlines
ELEMENTS: Rounded rectangles, thick arrows, simple icons per step
```
### Comparison ### Comparison
``` ```
@@ -79,6 +190,13 @@ STYLE: [style characteristics]
ASPECT: 16:9 ASPECT: 16:9
``` ```
**Comparison + vector-illustration**:
```
Flat vector comparison with split layout. Clear visual separation.
COLORS: Left side Coral (#E07A5F), Right side Mint (#81B29A), cream background
ELEMENTS: Bold icons, black outlines, centered divider line
```
### Framework ### Framework
``` ```
@@ -95,6 +213,13 @@ STYLE: [style characteristics]
ASPECT: 16:9 ASPECT: 16:9
``` ```
**Framework + vector-illustration**:
```
Flat vector framework diagram with geometric nodes and bold connectors.
COLORS: Cream background (#F5F0E6), nodes in Coral/Mint/Mustard/Blue, black outlines
ELEMENTS: Rounded rectangles or circles for nodes, thick connecting lines
```
### Timeline ### Timeline
``` ```
@@ -1,10 +1,28 @@
# Style Reference # Style Reference
## Core Styles
Simplified style tier for quick selection:
| Core Style | Maps To | Best For |
|------------|---------|----------|
| `vector` | vector-illustration | Knowledge articles, tutorials, tech content |
| `minimal-flat` | notion | General, knowledge sharing, SaaS |
| `sci-fi` | blueprint | AI, frontier tech, system design |
| `hand-drawn` | sketch/warm | Relaxed, reflective, casual content |
| `editorial` | editorial | Processes, data, journalism |
| `scene` | warm/watercolor | Narratives, emotional, lifestyle |
Use Core Styles for most cases. See full Style Gallery below for granular control.
---
## Style Gallery ## Style Gallery
| Style | Description | Best For | | Style | Description | Best For |
|-------|-------------|----------| |-------|-------------|----------|
| `notion` (Default) | Minimalist hand-drawn line art | Knowledge sharing, SaaS, productivity | | `vector-illustration` | Clean flat vector art with bold shapes | Knowledge articles, tutorials, tech content |
| `notion` | Minimalist hand-drawn line art | Knowledge sharing, SaaS, productivity |
| `elegant` | Refined, sophisticated | Business, thought leadership | | `elegant` | Refined, sophisticated | Business, thought leadership |
| `warm` | Friendly, approachable | Personal growth, lifestyle, education | | `warm` | Friendly, approachable | Personal growth, lifestyle, education |
| `minimal` | Ultra-clean, zen-like | Philosophy, minimalism, core concepts | | `minimal` | Ultra-clean, zen-like | Philosophy, minimalism, core concepts |
@@ -12,19 +30,31 @@
| `watercolor` | Soft artistic with natural warmth | Lifestyle, travel, creative | | `watercolor` | Soft artistic with natural warmth | Lifestyle, travel, creative |
| `editorial` | Magazine-style infographic | Tech explainers, journalism | | `editorial` | Magazine-style infographic | Tech explainers, journalism |
| `scientific` | Academic precise diagrams | Biology, chemistry, technical research | | `scientific` | Academic precise diagrams | Biology, chemistry, technical research |
| `chalkboard` | Classroom chalk drawing style | Education, teaching, explanations |
| `fantasy-animation` | Ghibli/Disney-inspired hand-drawn | Storybook, magical, emotional |
| `flat` | Modern bold geometric shapes | Modern digital, contemporary |
| `flat-doodle` | Cute flat with bold outlines | Cute, friendly, approachable |
| `intuition-machine` | Technical briefing with aged paper | Technical briefings, academic |
| `nature` | Organic earthy illustration | Environmental, wellness |
| `pixel-art` | Retro 8-bit gaming aesthetic | Gaming, retro tech |
| `playful` | Whimsical pastel doodles | Fun, casual, educational |
| `retro` | 80s/90s neon geometric | 80s/90s nostalgic, bold |
| `sketch` | Raw pencil notebook style | Brainstorming, creative exploration |
| `sketch-notes` | Soft hand-drawn warm notes | Educational, warm notes |
| `vintage` | Aged parchment historical | Historical, heritage |
Full specifications: `references/styles/<style>.md` Full specifications: `references/styles/<style>.md`
## Type × Style Compatibility Matrix ## Type × Style Compatibility Matrix
| | notion | warm | minimal | blueprint | watercolor | elegant | editorial | scientific | | | vector-illustration | notion | warm | minimal | blueprint | watercolor | elegant | editorial | scientific |
|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:| |---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
| infographic | ✓✓ | ✓ | ✓✓ | ✓✓ | ✓ | ✓✓ | ✓✓ | ✓✓ | | infographic | ✓✓ | ✓✓ | ✓ | ✓✓ | ✓✓ | ✓ | ✓✓ | ✓✓ | ✓✓ |
| scene | ✓ | ✓✓ | ✓ | ✗ | ✓✓ | ✓ | ✓ | ✗ | | scene | ✓ | ✓ | ✓✓ | ✓ | ✗ | ✓✓ | ✓ | ✓ | ✗ |
| flowchart | ✓✓ | ✓ | ✓ | ✓✓ | ✗ | ✓ | ✓✓ | ✓ | | flowchart | ✓✓ | ✓✓ | ✓ | ✓ | ✓✓ | ✗ | ✓ | ✓✓ | ✓ |
| comparison | ✓✓ | ✓ | ✓✓ | ✓ | ✓ | ✓✓ | ✓✓ | ✓ | | comparison | ✓✓ | ✓✓ | ✓ | ✓✓ | ✓ | ✓ | ✓✓ | ✓✓ | ✓ |
| framework | ✓✓ | ✓ | ✓✓ | ✓✓ | ✗ | ✓✓ | ✓ | ✓✓ | | framework | ✓✓ | ✓✓ | ✓ | ✓✓ | ✓✓ | ✗ | ✓✓ | ✓ | ✓✓ |
| timeline | ✓✓ | ✓ | ✓ | ✓ | ✓✓ | ✓✓ | ✓✓ | ✓ | | timeline | ✓ | ✓✓ | ✓ | ✓ | ✓ | ✓✓ | ✓✓ | ✓✓ | ✓ |
✓✓ = highly recommended | ✓ = compatible | ✗ = not recommended ✓✓ = highly recommended | ✓ = compatible | ✗ = not recommended
@@ -32,30 +62,57 @@ Full specifications: `references/styles/<style>.md`
| Type | Primary Style | Secondary Styles | | Type | Primary Style | Secondary Styles |
|------|---------------|------------------| |------|---------------|------------------|
| infographic | blueprint | notion, editorial, scientific | | infographic | vector-illustration | notion, blueprint, editorial |
| scene | warm | watercolor, elegant | | scene | warm | watercolor, elegant |
| flowchart | notion | blueprint, editorial | | flowchart | vector-illustration | notion, blueprint |
| comparison | notion | elegant, editorial | | comparison | vector-illustration | notion, elegant |
| framework | blueprint | notion, scientific | | framework | blueprint | vector-illustration, notion |
| timeline | elegant | warm, editorial | | timeline | elegant | warm, editorial |
## Auto Selection by Content Signals ## Auto Selection by Content Signals
| Content Signals | Recommended Type | Recommended Style | | Content Signals | Recommended Type | Recommended Style |
|-----------------|------------------|-------------------| |-----------------|------------------|-------------------|
| API, metrics, data, comparison, numbers | infographic | blueprint, notion | | API, metrics, data, comparison, numbers | infographic | blueprint, vector-illustration |
| Knowledge, concept, tutorial, learning, guide | infographic | vector-illustration, notion |
| Tech, AI, programming, development, code | infographic | vector-illustration, blueprint |
| How-to, steps, workflow, process, tutorial | flowchart | vector-illustration, notion |
| Framework, model, architecture, principles | framework | blueprint, vector-illustration |
| vs, pros/cons, before/after, alternatives | comparison | vector-illustration, notion |
| Story, emotion, journey, experience, personal | scene | warm, watercolor | | Story, emotion, journey, experience, personal | scene | warm, watercolor |
| How-to, steps, workflow, process, tutorial | flowchart | notion, minimal |
| vs, pros/cons, before/after, alternatives | comparison | notion, elegant |
| Framework, model, architecture, principles | framework | blueprint, notion |
| History, timeline, progress, evolution | timeline | elegant, warm | | History, timeline, progress, evolution | timeline | elegant, warm |
| Knowledge, concept, productivity, SaaS, tool | infographic | notion | | Productivity, SaaS, tool, app, software | infographic | notion, vector-illustration |
| Business, professional, strategy, corporate | framework | elegant | | Business, professional, strategy, corporate | framework | elegant |
| Biology, chemistry, medical, scientific | infographic | scientific | | Biology, chemistry, medical, scientific | infographic | scientific |
| Explainer, journalism, magazine, investigation | infographic | editorial | | Explainer, journalism, magazine, investigation | infographic | editorial |
## Style Characteristics by Type ## Style Characteristics by Type
### infographic + vector-illustration
- Clean flat vector shapes, bold geometric forms
- Vibrant but harmonious color palette
- Clear visual hierarchy with icons and labels
- Modern, professional, highly readable
- Perfect for knowledge articles and tutorials
### flowchart + vector-illustration
- Bold arrows and connectors
- Distinct step containers with icons
- Clean progression flow
- High contrast for readability
### comparison + vector-illustration
- Split layout with clear visual separation
- Bold iconography for each side
- Color-coded distinctions
- Easy at-a-glance comparison
### framework + vector-illustration
- Geometric node representations
- Clear hierarchical structure
- Bold connecting lines
- Modern system diagram aesthetic
### infographic + blueprint ### infographic + blueprint
- Technical precision, schematic lines - Technical precision, schematic lines
- Grid-based layout, clear zones - Grid-based layout, clear zones
@@ -0,0 +1,355 @@
# Detailed Workflow Procedures
## Step 1: Pre-check
### 1.0 Detect & Save Reference Images ⚠️ REQUIRED if images provided
Check if user provided reference images. Handle based on input type:
| Input Type | Action |
|------------|--------|
| Image file path provided | Copy to `references/` subdirectory → can use `--ref` |
| Image in conversation (no path) | **ASK user for file path** with AskUserQuestion |
| User can't provide path | Extract style/palette verbally → append to prompts (NO frontmatter references) |
**CRITICAL**: Only add `references` to prompt frontmatter if files are ACTUALLY SAVED to `references/` directory.
**If user provides file path**:
1. Copy to `references/NN-ref-{slug}.png`
2. Create description: `references/NN-ref-{slug}.md`
3. Verify files exist before proceeding
**If user can't provide path** (extracted verbally):
1. Analyze image visually, extract: colors, style, composition
2. Create `references/extracted-style.md` with extracted info
3. DO NOT add `references` to prompt frontmatter
4. Instead, append extracted style/colors directly to prompt text
**Description File Format** (only when file saved):
```yaml
---
ref_id: NN
filename: NN-ref-{slug}.png
---
[User's description or auto-generated description]
```
**Verification** (only for saved files):
```
Reference Images Saved:
- 01-ref-{slug}.png ✓ (can use --ref)
- 02-ref-{slug}.png ✓ (can use --ref)
```
**Or for extracted style**:
```
Reference Style Extracted (no file):
- Colors: #E8756D coral, #7ECFC0 mint...
- Style: minimal flat vector, clean lines...
→ Will append to prompt text (not --ref)
```
---
### 1.1 Determine Input Type
| Input | Output Directory | Next |
|-------|------------------|------|
| File path | Ask user (1.2) | → 1.2 |
| Pasted content | `illustrations/{topic-slug}/` | → 1.4 |
**Backup rule for pasted content**: If `source.md` exists in target directory, rename to `source-backup-YYYYMMDD-HHMMSS.md` before saving.
### 1.2-1.4 Configuration (file path input only)
Check preferences and existing state, then ask ALL needed questions in ONE AskUserQuestion call (max 4 questions).
**Questions to include** (skip if preference exists or not applicable):
| Question | When to Ask | Options |
|----------|-------------|---------|
| Output directory | No `default_output_dir` in EXTEND.md | `{article-dir}/`, `{article-dir}/imgs/` (Recommended), `{article-dir}/illustrations/`, `illustrations/{topic-slug}/` |
| Existing images | Target dir has `.png/.jpg/.webp` files | `supplement`, `overwrite`, `regenerate` |
| Article update | Always (file path input) | `update`, `copy` |
**Preference Values** (if configured, skip asking):
| `default_output_dir` | Path |
|----------------------|------|
| `same-dir` | `{article-dir}/` |
| `imgs-subdir` | `{article-dir}/imgs/` |
| `illustrations-subdir` | `{article-dir}/illustrations/` |
| `independent` | `illustrations/{topic-slug}/` |
### 1.5 Load Preferences (EXTEND.md) ⛔ BLOCKING
**CRITICAL**: If EXTEND.md not found, MUST complete first-time setup before ANY other questions or steps. Do NOT proceed to reference images, do NOT ask about content, do NOT ask about type/style — ONLY complete the preferences setup first.
```bash
test -f .baoyu-skills/baoyu-article-illustrator/EXTEND.md && echo "project"
test -f "$HOME/.baoyu-skills/baoyu-article-illustrator/EXTEND.md" && echo "user"
```
| Result | Action |
|--------|--------|
| Found | Read, parse, display summary → Continue |
| Not found | ⛔ **BLOCKING**: Run first-time setup ONLY ([config/first-time-setup.md](config/first-time-setup.md)) → Complete and save EXTEND.md → Then continue |
**Supports**: Watermark | Preferred type/style | Custom styles | Language | Output directory
---
## Step 2: Setup & Analyze
### 2.1 Analyze Content
| Analysis | Description |
|----------|-------------|
| Content type | Technical / Tutorial / Methodology / Narrative |
| Illustration purpose | information / visualization / imagination |
| Core arguments | 2-5 main points to visualize |
| Visual opportunities | Positions where illustrations add value |
| Recommended type | Based on content signals and purpose |
| Recommended density | Based on length and complexity |
### 2.2 Extract Core Arguments
- Main thesis
- Key concepts reader needs
- Comparisons/contrasts
- Framework/model proposed
**CRITICAL**: If article uses metaphors (e.g., "电锯切西瓜"), do NOT illustrate literally. Visualize the **underlying concept**.
### 2.3 Identify Positions
**Illustrate**:
- Core arguments (REQUIRED)
- Abstract concepts
- Data comparisons
- Processes, workflows
**Do NOT Illustrate**:
- Metaphors literally
- Decorative scenes
- Generic illustrations
### 2.4 Analyze Reference Images (if provided in Step 1.0)
For each reference image:
| Analysis | Description |
|----------|-------------|
| Visual characteristics | Style, colors, composition |
| Content/subject | What the reference depicts |
| Suitable positions | Which sections match this reference |
| Style match | Which illustration types/styles align |
| Usage recommendation | `direct` / `style` / `palette` |
| Usage | When to Use |
|-------|-------------|
| `direct` | Reference matches desired output closely |
| `style` | Extract visual style characteristics only |
| `palette` | Extract color scheme only |
---
## Step 3: Confirm Settings ⚠️
**Do NOT skip.** Use ONE AskUserQuestion call with max 4 questions. **Q1, Q2, Q3 are ALL REQUIRED.**
### Q1: Illustration Type ⚠️ REQUIRED
- [Recommended based on analysis] (Recommended)
- infographic / scene / flowchart / comparison / framework / timeline / mixed
### Q2: Density ⚠️ REQUIRED - DO NOT SKIP
- minimal (1-2) - Core concepts only
- balanced (3-5) - Major sections
- per-section - At least 1 per section/chapter (Recommended)
- rich (6+) - Comprehensive coverage
### Q3: Style ⚠️ REQUIRED (ALWAYS ask, even with preferred_style in EXTEND.md)
If EXTEND.md has `preferred_style`:
- [Custom style name + brief description] (Recommended)
- [Top compatible core style 1]
- [Top compatible core style 2]
- Other (see full Style Gallery)
If no `preferred_style` (present Core Styles first):
- [Best compatible core style] (Recommended)
- [Other compatible core style 1]
- [Other compatible core style 2]
- Other (see full Style Gallery)
**Core Styles** (simplified selection):
| Core Style | Best For |
|------------|----------|
| `minimal-flat` | General, knowledge sharing, SaaS |
| `sci-fi` | AI, frontier tech, system design |
| `hand-drawn` | Relaxed, reflective, casual |
| `editorial` | Processes, data, journalism |
| `scene` | Narratives, emotional, lifestyle |
Style selection based on Type × Style compatibility matrix (styles.md).
Full specs: `styles/<style>.md`
### Q4: Image Text Language ⚠️ REQUIRED when article language ≠ EXTEND.md `language`
Detect article language from content. If different from EXTEND.md `language` setting, MUST ask:
- Article language (match article content) (Recommended)
- EXTEND.md language (user's general preference)
**Skip only if**: Article language matches EXTEND.md `language`, or EXTEND.md has no `language` setting.
### Display Reference Usage (if references detected in Step 1.0)
When presenting outline preview to user, show reference assignments:
```
Reference Images:
| Ref | Filename | Recommended Usage |
|-----|----------|-------------------|
| 01 | 01-ref-diagram.png | direct → Illustration 1, 3 |
| 02 | 02-ref-chart.png | palette → Illustration 2 |
```
---
## Step 4: Generate Outline
Save as `outline.md`:
```yaml
---
type: infographic
density: balanced
style: blueprint
image_count: 4
references: # Only if references provided
- ref_id: 01
filename: 01-ref-diagram.png
description: "Technical diagram showing system architecture"
- ref_id: 02
filename: 02-ref-chart.png
description: "Color chart with brand palette"
---
## Illustration 1
**Position**: [section] / [paragraph]
**Purpose**: [why this helps]
**Visual Content**: [what to show]
**Type Application**: [how type applies]
**References**: [01] # Optional: list ref_ids used
**Reference Usage**: direct # direct | style | palette
**Filename**: 01-infographic-concept-name.png
## Illustration 2
...
```
**Requirements**:
- Each position justified by content needs
- Type applied consistently
- Style reflected in descriptions
- Count matches density
- References assigned based on Step 2.4 analysis
---
## Step 5: Generate Images
### 5.1 Create Prompts
Follow [prompt-construction.md](prompt-construction.md). Save to `prompts/illustration-{slug}.md`.
- **Backup rule**: If prompt file exists, rename to `prompts/illustration-{slug}-backup-YYYYMMDD-HHMMSS.md`
**CRITICAL - References in Frontmatter**:
- Only add `references` field if files ACTUALLY EXIST in `references/` directory
- If style/palette was extracted verbally (no file), append info to prompt BODY instead
- Before writing frontmatter, verify: `test -f references/NN-ref-{slug}.png`
### 5.2 Select Generation Skill
Check available skills. If multiple, ask user.
### 5.3 Process References ⚠️ REQUIRED if references saved in Step 1.0
**DO NOT SKIP if user provided reference images.** For each illustration with references:
1. **VERIFY files exist first**:
```bash
test -f references/NN-ref-{slug}.png && echo "exists" || echo "MISSING"
```
- If file MISSING but in frontmatter → ERROR, fix frontmatter or remove references field
- If file exists → proceed with processing
2. Read prompt frontmatter for reference info
3. Process based on usage type:
| Usage | Action | Example |
|-------|--------|---------|
| `direct` | Add reference path to `--ref` parameter | `--ref references/01-ref-brand.png` |
| `style` | Analyze reference, append style traits to prompt | "Style: clean lines, gradient backgrounds..." |
| `palette` | Extract colors from reference, append to prompt | "Colors: #E8756D coral, #7ECFC0 mint..." |
4. Check image generation skill capability:
| Skill Supports `--ref` | Action |
|------------------------|--------|
| Yes (e.g., baoyu-image-gen with Google) | Pass reference images via `--ref` |
| No | Convert to text description, append to prompt |
**Verification**: Before generating, confirm reference processing:
```
Reference Processing:
- Illustration 1: using 01-ref-brand.png (direct) ✓
- Illustration 2: extracted palette from 02-ref-style.png ✓
```
### 5.4 Apply Watermark (if enabled)
Add: `Include a subtle watermark "[content]" at [position].`
### 5.5 Generate
1. For each illustration:
- **Backup rule**: If image file exists, rename to `NN-{type}-{slug}-backup-YYYYMMDD-HHMMSS.md`
- If references with `direct` usage: include `--ref` parameter
- Generate image
2. After each: "Generated X/N"
3. On failure: retry once, then log and continue
---
## Step 6: Finalize
### 6.1 Update Article
Insert after corresponding paragraph:
```markdown
![description](illustrations/{slug}/NN-{type}-{slug}.png)
```
Alt text: concise description in article's language.
### 6.2 Output Summary
```
Article Illustration Complete!
Article: [path]
Type: [type] | Density: [level] | Style: [style]
Location: [directory]
Images: X/N generated
Positions:
- 01-xxx.png → After "[Section]"
- 02-yyy.png → After "[Section]"
[If failures]
Failed:
- NN-zzz.png: [reason]
```
+28 -4
View File
@@ -153,7 +153,11 @@ Technical terms remain in English.
``` ```
Comic Progress: Comic Progress:
- [ ] Step 1: Setup & Analyze (1.1 Preferences, 1.2 Analyze, 1.3 Check existing) - [ ] Step 1: Setup & Analyze
- [ ] 1.1 Preferences (EXTEND.md) ⛔ BLOCKING
- [ ] Found → load preferences → continue
- [ ] Not found → run first-time setup → MUST complete before other steps
- [ ] 1.2 Analyze, 1.3 Check existing
- [ ] Step 2: Confirmation - Style & options ⚠️ REQUIRED - [ ] Step 2: Confirmation - Style & options ⚠️ REQUIRED
- [ ] Step 3: Generate storyboard + characters - [ ] Step 3: Generate storyboard + characters
- [ ] Step 4: Review outline (conditional) - [ ] Step 4: Review outline (conditional)
@@ -169,14 +173,22 @@ Comic Progress:
### Flow ### Flow
``` ```
Input → Preferences → Analyze → [Check Existing?] → [Confirm: Style + Reviews] → Storyboard → [Review?] → Prompts → [Review?] → Images → PDF → Complete Input → [Preferences] ─┬─ Found → Continue
└─ Not found → First-Time Setup ⛔ BLOCKING
└─ Complete setup → Save EXTEND.md → Continue
┌─────────────────────────────────────────────────────────────────────┘
Analyze → [Check Existing?] → [Confirm: Style + Reviews] → Storyboard → [Review?] → Prompts → [Review?] → Images → PDF → Complete
``` ```
### Step Summary ### Step Summary
| Step | Action | Key Output | | Step | Action | Key Output |
|------|--------|------------| |------|--------|------------|
| 1.1 | Load EXTEND.md preferences | Config loaded | | 1.1 | Load EXTEND.md preferences ⛔ BLOCKING if not found | Config loaded |
| 1.2 | Analyze content | `analysis.md` | | 1.2 | Analyze content | `analysis.md` |
| 1.3 | Check existing directory | Handle conflicts | | 1.3 | Check existing directory | Handle conflicts |
| 2 | Confirm style, focus, audience, reviews | User preferences | | 2 | Confirm style, focus, audience, reviews | User preferences |
@@ -194,6 +206,7 @@ Input → Preferences → Analyze → [Check Existing?] → [Confirm: Style + Re
**Character reference is MANDATORY for visual consistency.** **Character reference is MANDATORY for visual consistency.**
**7.1 Generate character sheet first**: **7.1 Generate character sheet first**:
- **Backup rule**: If `characters/characters.png` exists, rename to `characters/characters-backup-YYYYMMDD-HHMMSS.png`
```bash ```bash
# Use Reference Sheet Prompt from characters/characters.md # Use Reference Sheet Prompt from characters/characters.md
npx -y bun ${SKILL_DIR}/../baoyu-image-gen/scripts/main.ts \ npx -y bun ${SKILL_DIR}/../baoyu-image-gen/scripts/main.ts \
@@ -214,6 +227,10 @@ Compress to reduce token usage when used as reference image:
| Supports `--ref` | Pass `characters/characters.png` with EVERY page | | Supports `--ref` | Pass `characters/characters.png` with EVERY page |
| No `--ref` support | Prepend character descriptions to EVERY prompt file | | No `--ref` support | Prepend character descriptions to EVERY prompt file |
**Backup rules for page generation**:
- If prompt file exists: rename to `prompts/NN-{cover|page}-[slug]-backup-YYYYMMDD-HHMMSS.md`
- If image file exists: rename to `NN-{cover|page}-[slug]-backup-YYYYMMDD-HHMMSS.png`
```bash ```bash
# Example: ALWAYS include --ref for consistency # Example: ALWAYS include --ref for consistency
npx -y bun ${SKILL_DIR}/../baoyu-image-gen/scripts/main.ts \ npx -y bun ${SKILL_DIR}/../baoyu-image-gen/scripts/main.ts \
@@ -224,13 +241,20 @@ npx -y bun ${SKILL_DIR}/../baoyu-image-gen/scripts/main.ts \
**Full workflow details**: [references/workflow.md](references/workflow.md) **Full workflow details**: [references/workflow.md](references/workflow.md)
### EXTEND.md Paths ### EXTEND.md Paths ⛔ BLOCKING
**CRITICAL**: If EXTEND.md not found, MUST complete first-time setup before ANY other questions or steps. Do NOT proceed to content analysis, do NOT ask about art style, do NOT ask about tone — ONLY complete the preferences setup first.
| Path | Location | | Path | Location |
|------|----------| |------|----------|
| `.baoyu-skills/baoyu-comic/EXTEND.md` | Project directory | | `.baoyu-skills/baoyu-comic/EXTEND.md` | Project directory |
| `$HOME/.baoyu-skills/baoyu-comic/EXTEND.md` | User home | | `$HOME/.baoyu-skills/baoyu-comic/EXTEND.md` | User home |
| Result | Action |
|--------|--------|
| Found | Read, parse, display summary → Continue |
| Not found | ⛔ **BLOCKING**: Run first-time setup ONLY ([references/config/first-time-setup.md](references/config/first-time-setup.md)) → Complete and save EXTEND.md → Then continue |
**EXTEND.md Supports**: Watermark | Preferred art/tone/layout | Custom style definitions | Character presets | Language preference **EXTEND.md Supports**: Watermark | Preferred art/tone/layout | Custom style definitions | Character presets | Language preference
Schema: [references/config/preferences-schema.md](references/config/preferences-schema.md) Schema: [references/config/preferences-schema.md](references/config/preferences-schema.md)
@@ -9,6 +9,14 @@ description: First-time setup flow for baoyu-comic preferences
When no EXTEND.md is found, guide user through preference setup. When no EXTEND.md is found, guide user through preference setup.
**⛔ BLOCKING OPERATION**: This setup MUST complete before ANY other workflow steps. Do NOT:
- Ask about content/source material
- Ask about art style or tone
- Ask about layout preferences
- Proceed to content analysis
ONLY ask the questions in this setup flow, save EXTEND.md, then continue.
## Setup Flow ## Setup Flow
``` ```
+9 -5
View File
@@ -84,6 +84,7 @@ Read source content, save it if needed, and perform deep analysis.
1. **Save source content** (if not already a file): 1. **Save source content** (if not already a file):
- If user provides a file path: use as-is - If user provides a file path: use as-is
- If user pastes content: save to `source.md` in target directory - If user pastes content: save to `source.md` in target directory
- **Backup rule**: If `source.md` exists, rename to `source-backup-YYYYMMDD-HHMMSS.md`
2. Read source content 2. Read source content
3. **Deep analysis** following `analysis-framework.md`: 3. **Deep analysis** following `analysis-framework.md`:
- Target audience identification - Target audience identification
@@ -329,6 +330,7 @@ Create image generation prompts for all pages.
1. Create prompt following art style + tone guidelines 1. Create prompt following art style + tone guidelines
2. Include character visual descriptions for consistency 2. Include character visual descriptions for consistency
3. Save to `prompts/NN-{cover|page}-[slug].md` 3. Save to `prompts/NN-{cover|page}-[slug].md`
- **Backup rule**: If prompt file exists, rename to `prompts/NN-{cover|page}-[slug]-backup-YYYYMMDD-HHMMSS.md`
**Prompt File Format**: **Prompt File Format**:
```markdown ```markdown
@@ -405,8 +407,9 @@ With confirmed prompts from Step 5/6:
### 7.1 Generate Character Reference Sheet (first) ### 7.1 Generate Character Reference Sheet (first)
1. Use Reference Sheet Prompt from `characters/characters.md` 1. Use Reference Sheet Prompt from `characters/characters.md`
2. Generate → `characters/characters.png` 2. **Backup rule**: If `characters/characters.png` exists, rename to `characters/characters-backup-YYYYMMDD-HHMMSS.png`
3. This ensures visual consistency for all subsequent pages 3. Generate → `characters/characters.png`
4. This ensures visual consistency for all subsequent pages
### 7.2 Generate Comic Pages ### 7.2 Generate Comic Pages
@@ -453,9 +456,10 @@ When skill does NOT support reference images, create combined prompt files:
**For each page (cover + pages)**: **For each page (cover + pages)**:
1. Read prompt from `prompts/NN-{cover|page}-[slug].md` 1. Read prompt from `prompts/NN-{cover|page}-[slug].md`
2. Generate image using Strategy A or B (based on skill capability) 2. **Backup rule**: If image file exists, rename to `NN-{cover|page}-[slug]-backup-YYYYMMDD-HHMMSS.png`
3. Save to `NN-{cover|page}-[slug].png` 3. Generate image using Strategy A or B (based on skill capability)
4. Report progress after each generation: "Generated X/N: [page title]" 4. Save to `NN-{cover|page}-[slug].png`
5. Report progress after each generation: "Generated X/N: [page title]"
**Session Management**: **Session Management**:
If image generation skill supports `--sessionId`: If image generation skill supports `--sessionId`:
+225 -18
View File
@@ -1,6 +1,6 @@
--- ---
name: baoyu-cover-image name: baoyu-cover-image
description: Generates article cover images with 5 dimensions (type, palette, rendering, text, mood) combining 9 color palettes and 6 rendering styles. Supports cinematic (2.35:1), widescreen (16:9), and square (1:1) aspects. Use when user asks to "generate cover image", "create article cover", "make cover", or mentions "封面图". description: Generates article cover images with 5 dimensions (type, palette, rendering, text, mood) combining 9 color palettes and 6 rendering styles. Supports cinematic (2.35:1), widescreen (16:9), and square (1:1) aspects. Use when user asks to "generate cover image", "create article cover", or "make cover".
--- ---
# Cover Image Generator # Cover Image Generator
@@ -34,6 +34,10 @@ Generate elegant cover images for articles with 5-dimensional customization.
# Direct input with options # Direct input with options
/baoyu-cover-image --palette mono --rendering digital --aspect 1:1 --quick /baoyu-cover-image --palette mono --rendering digital --aspect 1:1 --quick
[paste content] [paste content]
# With reference images
/baoyu-cover-image article.md --ref style-ref.png
/baoyu-cover-image article.md --ref ref1.png ref2.png --quick
``` ```
## Options ## Options
@@ -50,6 +54,7 @@ Generate elegant cover images for articles with 5-dimensional customization.
| `--lang <code>` | Title language (en, zh, ja, etc.) | | `--lang <code>` | Title language (en, zh, ja, etc.) |
| `--no-title` | Alias for `--text none` | | `--no-title` | Alias for `--text none` |
| `--quick` | Skip confirmation, use auto-selection for missing dimensions | | `--quick` | Skip confirmation, use auto-selection for missing dimensions |
| `--ref <files...>` | Reference images for style/composition guidance |
## Five Dimensions ## Five Dimensions
@@ -110,8 +115,8 @@ Rendering definitions: [references/renderings/](references/renderings/)
| Text Level | Title | Subtitle | Tags | Use Case | | Text Level | Title | Subtitle | Tags | Use Case |
|------------|:-----:|:--------:|:----:|----------| |------------|:-----:|:--------:|:----:|----------|
| `none` | - | - | - | Pure visual, no text | | `none` | - | - | - | Pure visual, no text |
| `title-only` | ✓ (≤8 字) | - | - | Simple headline (default) | | `title-only` | ✓ | - | - | Simple headline (default) |
| `title-subtitle` | ✓ | ✓ (≤15 字) | - | Title + supporting context | | `title-subtitle` | ✓ | ✓ | - | Title + supporting context |
| `text-rich` | ✓ | ✓ | ✓ (2-4) | Information-dense | | `text-rich` | ✓ | ✓ | ✓ (2-4) | Information-dense |
| Mood | Contrast | Saturation | Weight | Use Case | | Mood | Contrast | Saturation | Weight | Use Case |
@@ -142,6 +147,12 @@ Output directory depends on `default_output_dir` preference:
``` ```
<output-dir>/ <output-dir>/
├── source-{slug}.{ext} # Source files (text, images, etc.) ├── source-{slug}.{ext} # Source files (text, images, etc.)
├── refs/ # Reference images (if provided)
│ ├── ref-01-{slug}.{ext}
│ ├── ref-01-{slug}.md # Description file (optional)
│ ├── ref-02-{slug}.{ext}
│ ├── ref-02-{slug}.md # Description file (optional)
│ └── extracted-style.md # Verbally extracted style (if no file path)
├── prompts/cover.md # Generation prompt ├── prompts/cover.md # Generation prompt
└── cover.png # Output image └── cover.png # Output image
``` ```
@@ -156,25 +167,45 @@ Output directory depends on `default_output_dir` preference:
``` ```
Cover Image Progress: Cover Image Progress:
- [ ] Step 0: Check preferences (EXTEND.md) ⚠️ REQUIRED if not found - [ ] Step 0: Check preferences (EXTEND.md) ⛔ BLOCKING
- [ ] Step 1: Analyze content + determine output directory ⚠️ MUST ask if not configured - [ ] Found → load preferences → continue
- [ ] Not found → run first-time setup → MUST complete before Step 1
- [ ] Step 1: Analyze content + determine output directory
- [ ] 1.1 Reference images ⚠️ (if provided)
- [ ] File path given → saved to refs/ ✓
- [ ] No path → asked user OR extracted verbally
- [ ] 1.2 Output directory determined
- [ ] Step 2: Confirm options (5 dimensions) ⚠️ REQUIRED unless --quick or all specified - [ ] Step 2: Confirm options (5 dimensions) ⚠️ REQUIRED unless --quick or all specified
- [ ] Step 3: Create prompt - [ ] Step 3: Create prompt
- [ ] References in prompt ONLY if files exist in refs/
- [ ] Extracted style/palette appended to prompt body (if no file)
- [ ] Step 4: Generate image - [ ] Step 4: Generate image
- [ ] 4.1 References verified before generation
- [ ] 4.2 Pass refs via --ref if skill supports AND files exist
- [ ] Step 5: Completion report - [ ] Step 5: Completion report
``` ```
### Flow ### Flow
``` ```
Input → [Step 0: Preferences/Setup] → Analyze → [Output Dir ⚠️][Confirm: 5 Dimensions] → Prompt → Generate → Complete Input → [Step 0: Preferences] ─┬─ Found → Continue
└─ Not found → First-Time Setup ⛔ BLOCKING
└─ Complete setup → Save EXTEND.md → Continue
┌───────────────────────────────────────────────────────────────────────────┘
Analyze + Save Refs → [Output Dir ⚠️] → [Confirm: 5 Dimensions] → Prompt → Generate → Complete
(skip if --quick or all specified) (skip if --quick or all specified)
``` ```
### Step 0: Load Preferences (EXTEND.md) ⚠️ ### Step 0: Load Preferences (EXTEND.md) ⛔ BLOCKING
**Purpose**: Load user preferences or run first-time setup. **Do NOT skip setup if EXTEND.md not found.** **Purpose**: Load user preferences or run first-time setup.
**CRITICAL**: If EXTEND.md not found, MUST complete first-time setup before ANY other questions or steps. Do NOT proceed to content analysis, do NOT ask about reference images, do NOT ask about dimensions — ONLY complete the preferences setup first.
Use Bash to check EXTEND.md existence (priority order): Use Bash to check EXTEND.md existence (priority order):
@@ -189,7 +220,7 @@ test -f "$HOME/.baoyu-skills/baoyu-cover-image/EXTEND.md" && echo "user"
| Result | Action | | Result | Action |
|--------|--------| |--------|--------|
| Found | Read, parse, display preferences summary → Continue to Step 1 | | Found | Read, parse, display preferences summary → Continue to Step 1 |
| Not found | ⚠️ MUST run first-time setup ([references/config/first-time-setup.md](references/config/first-time-setup.md)) → Then continue to Step 1 | | Not found | **BLOCKING**: Run first-time setup ONLY ([references/config/first-time-setup.md](references/config/first-time-setup.md)) → Complete and save EXTEND.md → Then continue to Step 1 |
**Preferences Summary** (when found): **Preferences Summary** (when found):
@@ -208,10 +239,90 @@ Schema: [references/config/preferences-schema.md](references/config/preferences-
### Step 1: Analyze Content ### Step 1: Analyze Content
1. **Save source content** (if pasted, save to `source.md` in target directory; if file path, use as-is) **1.0 Detect & Save Reference Images** ⚠️ REQUIRED if images provided
2. **Content analysis**: Extract topic, core message, tone, keywords; identify visual metaphors; detect content type
3. **Language detection**: Detect source language, note user's input language, compare with EXTEND.md preference Check if user provided reference images. Handle based on input type:
4. **Determine output directory** per File Structure rules. If no `default_output_dir` preference + file path input, include in Step 2 Q4
| Input Type | Action |
|------------|--------|
| Image file path provided | Copy to `refs/` subdirectory → can use `--ref` |
| Image in conversation (no path) | **ASK user for file path** with AskUserQuestion |
| User can't provide path | Extract style/palette verbally → append to prompt (NO frontmatter references) |
**CRITICAL**: Only add `references` to prompt frontmatter if files are ACTUALLY SAVED to `refs/` directory.
**If user provides file path**:
1. Copy to `refs/ref-NN-{slug}.{ext}` (NN = 01, 02, ...)
2. Create description: `refs/ref-NN-{slug}.md`
3. Verify files exist before proceeding
**If user can't provide path** (extracted verbally):
1. Analyze image visually, extract: colors, style, composition
2. Create `refs/extracted-style.md` with extracted info
3. DO NOT add `references` to prompt frontmatter
4. Instead, append extracted style/colors directly to prompt text
**Description File Format** (only when file saved):
```yaml
---
ref_id: NN
filename: ref-NN-{slug}.{ext}
usage: direct | style | palette
---
[User's description or auto-generated description]
```
| Usage | When to Use |
|-------|-------------|
| `direct` | Reference matches desired output closely |
| `style` | Extract visual style characteristics only |
| `palette` | Extract color scheme only |
**Verification** (only for saved files):
```
Reference Images Saved:
- ref-01-{slug}.png ✓ (can use --ref)
- ref-02-{slug}.png ✓ (can use --ref)
```
**Or for extracted style**:
```
Reference Style Extracted (no file):
- Colors: #E8756D coral, #7ECFC0 mint...
- Style: minimal flat vector, clean lines...
→ Will append to prompt text (not --ref)
```
---
**1.1 Save Source Content**
- If pasted, save to `source.md` in target directory; if file path, use as-is
- **Backup rule**: If `source.md` exists, rename to `source-backup-YYYYMMDD-HHMMSS.md`
**1.2 Content Analysis**
- Extract topic, core message, tone, keywords
- Identify visual metaphors
- Detect content type
**1.3 Reference Image Analysis** (if provided in Step 1.0)
For each reference image:
| Analysis | Description |
|----------|-------------|
| Visual characteristics | Style, colors, composition |
| Content/subject | What the reference depicts |
| Style match | Which type/palette/rendering align |
| Usage recommendation | `direct` / `style` / `palette` |
**1.4 Language Detection**
- Detect source language
- Note user's input language
- Compare with EXTEND.md preference
**1.5 Determine Output Directory**
- Per File Structure rules
- If no `default_output_dir` preference + file path input, include in Step 2 Q4
### Step 2: Confirm Options ⚠️ ### Step 2: Confirm Options ⚠️
@@ -226,14 +337,92 @@ Validate all 5 dimensions + aspect ratio. Full confirmation flow: [references/wo
### Step 3: Create Prompt ### Step 3: Create Prompt
**Backup rule**: If `prompts/cover.md` exists, rename to `prompts/cover-backup-YYYYMMDD-HHMMSS.md`
Save to `prompts/cover.md`. Full template: [references/workflow/prompt-template.md](references/workflow/prompt-template.md) Save to `prompts/cover.md`. Full template: [references/workflow/prompt-template.md](references/workflow/prompt-template.md)
**CRITICAL - References in YAML Frontmatter**:
When reference files are saved to `refs/`, **MUST add `references` field in frontmatter**:
```yaml
---
type: cover
palette: warm
rendering: flat-vector
references:
- ref_id: 01
filename: refs/ref-01-podcast-thumbnail.jpg
usage: style
---
```
| Rule | Action |
|------|--------|
| Files saved to `refs/` | Add to frontmatter `references` list |
| Style extracted verbally (no file) | Omit `references` field, describe in body |
| Before writing | Verify: `test -f refs/ref-NN-{slug}.{ext}` |
**Reference Embedding**:
| Situation | Frontmatter | Body |
|-----------|-------------|------|
| Reference file saved to `refs/` | Add to `references` ✓ | Brief style note |
| Style extracted verbally (no file) | Omit `references` | Full style description |
| File in frontmatter but doesn't exist | ERROR - fix or remove | — |
### Step 4: Generate Image ### Step 4: Generate Image
1. Backup existing `cover.png``cover-backup-YYYYMMDD-HHMMSS.png` (if regenerating) **4.1 Backup existing** `cover.png``cover-backup-YYYYMMDD-HHMMSS.png` (if regenerating)
2. Check available image generation skills; if multiple, ask user preference
3. Call selected skill with prompt file path, output path (`cover.png`), aspect ratio **4.2 Check available image generation skills**; if multiple, ask user preference
4. On failure: auto-retry once before reporting error
**4.3 Process References** ⚠️ REQUIRED if references in frontmatter
**Read `references` from prompt frontmatter** and process each entry:
1. **Parse frontmatter** to get references list:
```yaml
references:
- ref_id: 01
filename: refs/ref-01-podcast-thumbnail.jpg
usage: style
```
2. **VERIFY each file exists**:
```bash
test -f refs/ref-NN-{slug}.{ext} && echo "exists" || echo "MISSING"
```
- If file MISSING → ERROR, fix prompt or remove from references
- If file exists → proceed with processing
3. Process based on `usage` type:
| Usage | Action | Example |
|-------|--------|---------|
| `direct` | Add reference path to `--ref` parameter | `--ref refs/ref-01-brand.png` |
| `style` | Analyze reference, append style traits to prompt | "Style: clean lines, gradient backgrounds..." |
| `palette` | Extract colors from reference, append to prompt | "Colors: #E8756D coral, #7ECFC0 mint..." |
3. Check image generation skill capability:
| Skill Supports `--ref` | Action |
|------------------------|--------|
| Yes (e.g., baoyu-image-gen with Google) | Pass reference images via `--ref` |
| No | Convert to text description, append to prompt |
**Verification**: Before generating, confirm reference processing:
```
Reference Processing:
- ref-01-brand.png: using as direct reference ✓
- ref-02-style.png: extracted palette ✓
```
**4.4 Generate**
1. Call selected skill with prompt file path, output path (`cover.png`), aspect ratio
2. If references with `direct` usage AND skill supports `--ref`: include `--ref` parameter
3. On failure: auto-retry once before reporting error
### Step 5: Completion Report ### Step 5: Completion Report
@@ -245,10 +434,14 @@ Type: [type] | Palette: [palette] | Rendering: [rendering]
Text: [text] | Mood: [mood] | Aspect: [ratio] Text: [text] | Mood: [mood] | Aspect: [ratio]
Title: [title text or "visual only"] Title: [title text or "visual only"]
Language: [lang] | Watermark: [enabled/disabled] Language: [lang] | Watermark: [enabled/disabled]
References: [N images (direct/style/palette) or "extracted style" or "none"]
Location: [directory path] Location: [directory path]
Files: Files:
✓ source-{slug}.{ext} ✓ source-{slug}.{ext}
[✓ refs/ref-01-{slug}.{ext} ... (if references saved)]
[✓ refs/ref-01-{slug}.md ... (description files)]
[✓ refs/extracted-style.md (if style extracted verbally)]
✓ prompts/cover.md ✓ prompts/cover.md
✓ cover.png ✓ cover.png
[✓ cover-backup-{timestamp}.png (if regenerated)] [✓ cover-backup-{timestamp}.png (if regenerated)]
@@ -269,7 +462,7 @@ All modifications automatically backup existing `cover.png` before regenerating.
- Cover must be readable at small preview sizes - Cover must be readable at small preview sizes
- Visual metaphors > literal representations - Visual metaphors > literal representations
- Title: max 8 chars, readable, impactful - Title: readable, impactful
- Two confirmation points: Step 0 (first-time setup) + Step 2 (options) - skip Step 2 with `--quick` - Two confirmation points: Step 0 (first-time setup) + Step 2 (options) - skip Step 2 with `--quick`
- Use confirmed language for title text - Use confirmed language for title text
- Maintain watermark consistency if enabled - Maintain watermark consistency if enabled
@@ -277,6 +470,19 @@ All modifications automatically backup existing `cover.png` before regenerating.
- `--no-title` is alias for `--text none` - `--no-title` is alias for `--text none`
- `--style` presets are backward-compatible; explicit `--palette`/`--rendering` override preset values - `--style` presets are backward-compatible; explicit `--palette`/`--rendering` override preset values
### Composition Principles
- **Generous whitespace**: 40-60% breathing room; avoid cluttered layouts
- **Visual anchor**: Main element centered or offset left (reserve right for title)
- **Character handling**: Simplified silhouettes or icon-style figures; NO realistic humans
- **Icon vocabulary**: Use simple, recognizable symbols (see [references/visual-elements.md](references/visual-elements.md))
### Title Handling
- **Source**: Use the exact title provided by user, or extract from source content
- **Do NOT invent titles**: Stay faithful to the original
- If no title in source and user doesn't provide one, ask user to specify
## References ## References
**Dimensions**: [text.md](references/dimensions/text.md) | [mood.md](references/dimensions/mood.md) **Dimensions**: [text.md](references/dimensions/text.md) | [mood.md](references/dimensions/mood.md)
@@ -286,5 +492,6 @@ All modifications automatically backup existing `cover.png` before regenerating.
**Style Presets**: [references/style-presets.md](references/style-presets.md) **Style Presets**: [references/style-presets.md](references/style-presets.md)
**Compatibility**: [references/compatibility.md](references/compatibility.md) **Compatibility**: [references/compatibility.md](references/compatibility.md)
**Types**: [references/types.md](references/types.md) **Types**: [references/types.md](references/types.md)
**Visual Elements**: [references/visual-elements.md](references/visual-elements.md)
**Workflow**: [confirm-options.md](references/workflow/confirm-options.md) | [prompt-template.md](references/workflow/prompt-template.md) **Workflow**: [confirm-options.md](references/workflow/confirm-options.md) | [prompt-template.md](references/workflow/prompt-template.md)
**Config**: [preferences-schema.md](references/config/preferences-schema.md) | [first-time-setup.md](references/config/first-time-setup.md) | [watermark-guide.md](references/config/watermark-guide.md) **Config**: [preferences-schema.md](references/config/preferences-schema.md) | [first-time-setup.md](references/config/first-time-setup.md) | [watermark-guide.md](references/config/watermark-guide.md)
@@ -39,8 +39,8 @@ Apply the specified rendering's characteristics:
### Text (Density Level) ### Text (Density Level)
- `none`: No text elements, full visual area - `none`: No text elements, full visual area
- `title-only`: Single headline (≤8 characters), 85% visual area - `title-only`: Single headline, 85% visual area
- `title-subtitle`: Title + context (≤15 chars), 75% visual area - `title-subtitle`: Title + context, 75% visual area
- `text-rich`: Title + subtitle + 2-4 keyword tags, 60% visual area - `text-rich`: Title + subtitle + 2-4 keyword tags, 60% visual area
### Mood (Emotional Intensity) ### Mood (Emotional Intensity)
@@ -50,17 +50,44 @@ Apply the specified rendering's characteristics:
## Text Style (When Title Included) ## Text Style (When Title Included)
- Title text: Large, eye-catching, max 8 characters - **Title source**: Use the exact title provided by user, or extract from source content. Do NOT invent or modify titles.
- Subtitle: Secondary, max 15 characters (if title-subtitle or text-rich) - Title text: Large, eye-catching, faithful to source
- Subtitle: Secondary element (if title-subtitle or text-rich)
- Tags: 2-4 keyword badges (if text-rich) - Tags: 2-4 keyword badges (if text-rich)
- Font style harmonizes with rendering style - Font style harmonizes with rendering style
- **Engagement hooks**: Use numbers ("3个关键"), questions ("Why?"), contrasts ("A vs B"), pain points ("别再X了"), or suspense ("隐藏的X") for compelling titles
## Composition Guidance ## Composition Guidance
**Icon Vocabulary**: Represent concepts with simple, recognizable icons rather than detailed illustrations. Use the rendering style to determine icon complexity (flat-vector = geometric, hand-drawn = sketchy, etc.) ### Layout Principles
**Character Handling**: When people are needed, use simplified silhouettes or abstract representations. NO realistic faces, detailed anatomy, or photographic representations. - **Generous whitespace**: Maintain 40-60% breathing room; avoid cluttered compositions
- **Visual anchor placement**: Main element centered or offset left (reserve right side for title if included)
- **Information hierarchy**: One dominant focal point, 1-2 supporting elements, decorative accents
- **Clean backgrounds**: Solid colors or subtle gradients; no complex textures or patterns
### Icon & Symbol Vocabulary
Represent concepts with simple, recognizable icons rather than detailed illustrations:
| Category | Examples |
|----------|----------|
| Tech | Code window, gear, circuit, cloud, lock, API brackets |
| Ideas | Lightbulb, rocket, target, puzzle, key, magnifier |
| Communication | Speech bubble, chat dots, megaphone, mail |
| Growth | Plant/sprout, tree, arrow, chart, mountain |
| Tools | Wrench, pencil, brush, checklist, clock |
Use the rendering style to determine icon complexity (flat-vector = geometric, hand-drawn = sketchy, etc.)
Full library: [references/visual-elements.md](visual-elements.md)
### Character Handling
When people are needed:
- Use simplified silhouettes or abstract stick figures
- Symbolic representations (head + shoulders outline)
- NO realistic faces, detailed anatomy, or photographic representations
- Cartoon/icon style consistent with rendering choice
## Mood Application ## Mood Application
@@ -77,6 +104,16 @@ Apply mood adjustments to the base palette:
- Use the same language as the content provided below for any text elements - Use the same language as the content provided below for any text elements
- Match punctuation style to the content language - Match punctuation style to the content language
## Reference Images
When reference images are provided:
- **Style extraction**: Identify rendering technique, line quality, texture, and visual vocabulary
- **Composition learning**: Note layout patterns, whitespace usage, element placement
- **Mood matching**: Capture the emotional tone and visual weight
- **Adaptation**: Apply extracted characteristics while respecting the specified Type, Palette, and Rendering dimensions
- **Priority**: If reference style conflicts with specified dimensions, dimensions take precedence for structural choices; reference influences decorative details
--- ---
Please generate the cover image based on the content provided below: Please generate the cover image based on the content provided below:
@@ -9,6 +9,14 @@ description: First-time setup flow for baoyu-cover-image preferences
When no EXTEND.md is found, guide user through preference setup. When no EXTEND.md is found, guide user through preference setup.
**⛔ BLOCKING OPERATION**: This setup MUST complete before ANY other workflow steps. Do NOT:
- Ask about reference images
- Ask about content/article
- Ask about dimensions (type, palette, rendering)
- Proceed to content analysis
ONLY ask the questions in this setup flow, save EXTEND.md, then continue.
## Setup Flow ## Setup Flow
``` ```
@@ -103,8 +103,8 @@ custom_palettes:
| Value | Description | | Value | Description |
|-------|-------------| |-------|-------------|
| `none` | Pure visual, no text elements | | `none` | Pure visual, no text elements |
| `title-only` | Single headline (≤8 characters) | | `title-only` | Single headline |
| `title-subtitle` | Title + subtitle (≤15 characters) | | `title-subtitle` | Title + subtitle |
| `text-rich` | Title + subtitle + keyword tags (2-4) | | `text-rich` | Title + subtitle + keyword tags (2-4) |
## Mood Options ## Mood Options
@@ -12,8 +12,8 @@ Controls text density and information hierarchy on cover images.
| Value | Title | Subtitle | Tags | Visual Area | | Value | Title | Subtitle | Tags | Visual Area |
|-------|:-----:|:--------:|:----:|:-----------:| |-------|:-----:|:--------:|:----:|:-----------:|
| `none` | - | - | - | 100% | | `none` | - | - | - | 100% |
| `title-only` | ✓ (≤8字) | - | - | 85% | | `title-only` | ✓ | - | - | 85% |
| `title-subtitle` | ✓ | ✓ (≤15字) | - | 75% | | `title-subtitle` | ✓ | ✓ | - | 75% |
| `text-rich` | ✓ | ✓ | ✓ (2-4) | 60% | | `text-rich` | ✓ | ✓ | ✓ (2-4) | 60% |
## Detail ## Detail
@@ -43,24 +43,14 @@ Single headline, maximum impact.
- Strong brand recognition - Strong brand recognition
**Composition**: **Composition**:
- Title: ≤8 characters, prominent - Title: prominent placement
- Reserved zone: top or bottom 15% - Reserved zone: top or bottom 15%
- Visual supports title message - Visual supports title message
**Title Guidelines**: **Title Guidelines**:
- Punchy, action-oriented - Use exact title from source content or user-provided title
- Do NOT invent or modify titles
- Match content language - Match content language
- Use engagement hooks (see below)
**Engagement Hooks**:
| Hook Type | Examples (EN) | Examples (ZH) |
|-----------|---------------|---------------|
| Numbers | "3 Traps", "5 Keys" | "3个陷阱", "5个关键" |
| Questions | "Why X?", "How?" | "为什么X?", "怎么做?" |
| Contrasts | "A vs B", "Old→New" | "A还是B", "旧→新" |
| Pain Points | "Stop X", "Never Do" | "别再X了", "千万别" |
| Suspense | "Hidden X", "Secret" | "隐藏的X", "秘密" |
### title-subtitle ### title-subtitle
@@ -72,14 +62,14 @@ Title with supporting context.
- Content with dual messages - Content with dual messages
**Composition**: **Composition**:
- Title: ≤8 characters, primary - Title: primary element
- Subtitle: ≤15 characters, secondary - Subtitle: secondary element
- Reserved zone: 25% - Reserved zone: 25%
- Clear hierarchy between title/subtitle - Clear hierarchy between title/subtitle
**Title Guidelines**: **Title Guidelines**:
- Use engagement hooks: numbers, questions, contrasts, pain points, suspense - Use exact title from source content or user-provided title
- Punchy, action-oriented - Do NOT invent or modify titles
**Subtitle Guidelines**: **Subtitle Guidelines**:
- Clarify or contextualize title - Clarify or contextualize title
@@ -104,8 +94,8 @@ Information-dense cover with multiple text elements.
- Clear visual hierarchy - Clear visual hierarchy
**Title Guidelines**: **Title Guidelines**:
- Use engagement hooks: numbers, questions, contrasts, pain points, suspense - Use exact title from source content or user-provided title
- Punchy, action-oriented - Do NOT invent or modify titles
**Tag Guidelines**: **Tag Guidelines**:
- 2-4 tags maximum - 2-4 tags maximum
@@ -0,0 +1,101 @@
# Visual Elements Library
Icon and symbol vocabulary organized by topic. Use these as building blocks for cover compositions.
## Tech & Development
| Element | Use For |
|---------|---------|
| Code window / Terminal | Programming, development |
| Gear / Cog | Engineering, settings, process |
| Circuit board / Chip | Hardware, AI, computing |
| Binary / Data stream | Data, algorithms |
| API brackets `</>` | Web development, APIs |
| Cloud | Cloud computing, SaaS |
| Lock / Shield | Security, privacy |
| Network nodes | Distributed systems, connections |
## Ideas & Innovation
| Element | Use For |
|---------|---------|
| Lightbulb | Ideas, insights, innovation |
| Rocket | Launch, growth, startups |
| Target / Bullseye | Goals, precision, focus |
| Puzzle piece | Problem solving, integration |
| Key | Solutions, access, unlocking |
| Magnifying glass | Analysis, search, discovery |
| Chart / Graph | Data, trends, growth |
| Arrow / Path | Direction, journey, progress |
## Communication & Collaboration
| Element | Use For |
|---------|---------|
| Speech bubble | Communication, dialogue |
| Chat dots `...` | Conversation, messaging |
| Handshake | Partnership, agreement |
| Team / Figures | Collaboration, community |
| Mail / Envelope | Notifications, outreach |
| Megaphone | Announcements, marketing |
| Network / Web | Social, connections |
## Nature & Growth
| Element | Use For |
|---------|---------|
| Plant / Sprout | Growth, organic, sustainability |
| Tree | Established, structure, branching |
| Leaf | Eco, natural, fresh |
| Sun / Rays | Energy, positivity, new beginnings |
| Mountain | Challenge, achievement, scale |
| Wave | Flow, change, rhythm |
| Seed → Plant | Transformation, potential |
## Tools & Actions
| Element | Use For |
|---------|---------|
| Wrench / Hammer | Building, fixing, tools |
| Pencil / Pen | Writing, creation, editing |
| Brush | Design, creativity, art |
| Scissors | Cutting, editing, trimming |
| Clock / Timer | Time, scheduling, deadlines |
| Calendar | Planning, events, milestones |
| Checklist / Checkbox | Tasks, completion, validation |
## Abstract Concepts
| Element | Use For |
|---------|---------|
| Infinity ∞ | Continuous, endless, loops |
| Yin-yang | Balance, duality, harmony |
| Spiral | Evolution, recursion, cycles |
| Stack / Layers | Depth, hierarchy, structure |
| Bridge | Connection, transition, spanning |
| Door / Portal | Opportunity, entry, access |
| Mirror / Reflection | Self-improvement, analysis |
## Combination Patterns
Create visual metaphors by combining elements:
| Combination | Represents |
|-------------|------------|
| Lightbulb + Gear | Innovative engineering |
| Plant + Code | Organic tech growth |
| Rocket + Target | Precise acceleration |
| Key + Lock | Security solutions |
| Bridge + People | Team connections |
| Magnifier + Data | Analytics, insights |
## Rendering-Specific Treatment
| Rendering | Element Style |
|-----------|---------------|
| `flat-vector` | Geometric, simple shapes, uniform fills |
| `hand-drawn` | Sketchy, organic, doodle-like |
| `painterly` | Soft edges, brush strokes |
| `digital` | Precise, gradient hints, polished |
| `pixel` | 8-bit chunky, grid-aligned |
| `chalk` | Dusty, textured, board style |
@@ -3,6 +3,19 @@
Save to `prompts/cover.md`: Save to `prompts/cover.md`:
```markdown ```markdown
---
type: cover
palette: [confirmed palette]
rendering: [confirmed rendering]
references:
- ref_id: 01
filename: refs/ref-01-{slug}.{ext}
usage: direct | style | palette
- ref_id: 02
filename: refs/ref-02-{slug}.{ext}
usage: direct | style | palette
---
# Content Context # Content Context
Article title: [full original title from source] Article title: [full original title from source]
Content summary: [2-3 sentence summary of key points and themes] Content summary: [2-3 sentence summary of key points and themes]
@@ -21,9 +34,9 @@ Language: [confirmed language]
# Text Elements # Text Elements
[Based on text level:] [Based on text level:]
- none: "No text elements" - none: "No text elements"
- title-only: "Title: [max 8 chars headline]" - title-only: "Title: [exact title from source or user]"
- title-subtitle: "Title: [headline] / Subtitle: [max 15 chars context]" - title-subtitle: "Title: [title] / Subtitle: [context]"
- text-rich: "Title: [headline] / Subtitle: [context] / Tags: [2-4 keywords]" - text-rich: "Title: [title] / Subtitle: [context] / Tags: [2-4 keywords]"
# Mood Application # Mood Application
[Based on mood level:] [Based on mood level:]
@@ -46,6 +59,8 @@ Type notes: [key characteristics from type definition]
Palette notes: [key characteristics from palette definition] Palette notes: [key characteristics from palette definition]
[Watermark section if enabled] [Watermark section if enabled]
[Reference images section if provided — see below]
``` ```
## Content-Driven Design ## Content-Driven Design
@@ -54,6 +69,21 @@ Palette notes: [key characteristics from palette definition]
- Keywords guide decorative elements and symbols - Keywords guide decorative elements and symbols
- The skill controls visual style; the content drives meaning - The skill controls visual style; the content drives meaning
## Visual Element Selection
Match content themes to icon vocabulary:
| Content Theme | Suggested Elements |
|---------------|-------------------|
| Programming/Dev | Code window, terminal, API brackets, gear |
| AI/ML | Brain, neural network, robot, circuit |
| Growth/Business | Chart, rocket, plant, mountain, arrow |
| Security | Lock, shield, key, fingerprint |
| Communication | Speech bubble, megaphone, mail, handshake |
| Tools/Methods | Wrench, checklist, pencil, puzzle |
Full library: [../visual-elements.md](../visual-elements.md)
## Type-Specific Composition ## Type-Specific Composition
| Type | Composition Guidelines | | Type | Composition Guidelines |
@@ -68,8 +98,8 @@ Palette notes: [key characteristics from palette definition]
## Title Guidelines ## Title Guidelines
When text level includes title: When text level includes title:
- Max 8 characters, punchy headline - **Source**: Use the exact title provided by user, or extract from source content
- Use engagement hooks: numbers ("3个陷阱"), questions ("Why X?"), contrasts ("A vs B"), pain points ("别再X了") - **Do NOT invent titles**: Stay faithful to the original
- Match confirmed language - Match confirmed language
## Watermark Application ## Watermark Application
@@ -82,3 +112,118 @@ The watermark should be legible but not distracting from the main content.
``` ```
Reference: `config/watermark-guide.md` Reference: `config/watermark-guide.md`
## Reference Image Handling
When user provides reference images (`--ref` or pasted images):
### ⚠️ CRITICAL - Frontmatter References
**MUST add `references` field in YAML frontmatter** when reference files are saved to `refs/`:
```yaml
---
type: cover
palette: warm
rendering: flat-vector
references:
- ref_id: 01
filename: refs/ref-01-podcast-thumbnail.jpg
usage: style
---
```
| Field | Description |
|-------|-------------|
| `ref_id` | Sequential number (01, 02, ...) |
| `filename` | Relative path from prompt file's parent directory |
| `usage` | `direct` / `style` / `palette` |
**Omit `references` field entirely** if no reference files saved (style extracted verbally only).
### When to Include References in Frontmatter
| Situation | Frontmatter Action | Generation Action |
|-----------|-------------------|-------------------|
| Reference file saved to `refs/` | Add to `references` list ✓ | Pass via `--ref` parameter |
| Style extracted verbally (no file) | Omit `references` field | Describe in prompt body only |
| File path in frontmatter but doesn't exist | ERROR - fix or remove | Generation will fail |
**Before writing prompt with references, verify**: `test -f refs/ref-NN-{slug}.{ext}`
### Reference Usage Types
| Usage | When to Use | Generation Action |
|-------|-------------|-------------------|
| `direct` | Reference matches desired output closely | Pass to `--ref` parameter |
| `style` | Extract visual style characteristics only | Describe style in prompt text |
| `palette` | Extract color palette only | Include colors in prompt |
### Step 1: Analyze References
For each reference image, extract:
- **Style**: Rendering technique, line quality, texture
- **Composition**: Layout, visual hierarchy, focal points
- **Color mood**: Palette characteristics (without specific colors)
- **Elements**: Key visual elements and symbols used
### Step 2: Embed in Prompt
**If file saved AND skill supports `--ref`** (e.g., baoyu-image-gen with Google):
- Pass ref images directly via `--ref` parameter
- Add brief style note in prompt:
```
# Reference Style
Follow the visual style of the attached reference image(s):
- [1-2 sentence style summary from analysis]
```
**If file saved BUT skill does NOT support `--ref`**:
- Embed detailed text description in prompt:
```
# Reference Style (Text Description)
Emulate the following visual style from reference image(s):
Reference 1: [filename]
- Style: [detailed rendering technique description]
- Composition: [layout and hierarchy description]
- Elements: [key visual elements used]
- Mood: [emotional tone and visual weight]
[Repeat for additional references]
Apply these style characteristics to the cover design while maintaining the specified Type, Palette, and Rendering dimensions.
```
**If style/palette extracted verbally (NO file saved)**:
- DO NOT add references metadata to prompt
- Append extracted info directly to prompt body:
```
# Extracted Style (from reference)
COLORS (from reference):
- Primary: #E8756D coral
- Secondary: #7ECFC0 mint
...
STYLE (from reference):
- Clean lines, minimal shadows
- Gradient backgrounds
- Flat vector icons
...
```
### Reference Analysis Template
Use this format when analyzing reference images:
| Aspect | Analysis Points |
|--------|-----------------|
| **Rendering** | Line quality (clean/sketchy/painted), texture presence, depth treatment |
| **Composition** | Element placement, whitespace ratio, visual flow |
| **Typography** | Font style, text placement, hierarchy (if present) |
| **Elements** | Icon vocabulary, decorative motifs, character style |
| **Mood** | Contrast level, saturation, visual weight |
+1 -2
View File
@@ -13,8 +13,7 @@ Scripts in `scripts/` subdirectory. Replace `${SKILL_DIR}` with this SKILL.md's
| Script | Purpose | | Script | Purpose |
|--------|---------| |--------|---------|
| `scripts/main.ts` | Main entry point with CLI options | | `scripts/main.ts` | Main entry point with CLI options (uses remark-cjk-friendly for CJK emphasis) |
| `scripts/cjk-emphasis.ts` | Fix CJK emphasis/bold punctuation issues |
| `scripts/quotes.ts` | Replace ASCII quotes with fullwidth quotes | | `scripts/quotes.ts` | Replace ASCII quotes with fullwidth quotes |
| `scripts/autocorrect.ts` | Add CJK/English spacing via autocorrect | | `scripts/autocorrect.ts` | Add CJK/English spacing via autocorrect |
@@ -1,314 +0,0 @@
const CJK_PUNCT_COMMON = "。.,、?!:;";
const CJK_OPENING_PUNCT = "(〔〖〘〚「『〈《【\u201C\u2018";
const CJK_CLOSING_PUNCT = ")〕〗〙〛」』〉》】\u201D\u2019" + CJK_PUNCT_COMMON;
const CJK_SCRIPTS =
"\\p{Script=Han}\\p{Script=Hiragana}\\p{Script=Katakana}\\p{Script=Hangul}";
export const CJK_CLOSING_PUNCT_RE = new RegExp(`[${CJK_CLOSING_PUNCT}]`);
export const CJK_OPENING_PUNCT_RE = new RegExp(`^[${CJK_OPENING_PUNCT}]`);
export const CJK_CHAR_RE = new RegExp(`[${CJK_SCRIPTS}]`, "u");
const PUNCT_OR_SYMBOL_RE = /[\p{P}\p{S}]/u;
const WORD_CHAR_RE = /[\p{L}\p{N}]/u;
const CJK_PUNCT_PAIRS: Record<string, string> = {
"“": "”",
"": "",
"": "",
"": "",
"〖": "〗",
"〘": "〙",
"〚": "〛",
"「": "」",
"『": "』",
"〈": "〉",
"《": "》",
"【": "】",
};
function findInlineCodeRanges(text: string): Array<[number, number]> {
const ranges: Array<[number, number]> = [];
let i = 0;
while (i < text.length) {
if (text[i] !== "`") {
i += 1;
continue;
}
let run = 1;
while (i + run < text.length && text[i + run] === "`") {
run += 1;
}
const start = i;
let j = i + run;
let found = false;
while (j < text.length) {
if (text[j] !== "`") {
j += 1;
continue;
}
let closeRun = 1;
while (j + closeRun < text.length && text[j + closeRun] === "`") {
closeRun += 1;
}
if (closeRun === run) {
ranges.push([start, j + closeRun - 1]);
i = j + closeRun;
found = true;
break;
}
j += closeRun;
}
if (!found) {
i = start + run;
}
}
return ranges;
}
function isEscaped(text: string, pos: number): boolean {
let count = 0;
for (let i = pos - 1; i >= 0 && text[i] === "\\"; i -= 1) {
count += 1;
}
return count % 2 === 1;
}
function isWhitespaceChar(ch: string | undefined): boolean {
return !ch || /\s/u.test(ch);
}
function isPunctuationOrSymbol(ch: string | undefined): boolean {
return !!ch && PUNCT_OR_SYMBOL_RE.test(ch);
}
function isMatchingCjkPunct(open: string, close: string): boolean {
return CJK_PUNCT_PAIRS[open] === close;
}
function mapNonCodeSegments(
block: string,
mapper: (segment: string) => string
): string {
const codeRanges = findInlineCodeRanges(block);
if (codeRanges.length === 0) {
return mapper(block);
}
let result = "";
let lastIndex = 0;
for (const [start, end] of codeRanges) {
if (start > lastIndex) {
result += mapper(block.slice(lastIndex, start));
}
result += block.slice(start, end + 1);
lastIndex = end + 1;
}
if (lastIndex < block.length) {
result += mapper(block.slice(lastIndex));
}
return result;
}
function moveCjkPunctuationOutsideEmphasis(block: string): string {
return mapNonCodeSegments(block, (segment) => {
const delimiterPositions: number[] = [];
let cursor = 0;
while (cursor < segment.length - 1) {
if (
segment[cursor] === "*" &&
segment[cursor + 1] === "*" &&
segment[cursor - 1] !== "*" &&
segment[cursor + 2] !== "*" &&
!isEscaped(segment, cursor)
) {
delimiterPositions.push(cursor);
cursor += 2;
continue;
}
cursor += 1;
}
if (delimiterPositions.length < 2) return segment;
const stack: number[] = [];
const pairs: Array<{ open: number; close: number }> = [];
for (const pos of delimiterPositions) {
if (stack.length === 0) {
stack.push(pos);
} else {
const open = stack.pop() as number;
pairs.push({ open, close: pos });
}
}
const skip = new Set<number>();
const insertBefore = new Map<number, string>();
for (const pair of pairs) {
const openPunctPos = pair.open + 2;
const closePunctPos = pair.close - 1;
if (openPunctPos >= closePunctPos) continue;
const openPunct = segment[openPunctPos];
const closePunct = segment[closePunctPos];
if (!openPunct || !closePunct) continue;
if (!CJK_OPENING_PUNCT_RE.test(openPunct)) continue;
if (!CJK_CLOSING_PUNCT_RE.test(closePunct)) continue;
if (!isMatchingCjkPunct(openPunct, closePunct)) continue;
if (openPunctPos + 1 >= closePunctPos) continue;
const inner = segment.slice(openPunctPos + 1, closePunctPos);
if (inner.length === 0) continue;
skip.add(openPunctPos);
skip.add(closePunctPos);
insertBefore.set(pair.open, (insertBefore.get(pair.open) ?? "") + openPunct);
const afterClose = pair.close + 2;
insertBefore.set(
afterClose,
(insertBefore.get(afterClose) ?? "") + closePunct
);
}
if (skip.size === 0) return segment;
let result = "";
for (let idx = 0; idx < segment.length; idx += 1) {
const insert = insertBefore.get(idx);
if (insert) {
result += insert;
}
if (skip.has(idx)) {
continue;
}
result += segment[idx];
}
const tailInsert = insertBefore.get(segment.length);
if (tailInsert) {
result += tailInsert;
}
return result;
});
}
function fixCjkEmphasisSpacingInBlock(block: string): string {
const normalized = moveCjkPunctuationOutsideEmphasis(block);
const codeRanges = findInlineCodeRanges(normalized);
let rangeIndex = 0;
const delimiters: Array<{
pos: number;
canOpen: boolean;
canClose: boolean;
}> = [];
let cursor = 0;
while (cursor < normalized.length - 1) {
if (rangeIndex < codeRanges.length && cursor >= codeRanges[rangeIndex][0]) {
if (cursor <= codeRanges[rangeIndex][1]) {
cursor = codeRanges[rangeIndex][1] + 1;
continue;
}
rangeIndex += 1;
continue;
}
if (
normalized[cursor] === "*" &&
normalized[cursor + 1] === "*" &&
normalized[cursor - 1] !== "*" &&
normalized[cursor + 2] !== "*" &&
!isEscaped(normalized, cursor)
) {
const before = normalized[cursor - 1];
const after = normalized[cursor + 2];
const beforeIsSpace = isWhitespaceChar(before);
const afterIsSpace = isWhitespaceChar(after);
const beforeIsPunct = isPunctuationOrSymbol(before);
const afterIsPunct = isPunctuationOrSymbol(after);
const leftFlanking =
!afterIsSpace && (!afterIsPunct || beforeIsSpace || beforeIsPunct);
const rightFlanking =
!beforeIsSpace && (!beforeIsPunct || afterIsSpace || afterIsPunct);
const cjkPunctBefore = !!before && CJK_CLOSING_PUNCT_RE.test(before);
const wordAfter = !!after && WORD_CHAR_RE.test(after);
delimiters.push({
pos: cursor,
canOpen: leftFlanking,
canClose: rightFlanking || (cjkPunctBefore && wordAfter),
});
cursor += 2;
continue;
}
cursor += 1;
}
const stack: Array<{ pos: number }> = [];
const pairs: Array<{ open: number; close: number }> = [];
for (const delimiter of delimiters) {
if (delimiter.canClose) {
let openerIndex = -1;
for (let j = stack.length - 1; j >= 0; j -= 1) {
openerIndex = j;
break;
}
if (openerIndex !== -1) {
const opener = stack.splice(openerIndex, 1)[0];
pairs.push({ open: opener.pos, close: delimiter.pos });
}
}
if (delimiter.canOpen) {
stack.push({ pos: delimiter.pos });
}
}
if (pairs.length === 0) return normalized;
const insertPositions = new Set<number>();
for (const pair of pairs) {
const insideLast = normalized[pair.close - 1];
const afterClose = normalized[pair.close + 2];
if (!afterClose) continue;
if (
CJK_CLOSING_PUNCT_RE.test(insideLast) &&
WORD_CHAR_RE.test(afterClose)
) {
insertPositions.add(pair.close + 2);
}
}
if (insertPositions.size === 0) return normalized;
let result = "";
for (let idx = 0; idx < normalized.length; idx += 1) {
if (insertPositions.has(idx)) {
result += " ";
}
result += normalized[idx];
}
if (insertPositions.has(normalized.length)) {
result += " ";
}
return result;
}
export function fixCjkEmphasisSpacing(content: string): string {
const parts = content.split(/(^```[\s\S]*?^```|^~~~[\s\S]*?^~~~)/m);
return parts
.map((part, i) => {
if (i % 2 === 1) return part;
const blocks = part.split(/(\n\s*\n+)/);
return blocks
.map((block, index) => {
if (index % 2 === 1) return block;
return fixCjkEmphasisSpacingInBlock(block);
})
.join("");
})
.join("");
}
+10 -55
View File
@@ -1,17 +1,12 @@
import { readFileSync, writeFileSync } from "fs"; import { readFileSync, writeFileSync } from "fs";
import { unified } from "unified"; import { unified } from "unified";
import remarkParse from "remark-parse"; import remarkParse from "remark-parse";
import remarkCjkFriendly from "remark-cjk-friendly";
import remarkGfm from "remark-gfm"; import remarkGfm from "remark-gfm";
import remarkFrontmatter from "remark-frontmatter"; import remarkFrontmatter from "remark-frontmatter";
import remarkStringify from "remark-stringify"; import remarkStringify from "remark-stringify";
import { visit } from "unist-util-visit"; import { visit } from "unist-util-visit";
import YAML from "yaml"; import YAML from "yaml";
import {
fixCjkEmphasisSpacing,
CJK_CLOSING_PUNCT_RE,
CJK_OPENING_PUNCT_RE,
CJK_CHAR_RE,
} from "./cjk-emphasis";
import { replaceQuotes } from "./quotes"; import { replaceQuotes } from "./quotes";
import { applyAutocorrect } from "./autocorrect"; import { applyAutocorrect } from "./autocorrect";
@@ -36,6 +31,12 @@ const DEFAULT_OPTIONS: Required<FormatOptions> = {
emphasis: true, emphasis: true,
}; };
function decodeHtmlEntities(text: string): string {
return text.replace(/&#x([0-9A-Fa-f]+);/g, (_, hex) =>
String.fromCodePoint(parseInt(hex, 16))
);
}
function formatFrontmatter(value: string): string | null { function formatFrontmatter(value: string): string | null {
try { try {
const doc = YAML.parseDocument(value); const doc = YAML.parseDocument(value);
@@ -49,12 +50,9 @@ function formatMarkdownContent(
content: string, content: string,
options: Required<FormatOptions> options: Required<FormatOptions>
): string { ): string {
if (options.emphasis) {
content = fixCjkEmphasisSpacing(content);
}
const processor = unified() const processor = unified()
.use(remarkParse) .use(remarkParse)
.use(options.emphasis ? remarkCjkFriendly : [])
.use(remarkGfm) .use(remarkGfm)
.use(remarkFrontmatter, ["yaml"]) .use(remarkFrontmatter, ["yaml"])
.use(remarkStringify, { .use(remarkStringify, {
@@ -63,7 +61,7 @@ function formatMarkdownContent(
const tree = processor.parse(content); const tree = processor.parse(content);
visit(tree, (node, _index, parent) => { visit(tree, (node) => {
if (node.type === "text" && options.quotes) { if (node.type === "text" && options.quotes) {
const textNode = node as { value: string }; const textNode = node as { value: string };
textNode.value = replaceQuotes(textNode.value); textNode.value = replaceQuotes(textNode.value);
@@ -77,54 +75,11 @@ function formatMarkdownContent(
} }
return; return;
} }
if (
options.emphasis &&
(node.type === "strong" ||
node.type === "emphasis" ||
node.type === "delete") &&
parent
) {
const siblings = (parent as { children: typeof node[] }).children;
const idx = siblings.indexOf(node);
const children = (node as { children: typeof node[] }).children;
if (!children || children.length === 0) return;
const lastChild = children[children.length - 1];
if (lastChild.type === "text") {
const lastText = (lastChild as { value: string }).value;
if (
CJK_CLOSING_PUNCT_RE.test(lastText.slice(-1)) &&
idx + 1 < siblings.length
) {
const nextSib = siblings[idx + 1];
if (nextSib.type === "text") {
const nextText = (nextSib as { value: string }).value;
if (CJK_CHAR_RE.test(nextText.charAt(0))) {
(nextSib as { value: string }).value = " " + nextText;
}
}
}
}
const firstChild = children[0];
if (firstChild.type === "text") {
const firstText = (firstChild as { value: string }).value;
if (CJK_OPENING_PUNCT_RE.test(firstText) && idx > 0) {
const prevSib = siblings[idx - 1];
if (prevSib.type === "text") {
const prevText = (prevSib as { value: string }).value;
if (CJK_CHAR_RE.test(prevText.charAt(prevText.length - 1))) {
(prevSib as { value: string }).value = prevText + " ";
}
}
}
}
}
}); });
let result = processor.stringify(tree); let result = processor.stringify(tree);
if (options.emphasis) { if (options.emphasis) {
result = fixCjkEmphasisSpacing(result); result = decodeHtmlEntities(result);
} }
return result; return result;
} }
File diff suppressed because it is too large Load Diff
@@ -1,5 +1,6 @@
{ {
"dependencies": { "dependencies": {
"remark-cjk-friendly": "^1.1.0",
"remark-frontmatter": "^5.0.0", "remark-frontmatter": "^5.0.0",
"remark-gfm": "^4.0.1", "remark-gfm": "^4.0.1",
"remark-parse": "^11.0.0", "remark-parse": "^11.0.0",
+17 -6
View File
@@ -153,10 +153,12 @@ Schema: `references/config/preferences-schema.md`
**1.2 Analyze Content → `analysis.md`** **1.2 Analyze Content → `analysis.md`**
1. Save source content (file path or paste → `source.md`) 1. Save source content (file path or paste → `source.md`)
- **Backup rule**: If `source.md` exists, rename to `source-backup-YYYYMMDD-HHMMSS.md`
2. Analyze: topic, data type, complexity, tone, audience 2. Analyze: topic, data type, complexity, tone, audience
3. Detect source language and user language 3. Detect source language and user language
4. Extract design instructions from user input 4. Extract design instructions from user input
5. Save analysis 5. Save analysis
- **Backup rule**: If `analysis.md` exists, rename to `analysis-backup-YYYYMMDD-HHMMSS.md`
See `references/analysis-framework.md` for detailed format. See `references/analysis-framework.md` for detailed format.
@@ -182,13 +184,20 @@ Recommend 3-5 layout×style combinations based on:
### Step 4: Confirm Options ### Step 4: Confirm Options
Present all options in single confirmation: Use **single AskUserQuestion call** with multiple questions to confirm all options together:
1. **Combination** (always): 3+ options with rationale
2. **Aspect** (always): landscape/portrait/square | Question | When | Options |
3. **Language** (only if source ≠ user language): which language for text |----------|------|---------|
| **Combination** | Always | 3+ layout×style combos with rationale |
| **Aspect** | Always | landscape (16:9), portrait (9:16), square (1:1) |
| **Language** | Only if source ≠ user language | Language for text content |
**Important**: Do NOT split into separate AskUserQuestion calls. Combine all applicable questions into one call.
### Step 5: Generate Prompt → `prompts/infographic.md` ### Step 5: Generate Prompt → `prompts/infographic.md`
**Backup rule**: If `prompts/infographic.md` exists, rename to `prompts/infographic-backup-YYYYMMDD-HHMMSS.md`
Combine: Combine:
1. Layout definition from `references/layouts/<layout>.md` 1. Layout definition from `references/layouts/<layout>.md`
2. Style definition from `references/styles/<style>.md` 2. Style definition from `references/styles/<style>.md`
@@ -199,8 +208,10 @@ Combine:
### Step 6: Generate Image ### Step 6: Generate Image
1. Select available image generation skill (ask user if multiple) 1. Select available image generation skill (ask user if multiple)
2. Call with prompt file and output path 2. **Check for existing file**: Before generating, check if `infographic.png` exists
3. On failure, auto-retry once - If exists: Rename to `infographic-backup-YYYYMMDD-HHMMSS.png`
3. Call with prompt file and output path
4. On failure, auto-retry once
### Step 7: Output Summary ### Step 7: Output Summary
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,14 @@
{
"dependencies": {
"fflate": "^0.8.2",
"front-matter": "^4.0.2",
"highlight.js": "^11.11.1",
"juice": "^11.0.1",
"marked": "^15.0.6",
"reading-time": "^1.5.0",
"remark-cjk-friendly": "^1.1.0",
"remark-parse": "^11.0.0",
"remark-stringify": "^11.0.0",
"unified": "^11.0.5"
}
}
@@ -7,6 +7,10 @@ import frontMatter from "front-matter";
import hljs from "highlight.js/lib/core"; import hljs from "highlight.js/lib/core";
import { marked, type RendererObject, type Tokens } from "marked"; import { marked, type RendererObject, type Tokens } from "marked";
import readingTime, { type ReadTimeResults } from "reading-time"; import readingTime, { type ReadTimeResults } from "reading-time";
import { unified } from "unified";
import remarkParse from "remark-parse";
import remarkCjkFriendly from "remark-cjk-friendly";
import remarkStringify from "remark-stringify";
import { import {
markedAlert, markedAlert,
@@ -552,12 +556,47 @@ interface CliOptions {
keepTitle: boolean; keepTitle: boolean;
} }
function preprocessCjkEmphasis(markdown: string): string {
const processor = unified()
.use(remarkParse)
.use(remarkCjkFriendly);
const tree = processor.parse(markdown);
const visit = (node: any, parent?: any, index?: number) => {
if (node.children) {
for (let i = 0; i < node.children.length; i++) {
visit(node.children[i], node, i);
}
}
if (node.type === "strong" && parent && typeof index === "number") {
const text = extractText(node);
parent.children[index] = { type: "html", value: `<strong>${text}</strong>` };
}
if (node.type === "emphasis" && parent && typeof index === "number") {
const text = extractText(node);
parent.children[index] = { type: "html", value: `<em>${text}</em>` };
}
};
const extractText = (node: any): string => {
if (node.type === "text") return node.value;
if (node.children) return node.children.map(extractText).join("");
return "";
};
visit(tree);
const stringify = unified().use(remarkStringify);
let result = stringify.stringify(tree);
result = result.replace(/&#x([0-9A-Fa-f]+);/g, (_, hex) =>
String.fromCodePoint(parseInt(hex, 16))
);
return result;
}
function renderMarkdown(raw: string, renderer: RendererAPI): { function renderMarkdown(raw: string, renderer: RendererAPI): {
html: string; html: string;
readingTime: ReadTimeResults; readingTime: ReadTimeResults;
} { } {
const preprocessed = preprocessCjkEmphasis(raw);
const { markdownContent, readingTime: readingTimeResult } = const { markdownContent, readingTime: readingTimeResult } =
renderer.parseFrontMatterAndContent(raw); renderer.parseFrontMatterAndContent(preprocessed);
const html = marked.parse(markdownContent) as string; const html = marked.parse(markdownContent) as string;
+105 -21
View File
@@ -28,6 +28,18 @@ interface PublishResponse {
errmsg?: string; errmsg?: string;
} }
type ArticleType = "news" | "newspic";
interface ArticleOptions {
title: string;
author?: string;
digest?: string;
content: string;
thumbMediaId: string;
articleType: ArticleType;
imageMediaIds?: string[];
}
const TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token"; const TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";
const UPLOAD_URL = "https://api.weixin.qq.com/cgi-bin/material/add_material"; const UPLOAD_URL = "https://api.weixin.qq.com/cgi-bin/material/add_material";
const DRAFT_URL = "https://api.weixin.qq.com/cgi-bin/draft/add"; const DRAFT_URL = "https://api.weixin.qq.com/cgi-bin/draft/add";
@@ -176,16 +188,17 @@ async function uploadImagesInHtml(
html: string, html: string,
accessToken: string, accessToken: string,
baseDir: string baseDir: string
): Promise<{ html: string; firstMediaId: string }> { ): Promise<{ html: string; firstMediaId: string; allMediaIds: string[] }> {
const imgRegex = /<img[^>]*\ssrc=["']([^"']+)["'][^>]*>/gi; const imgRegex = /<img[^>]*\ssrc=["']([^"']+)["'][^>]*>/gi;
const matches = [...html.matchAll(imgRegex)]; const matches = [...html.matchAll(imgRegex)];
if (matches.length === 0) { if (matches.length === 0) {
return { html, firstMediaId: "" }; return { html, firstMediaId: "", allMediaIds: [] };
} }
let firstMediaId = ""; let firstMediaId = "";
let updatedHtml = html; let updatedHtml = html;
const allMediaIds: string[] = [];
for (const match of matches) { for (const match of matches) {
const [fullTag, src] = match; const [fullTag, src] = match;
@@ -208,6 +221,7 @@ async function uploadImagesInHtml(
.replace(/\ssrc=["'][^"']+["']/, ` src="${resp.url}"`) .replace(/\ssrc=["'][^"']+["']/, ` src="${resp.url}"`)
.replace(/\sdata-local-path=["'][^"']+["']/, ""); .replace(/\sdata-local-path=["'][^"']+["']/, "");
updatedHtml = updatedHtml.replace(fullTag, newTag); updatedHtml = updatedHtml.replace(fullTag, newTag);
allMediaIds.push(resp.media_id);
if (!firstMediaId) { if (!firstMediaId) {
firstMediaId = resp.media_id; firstMediaId = resp.media_id;
} }
@@ -216,28 +230,51 @@ async function uploadImagesInHtml(
} }
} }
return { html: updatedHtml, firstMediaId }; return { html: updatedHtml, firstMediaId, allMediaIds };
} }
async function publishToDraft( async function publishToDraft(
title: string, options: ArticleOptions,
html: string,
thumbMediaId: string,
accessToken: string accessToken: string
): Promise<PublishResponse> { ): Promise<PublishResponse> {
const url = `${DRAFT_URL}?access_token=${accessToken}`; const url = `${DRAFT_URL}?access_token=${accessToken}`;
let article: Record<string, unknown>;
if (options.articleType === "newspic") {
if (!options.imageMediaIds || options.imageMediaIds.length === 0) {
throw new Error("newspic requires at least one image");
}
article = {
article_type: "newspic",
title: options.title,
content: options.content,
need_open_comment: 1,
only_fans_can_comment: 0,
image_info: {
image_list: options.imageMediaIds.map(id => ({ image_media_id: id })),
},
};
if (options.author) article.author = options.author;
} else {
article = {
article_type: "news",
title: options.title,
content: options.content,
thumb_media_id: options.thumbMediaId,
need_open_comment: 1,
only_fans_can_comment: 0,
};
if (options.author) article.author = options.author;
if (options.digest) article.digest = options.digest;
}
const res = await fetch(url, { const res = await fetch(url, {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
body: JSON.stringify({ body: JSON.stringify({ articles: [article] }),
articles: [{
title,
content: html,
thumb_media_id: thumbMediaId,
}],
}),
}); });
const data = await res.json() as PublishResponse; const data = await res.json() as PublishResponse;
@@ -315,13 +352,24 @@ Arguments:
file Markdown (.md) or HTML (.html) file file Markdown (.md) or HTML (.html) file
Options: Options:
--type <type> Article type: news (文章, default) or newspic (图文)
--title <title> Override title --title <title> Override title
--summary <text> Article summary (for future use) --author <name> Author name (max 16 chars)
--summary <text> Article summary/digest (max 128 chars)
--theme <name> Theme name for markdown (default, grace, simple). Default: default --theme <name> Theme name for markdown (default, grace, simple). Default: default
--cover <path> Cover image path (local or URL) --cover <path> Cover image path (local or URL)
--dry-run Parse and render only, don't publish --dry-run Parse and render only, don't publish
--help Show this help --help Show this help
Frontmatter Fields (markdown):
title Article title
author Author name
digest/summary Article summary
featureImage/coverImage/cover/image Cover image path
Comments:
Comments are enabled by default, open to all users.
Environment Variables: Environment Variables:
WECHAT_APP_ID WeChat App ID WECHAT_APP_ID WeChat App ID
WECHAT_APP_SECRET WeChat App Secret WECHAT_APP_SECRET WeChat App Secret
@@ -334,7 +382,9 @@ Config File Locations (in priority order):
Example: Example:
npx -y bun wechat-api.ts article.md npx -y bun wechat-api.ts article.md
npx -y bun wechat-api.ts article.md --theme grace --cover cover.png npx -y bun wechat-api.ts article.md --theme grace --cover cover.png
npx -y bun wechat-api.ts article.md --author "Author Name" --summary "Brief intro"
npx -y bun wechat-api.ts article.html --title "My Article" npx -y bun wechat-api.ts article.html --title "My Article"
npx -y bun wechat-api.ts images/ --type newspic --title "Photo Album"
npx -y bun wechat-api.ts article.md --dry-run npx -y bun wechat-api.ts article.md --dry-run
`); `);
process.exit(0); process.exit(0);
@@ -343,7 +393,9 @@ Example:
interface CliArgs { interface CliArgs {
filePath: string; filePath: string;
isHtml: boolean; isHtml: boolean;
articleType: ArticleType;
title?: string; title?: string;
author?: string;
summary?: string; summary?: string;
theme: string; theme: string;
cover?: string; cover?: string;
@@ -358,14 +410,22 @@ function parseArgs(argv: string[]): CliArgs {
const args: CliArgs = { const args: CliArgs = {
filePath: "", filePath: "",
isHtml: false, isHtml: false,
articleType: "news",
theme: "default", theme: "default",
dryRun: false, dryRun: false,
}; };
for (let i = 0; i < argv.length; i++) { for (let i = 0; i < argv.length; i++) {
const arg = argv[i]!; const arg = argv[i]!;
if (arg === "--title" && argv[i + 1]) { if (arg === "--type" && argv[i + 1]) {
const t = argv[++i]!.toLowerCase();
if (t === "news" || t === "newspic") {
args.articleType = t;
}
} else if (arg === "--title" && argv[i + 1]) {
args.title = argv[++i]; args.title = argv[++i];
} else if (arg === "--author" && argv[i + 1]) {
args.author = argv[++i];
} else if (arg === "--summary" && argv[i + 1]) { } else if (arg === "--summary" && argv[i + 1]) {
args.summary = argv[++i]; args.summary = argv[++i];
} else if (arg === "--theme" && argv[i + 1]) { } else if (arg === "--theme" && argv[i + 1]) {
@@ -410,6 +470,8 @@ async function main(): Promise<void> {
const baseDir = path.dirname(filePath); const baseDir = path.dirname(filePath);
let title = args.title || ""; let title = args.title || "";
let author = args.author || "";
let digest = args.summary || "";
let htmlPath: string; let htmlPath: string;
let htmlContent: string; let htmlContent: string;
let frontmatter: Record<string, string> = {}; let frontmatter: Record<string, string> = {};
@@ -422,9 +484,9 @@ async function main(): Promise<void> {
const mdContent = fs.readFileSync(mdPath, "utf-8"); const mdContent = fs.readFileSync(mdPath, "utf-8");
const parsed = parseFrontmatter(mdContent); const parsed = parseFrontmatter(mdContent);
frontmatter = parsed.frontmatter; frontmatter = parsed.frontmatter;
if (!title && frontmatter.title) { if (!title && frontmatter.title) title = frontmatter.title;
title = frontmatter.title; if (!author) author = frontmatter.author || "";
} if (!digest) digest = frontmatter.digest || frontmatter.summary || frontmatter.description || "";
} }
if (!title) { if (!title) {
title = extractHtmlTitle(fs.readFileSync(htmlPath, "utf-8")); title = extractHtmlTitle(fs.readFileSync(htmlPath, "utf-8"));
@@ -441,6 +503,8 @@ async function main(): Promise<void> {
const h1Match = body.match(/^#\s+(.+)$/m); const h1Match = body.match(/^#\s+(.+)$/m);
if (h1Match) title = h1Match[1]!; if (h1Match) title = h1Match[1]!;
} }
if (!author) author = frontmatter.author || "";
if (!digest) digest = frontmatter.digest || frontmatter.summary || frontmatter.description || "";
console.error(`[wechat-api] Theme: ${args.theme}`); console.error(`[wechat-api] Theme: ${args.theme}`);
htmlPath = renderMarkdownToHtml(filePath, args.theme); htmlPath = renderMarkdownToHtml(filePath, args.theme);
@@ -454,10 +518,16 @@ async function main(): Promise<void> {
} }
console.error(`[wechat-api] Title: ${title}`); console.error(`[wechat-api] Title: ${title}`);
if (author) console.error(`[wechat-api] Author: ${author}`);
if (digest) console.error(`[wechat-api] Digest: ${digest.slice(0, 50)}...`);
console.error(`[wechat-api] Type: ${args.articleType}`);
if (args.dryRun) { if (args.dryRun) {
console.log(JSON.stringify({ console.log(JSON.stringify({
articleType: args.articleType,
title, title,
author: author || undefined,
digest: digest || undefined,
htmlPath, htmlPath,
contentLength: htmlContent.length, contentLength: htmlContent.length,
}, null, 2)); }, null, 2));
@@ -469,7 +539,7 @@ async function main(): Promise<void> {
const accessToken = await fetchAccessToken(config.appId, config.appSecret); const accessToken = await fetchAccessToken(config.appId, config.appSecret);
console.error("[wechat-api] Uploading images..."); console.error("[wechat-api] Uploading images...");
const { html: processedHtml, firstMediaId } = await uploadImagesInHtml( const { html: processedHtml, firstMediaId, allMediaIds } = await uploadImagesInHtml(
htmlContent, htmlContent,
accessToken, accessToken,
baseDir baseDir
@@ -497,18 +567,32 @@ async function main(): Promise<void> {
} }
} }
if (!thumbMediaId) { if (args.articleType === "news" && !thumbMediaId) {
console.error("Error: No cover image. Provide via --cover, frontmatter.featureImage, or include an image in content."); console.error("Error: No cover image. Provide via --cover, frontmatter.featureImage, or include an image in content.");
process.exit(1); process.exit(1);
} }
if (args.articleType === "newspic" && allMediaIds.length === 0) {
console.error("Error: newspic requires at least one image in content.");
process.exit(1);
}
console.error("[wechat-api] Publishing to draft..."); console.error("[wechat-api] Publishing to draft...");
const result = await publishToDraft(title, htmlContent, thumbMediaId, accessToken); const result = await publishToDraft({
title,
author: author || undefined,
digest: digest || undefined,
content: htmlContent,
thumbMediaId,
articleType: args.articleType,
imageMediaIds: args.articleType === "newspic" ? allMediaIds : undefined,
}, accessToken);
console.log(JSON.stringify({ console.log(JSON.stringify({
success: true, success: true,
media_id: result.media_id, media_id: result.media_id,
title, title,
articleType: args.articleType,
}, null, 2)); }, null, 2));
console.error(`[wechat-api] Published successfully! media_id: ${result.media_id}`); console.error(`[wechat-api] Published successfully! media_id: ${result.media_id}`);
+5 -1
View File
@@ -226,6 +226,7 @@ Schema: `references/config/preferences-schema.md`
**1.2 Analyze Content** **1.2 Analyze Content**
1. Save source content (if pasted, save as `source.md`) 1. Save source content (if pasted, save as `source.md`)
- **Backup rule**: If `source.md` exists, rename to `source-backup-YYYYMMDD-HHMMSS.md`
2. Follow `references/analysis-framework.md` for content analysis 2. Follow `references/analysis-framework.md` for content analysis
3. Analyze content signals for style recommendations 3. Analyze content signals for style recommendations
4. Detect source language 4. Detect source language
@@ -483,6 +484,7 @@ options:
- Add slide-specific content - Add slide-specific content
- If `Layout:` specified, include layout guidance from `references/layouts.md` - If `Layout:` specified, include layout guidance from `references/layouts.md`
3. Save to `prompts/` directory 3. Save to `prompts/` directory
- **Backup rule**: If prompt file exists, rename to `prompts/NN-slide-{slug}-backup-YYYYMMDD-HHMMSS.md`
**After generation**: **After generation**:
- If `--prompts-only`, stop here and output prompt summary - If `--prompts-only`, stop here and output prompt summary
@@ -539,7 +541,9 @@ options:
**Standard flow**: **Standard flow**:
1. Select available image generation skill 1. Select available image generation skill
2. Generate session ID: `slides-{topic-slug}-{timestamp}` 2. Generate session ID: `slides-{topic-slug}-{timestamp}`
3. Generate each slide sequentially with same session ID 3. For each slide:
- **Backup rule**: If image file exists, rename to `NN-slide-{slug}-backup-YYYYMMDD-HHMMSS.png`
- Generate image sequentially with same session ID
4. Report progress: "Generated X/N" (in user's language) 4. Report progress: "Generated X/N" (in user's language)
5. Auto-retry once on failure before reporting error 5. Auto-retry once on failure before reporting error
+26 -14
View File
@@ -1,6 +1,6 @@
--- ---
name: baoyu-xhs-images name: baoyu-xhs-images
description: Generates Xiaohongshu (Little Red Book) infographic series with 11 visual styles and 8 layouts. Breaks content into 1-10 cartoon-style images optimized for XHS engagement. Use when user mentions "小红书图片", "XHS images", "RedNote infographics", "小红书种草", or wants social media infographics for Chinese platforms. description: Generates Xiaohongshu (Little Red Book) infographic series with 10 visual styles and 8 layouts. Breaks content into 1-10 cartoon-style images optimized for XHS engagement. Use when user mentions "小红书图片", "XHS images", "RedNote infographics", "小红书种草", or wants social media infographics for Chinese platforms.
--- ---
# Xiaohongshu Infographic Series Generator # Xiaohongshu Infographic Series Generator
@@ -42,7 +42,7 @@ Break down complex content into eye-catching infographic series for Xiaohongshu
| Dimension | Controls | Options | | Dimension | Controls | Options |
|-----------|----------|---------| |-----------|----------|---------|
| **Style** | Visual aesthetics: colors, lines, decorations | cute, fresh, warm, bold, minimal, retro, pop, notion, chalkboard, notebook, study-notes | | **Style** | Visual aesthetics: colors, lines, decorations | cute, fresh, warm, bold, minimal, retro, pop, notion, chalkboard, study-notes |
| **Layout** | Information structure: density, arrangement | sparse, balanced, dense, list, comparison, flow, mindmap, quadrant | | **Layout** | Information structure: density, arrangement | sparse, balanced, dense, list, comparison, flow, mindmap, quadrant |
Style × Layout can be freely combined. Example: `--style notion --layout dense` creates an intellectual-looking knowledge card with high information density. Style × Layout can be freely combined. Example: `--style notion --layout dense` creates an intellectual-looking knowledge card with high information density.
@@ -60,7 +60,6 @@ Style × Layout can be freely combined. Example: `--style notion --layout dense`
| `pop` | Vibrant, energetic, eye-catching | | `pop` | Vibrant, energetic, eye-catching |
| `notion` | Minimalist hand-drawn line art, intellectual | | `notion` | Minimalist hand-drawn line art, intellectual |
| `chalkboard` | Colorful chalk on black board, educational | | `chalkboard` | Colorful chalk on black board, educational |
| `notebook` | Hand-drawn infographic style, watercolor rendering + Morandi palette |
| `study-notes` | Realistic handwritten photo style, blue pen + red annotations + yellow highlighter | | `study-notes` | Realistic handwritten photo style, blue pen + red annotations + yellow highlighter |
Detailed style definitions: `references/presets/<style>.md` Detailed style definitions: `references/presets/<style>.md`
@@ -93,7 +92,6 @@ Detailed layout definitions: `references/elements/canvas.md`
| Fun, exciting, wow, amazing | `pop` | sparse/list | | Fun, exciting, wow, amazing | `pop` | sparse/list |
| Knowledge, concept, productivity, SaaS | `notion` | dense/list | | Knowledge, concept, productivity, SaaS | `notion` | dense/list |
| Education, tutorial, learning, teaching, classroom | `chalkboard` | balanced/dense | | Education, tutorial, learning, teaching, classroom | `chalkboard` | balanced/dense |
| Notes, hand-drawn, infographic, study, mindmap, Morandi | `notebook` | mindmap/balanced/dense |
| Notes, handwritten, study guide, knowledge, realistic, photo | `study-notes` | dense/list/mindmap | | Notes, handwritten, study guide, knowledge, realistic, photo | `study-notes` | dense/list/mindmap |
## Outline Strategies ## Outline Strategies
@@ -170,7 +168,9 @@ Copy and track progress:
``` ```
XHS Infographic Progress: XHS Infographic Progress:
- [ ] Step 0: Check preferences (EXTEND.md) ⚠️ REQUIRED if not found - [ ] Step 0: Check preferences (EXTEND.md) ⛔ BLOCKING
- [ ] Found → load preferences → continue
- [ ] Not found → run first-time setup → MUST complete before Step 1
- [ ] Step 1: Analyze content → analysis.md - [ ] Step 1: Analyze content → analysis.md
- [ ] Step 2: Confirmation 1 - Content understanding ⚠️ REQUIRED - [ ] Step 2: Confirmation 1 - Content understanding ⚠️ REQUIRED
- [ ] Step 3: Generate 3 outline + style variants - [ ] Step 3: Generate 3 outline + style variants
@@ -182,12 +182,22 @@ XHS Infographic Progress:
### Flow ### Flow
``` ```
Input → Analyze → [Confirm 1] → 3 Outlines → [Confirm 2: Outline + Style + Elements] → Generate → Complete Input → [Step 0: Preferences] ─┬─ Found → Continue
└─ Not found → First-Time Setup ⛔ BLOCKING
└─ Complete setup → Save EXTEND.md → Continue
┌───────────────────────────────────────────────────────────────────────────┘
Analyze → [Confirm 1] → 3 Outlines → [Confirm 2: Outline + Style + Elements] → Generate → Complete
``` ```
### Step 0: Load Preferences (EXTEND.md) ⚠️ ### Step 0: Load Preferences (EXTEND.md) ⛔ BLOCKING
**Purpose**: Load user preferences or run first-time setup. **Do NOT skip setup if EXTEND.md not found.** **Purpose**: Load user preferences or run first-time setup.
**CRITICAL**: If EXTEND.md not found, MUST complete first-time setup before ANY other questions or steps. Do NOT proceed to content analysis, do NOT ask about style, do NOT ask about layout — ONLY complete the preferences setup first.
Use Bash to check EXTEND.md existence (priority order): Use Bash to check EXTEND.md existence (priority order):
@@ -207,13 +217,13 @@ test -f "$HOME/.baoyu-skills/baoyu-xhs-images/EXTEND.md" && echo "user"
│ $HOME/.baoyu-skills/baoyu-xhs-images/EXTEND.md │ User home │ │ $HOME/.baoyu-skills/baoyu-xhs-images/EXTEND.md │ User home │
└────────────────────────────────────────────────────┴───────────────────┘ └────────────────────────────────────────────────────┴───────────────────┘
┌───────────┬───────────────────────────────────────────────────────────────────────────┐ ┌───────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────
│ Result │ Action │ │ Result │ Action │
├───────────┼───────────────────────────────────────────────────────────────────────────┤ ├───────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────
│ Found │ Read, parse, display summary → Continue to Step 1 │ │ Found │ Read, parse, display summary → Continue to Step 1 │
├───────────┼───────────────────────────────────────────────────────────────────────────┤ ├───────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────
│ Not found │ ⚠️ MUST run first-time setup (see below) → Then continue to Step 1 │ Not found │ ⛔ BLOCKING: Run first-time setup ONLY (see below) → Complete and save EXTEND.md → Then Step 1 │
└───────────┴───────────────────────────────────────────────────────────────────────────┘ └───────────┴─────────────────────────────────────────────────────────────────────────────────────────────────────
**First-Time Setup** (when EXTEND.md not found): **First-Time Setup** (when EXTEND.md not found):
@@ -233,6 +243,7 @@ Read source content, save it if needed, and perform deep analysis.
1. **Save source content** (if not already a file): 1. **Save source content** (if not already a file):
- If user provides a file path: use as-is - If user provides a file path: use as-is
- If user pastes content: save to `source.md` in target directory - If user pastes content: save to `source.md` in target directory
- **Backup rule**: If `source.md` exists, rename to `source-backup-YYYYMMDD-HHMMSS.md`
2. Read source content 2. Read source content
3. **Deep analysis** following `references/workflows/analysis-framework.md`: 3. **Deep analysis** following `references/workflows/analysis-framework.md`:
- Content type classification (种草/干货/测评/教程/避坑...) - Content type classification (种草/干货/测评/教程/避坑...)
@@ -359,7 +370,9 @@ With confirmed outline + style + layout:
**For each image (cover + content + ending)**: **For each image (cover + content + ending)**:
1. Save prompt to `prompts/NN-{type}-[slug].md` (in user's preferred language) 1. Save prompt to `prompts/NN-{type}-[slug].md` (in user's preferred language)
- **Backup rule**: If prompt file exists, rename to `prompts/NN-{type}-[slug]-backup-YYYYMMDD-HHMMSS.md`
2. Generate image using confirmed style and layout 2. Generate image using confirmed style and layout
- **Backup rule**: If image file exists, rename to `NN-{type}-[slug]-backup-YYYYMMDD-HHMMSS.png`
3. Report progress after each generation 3. Report progress after each generation
**Watermark Application** (if enabled in preferences): **Watermark Application** (if enabled in preferences):
@@ -434,7 +447,6 @@ Files:
| pop | ✓✓ | ✓✓ | ✓ | ✓✓ | ✓✓ | ✓ | ✓ | ✓ | | pop | ✓✓ | ✓✓ | ✓ | ✓✓ | ✓✓ | ✓ | ✓ | ✓ |
| notion | ✓✓ | ✓✓ | ✓✓ | ✓✓ | ✓✓ | ✓✓ | ✓✓ | ✓✓ | | notion | ✓✓ | ✓✓ | ✓✓ | ✓✓ | ✓✓ | ✓✓ | ✓✓ | ✓✓ |
| chalkboard | ✓✓ | ✓✓ | ✓✓ | ✓✓ | ✓ | ✓✓ | ✓✓ | ✓ | | chalkboard | ✓✓ | ✓✓ | ✓✓ | ✓✓ | ✓ | ✓✓ | ✓✓ | ✓ |
| notebook | ✓✓ | ✓✓ | ✓✓ | ✓✓ | ✓✓ | ✓✓ | ✓✓ | ✓✓ |
| study-notes | ✗ | ✓ | ✓✓ | ✓✓ | ✓ | ✓ | ✓✓ | ✓ | | study-notes | ✗ | ✓ | ✓✓ | ✓✓ | ✓ | ✓ | ✓✓ | ✓ |
## References ## References
@@ -9,6 +9,14 @@ description: First-time setup flow for baoyu-xhs-images preferences
When no EXTEND.md is found, guide user through preference setup. When no EXTEND.md is found, guide user through preference setup.
**⛔ BLOCKING OPERATION**: This setup MUST complete before ANY other workflow steps. Do NOT:
- Ask about content/article
- Ask about style or layout
- Ask about target audience
- Proceed to content analysis
ONLY ask the questions in this setup flow, save EXTEND.md, then continue.
## Setup Flow ## Setup Flow
``` ```
@@ -1,76 +0,0 @@
---
name: notebook
category: educational
---
# Notebook Style
Hand-drawn infographic / study notes aesthetic with watercolor rendering and Morandi color palette.
## Element Combination
```yaml
canvas:
ratio: portrait-3-4
grid: single | dual | triptych
image_effects:
cutout: soft
stroke: none | watercolor-edge
filter: muted-tones | morandi
typography:
decorated: watercolor-highlight | handwritten-bold
tags: pill | rounded-rect
direction: horizontal
decorations:
emphasis: circle-mark | underline | checkmark
background: paper-texture | watercolor-wash
doodles: hand-drawn-lines | mindmap-nodes | speech-bubbles | hearts | peace-dove
frames: rounded-rect | none
```
## Color Palette (Morandi Tones)
| Role | Colors | Hex |
|------|--------|-----|
| Primary | Sage green, Teal | #A8B5A0, #4A7C7C |
| Background | Off-white, Warm paper | #FAF8F5, #F5F0E8 |
| Accents | Dust blue, Warm grey, Terracotta | #8FA3B0, #9A9590, #C4A484 |
## Visual Elements
- Bold handwritten titles with watercolor wash blocks (sage green/teal backgrounds)
- Black line illustrations, slightly imperfect, simulating ink effect
- Soft paper texture background, mimicking watercolor paper
- Mindmap nodes, list boxes, explanatory doodles
- Symbolic icons: hearts, speech bubbles, peace dove, handshake
- Flat lighting, vector illustration feel with analog texture
## Typography
- Bold handwritten fonts
- Watercolor wash effect backgrounds
- Clear and readable, CJK optimized
## Best Layout Pairings
| Layout | Compatibility | Use Case |
|--------|---------------|----------|
| sparse | ✓✓ | Covers, quotes |
| balanced | ✓✓ | Standard content cards |
| dense | ✓✓ | Knowledge cards, checklists |
| list | ✓✓ | Step guides, rankings |
| comparison | ✓✓ | Before/after, contrasts |
| flow | ✓✓ | Processes, timelines |
| mindmap | ✓✓ | Mind maps |
| quadrant | ✓✓ | Quadrant analysis, circular sections |
## Best For
- Study notes, knowledge summaries
- Mind maps, infographics
- Tutorials, knowledge sharing
- Bullet journal style content
- Concept explanations, framework overviews