mirror of
https://github.com/JimLiu/baoyu-skills.git
synced 2026-07-12 22:09:48 +08:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bb4f0dc52c | |||
| c731faea8f | |||
| fa155da15d | |||
| 6194f71378 | |||
| 8e88cf4a8b | |||
| 259baff413 | |||
| a42137ff13 | |||
| c6d96d4134 | |||
| e174d642df | |||
| db7eaa2847 |
@@ -6,7 +6,7 @@
|
||||
},
|
||||
"metadata": {
|
||||
"description": "Skills shared by Baoyu for improving daily work efficiency",
|
||||
"version": "0.4.1"
|
||||
"version": "0.6.1"
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
@@ -21,7 +21,8 @@
|
||||
"./skills/baoyu-post-to-wechat",
|
||||
"./skills/baoyu-article-illustrator",
|
||||
"./skills/baoyu-cover-image",
|
||||
"./skills/baoyu-slide-deck"
|
||||
"./skills/baoyu-slide-deck",
|
||||
"./skills/baoyu-comic"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -71,6 +71,30 @@ npx -y bun skills/baoyu-gemini-web/scripts/main.ts --promptfiles system.md conte
|
||||
2. Add TypeScript in `skills/baoyu-<name>/scripts/`
|
||||
3. Add prompt templates in `skills/baoyu-<name>/prompts/` if needed
|
||||
4. Register in `marketplace.json` plugins[0].skills array as `./skills/baoyu-<name>`
|
||||
5. **Add Script Directory section** to SKILL.md (see template below)
|
||||
|
||||
### Script Directory Template
|
||||
|
||||
Every SKILL.md with scripts MUST include this section after Usage:
|
||||
|
||||
```markdown
|
||||
## Script Directory
|
||||
|
||||
**Important**: All scripts are located in the `scripts/` subdirectory of this skill.
|
||||
|
||||
**Agent Execution Instructions**:
|
||||
1. Determine this SKILL.md file's directory path as `SKILL_DIR`
|
||||
2. Script path = `${SKILL_DIR}/scripts/<script-name>.ts`
|
||||
3. Replace all `${SKILL_DIR}` in this document with the actual path
|
||||
|
||||
**Script Reference**:
|
||||
| Script | Purpose |
|
||||
|--------|---------|
|
||||
| `scripts/main.ts` | Main entry point |
|
||||
| `scripts/other.ts` | Other functionality |
|
||||
```
|
||||
|
||||
When referencing scripts in workflow sections, use `${SKILL_DIR}/scripts/<name>.ts` so agents can resolve the correct path.
|
||||
|
||||
## Code Style
|
||||
|
||||
|
||||
@@ -11,6 +11,12 @@ Skills shared by Baoyu for improving daily work efficiency with Claude Code.
|
||||
|
||||
## Installation
|
||||
|
||||
### Quick Install (Recommended)
|
||||
|
||||
```bash
|
||||
npx add-skill jimliu/baoyu-skills
|
||||
```
|
||||
|
||||
### Register as Plugin Marketplace
|
||||
|
||||
Run the following command in Claude Code:
|
||||
@@ -55,43 +61,43 @@ You can also **Enable auto-update** to get the latest versions automatically.
|
||||
|
||||
## Available Skills
|
||||
|
||||
### gemini-web
|
||||
### baoyu-gemini-web
|
||||
|
||||
Interacts with Gemini Web to generate text and images.
|
||||
|
||||
**Text Generation:**
|
||||
|
||||
```bash
|
||||
/gemini-web "Hello, Gemini"
|
||||
/gemini-web --prompt "Explain quantum computing"
|
||||
/baoyu-gemini-web "Hello, Gemini"
|
||||
/baoyu-gemini-web --prompt "Explain quantum computing"
|
||||
```
|
||||
|
||||
**Image Generation:**
|
||||
|
||||
```bash
|
||||
/gemini-web --prompt "A cute cat" --image cat.png
|
||||
/gemini-web --promptfiles system.md content.md --image out.png
|
||||
/baoyu-gemini-web --prompt "A cute cat" --image cat.png
|
||||
/baoyu-gemini-web --promptfiles system.md content.md --image out.png
|
||||
```
|
||||
|
||||
### xhs-images
|
||||
### baoyu-xhs-images
|
||||
|
||||
Xiaohongshu (RedNote) infographic series generator. Breaks down content into 1-10 cartoon-style infographics with **Style × Layout** two-dimensional system.
|
||||
|
||||
```bash
|
||||
# Auto-select style and layout
|
||||
/xhs-images posts/ai-future/article.md
|
||||
/baoyu-xhs-images posts/ai-future/article.md
|
||||
|
||||
# Specify style
|
||||
/xhs-images posts/ai-future/article.md --style notion
|
||||
/baoyu-xhs-images posts/ai-future/article.md --style notion
|
||||
|
||||
# Specify layout
|
||||
/xhs-images posts/ai-future/article.md --layout dense
|
||||
/baoyu-xhs-images posts/ai-future/article.md --layout dense
|
||||
|
||||
# Combine style and layout
|
||||
/xhs-images posts/ai-future/article.md --style tech --layout list
|
||||
/baoyu-xhs-images posts/ai-future/article.md --style tech --layout list
|
||||
|
||||
# Direct content input
|
||||
/xhs-images 今日星座运势
|
||||
/baoyu-xhs-images 今日星座运势
|
||||
```
|
||||
|
||||
**Styles** (visual aesthetics): `cute` (default), `fresh`, `tech`, `warm`, `bold`, `minimal`, `retro`, `pop`, `notion`
|
||||
@@ -106,70 +112,128 @@ Xiaohongshu (RedNote) infographic series generator. Breaks down content into 1-1
|
||||
| `comparison` | 2 sides | Before/after, pros/cons |
|
||||
| `flow` | 3-6 steps | Processes, timelines |
|
||||
|
||||
### cover-image
|
||||
### baoyu-cover-image
|
||||
|
||||
Generate hand-drawn style cover images for articles with multiple style options.
|
||||
|
||||
```bash
|
||||
# From markdown file (auto-select style)
|
||||
/cover-image path/to/article.md
|
||||
/baoyu-cover-image path/to/article.md
|
||||
|
||||
# Specify a style
|
||||
/cover-image path/to/article.md --style tech
|
||||
/cover-image path/to/article.md --style warm
|
||||
/baoyu-cover-image path/to/article.md --style tech
|
||||
/baoyu-cover-image path/to/article.md --style warm
|
||||
|
||||
# Without title text
|
||||
/cover-image path/to/article.md --no-title
|
||||
/baoyu-cover-image path/to/article.md --no-title
|
||||
```
|
||||
|
||||
Available styles: `elegant` (default), `tech`, `warm`, `bold`, `minimal`, `playful`, `nature`, `retro`
|
||||
|
||||
### slide-deck
|
||||
### baoyu-slide-deck
|
||||
|
||||
Generate professional slide deck images from content. Creates comprehensive outlines with style instructions, then generates individual slide images.
|
||||
|
||||
```bash
|
||||
# From markdown file
|
||||
/slide-deck path/to/article.md
|
||||
/baoyu-slide-deck path/to/article.md
|
||||
|
||||
# With style and audience
|
||||
/slide-deck path/to/article.md --style corporate
|
||||
/slide-deck path/to/article.md --audience executives
|
||||
/baoyu-slide-deck path/to/article.md --style corporate
|
||||
/baoyu-slide-deck path/to/article.md --audience executives
|
||||
|
||||
# Outline only (no image generation)
|
||||
/slide-deck path/to/article.md --outline-only
|
||||
/baoyu-slide-deck path/to/article.md --outline-only
|
||||
|
||||
# With language
|
||||
/slide-deck path/to/article.md --lang zh
|
||||
/baoyu-slide-deck path/to/article.md --lang zh
|
||||
```
|
||||
|
||||
Available styles: `editorial` (default), `corporate`, `technical`, `playful`, `minimal`, `storytelling`, `warm`, `retro-flat`, `notion`
|
||||
**Styles** (visual aesthetics):
|
||||
|
||||
### post-to-wechat
|
||||
| Style | Description | Best For |
|
||||
|-------|-------------|----------|
|
||||
| `notion` (default) | SaaS dashboard aesthetic with clean data focus, card-based layouts | Product demos, SaaS, productivity tools, B2B |
|
||||
| `sketch-notes` | Hand-drawn feel with soft brush strokes, warm off-white background | Educational, tutorials, knowledge sharing |
|
||||
| `blueprint` | Technical schematics with grid texture, engineering precision | Architecture, system design, data analysis |
|
||||
| `bold-editorial` | High-impact magazine style, bold typography, dark backgrounds | Product launches, marketing, keynotes |
|
||||
| `vector-illustration` | Flat vector with black outlines, retro soft colors, toy model aesthetic | Creative proposals, children's content, explainers |
|
||||
| `minimal` | Ultra-clean with maximum whitespace, single accent color, zen-like | Executive briefings, keynotes, premium brands |
|
||||
| `storytelling` | Cinematic full-bleed visuals, emotional photography | Case studies, narratives, customer journeys |
|
||||
| `warm` | Soft gradients, rounded shapes, wellness palette | Lifestyle, wellness, personal development |
|
||||
| `corporate` | Navy/gold palette, structured layouts, professional iconography | Investor decks, client proposals, quarterly reports |
|
||||
| `playful` | Vibrant coral/teal/yellow, rounded shapes, dynamic layouts | Workshops, training, creative pitches |
|
||||
|
||||
After generation, slides are automatically merged into a `.pptx` file for easy sharing.
|
||||
|
||||
### baoyu-comic
|
||||
|
||||
Knowledge comic creator supporting multiple styles (Logicomix/Ligne Claire, Ohmsha manga guide). Creates original educational comics with detailed panel layouts and sequential image generation.
|
||||
|
||||
```bash
|
||||
# From source material
|
||||
/baoyu-comic posts/turing-story/source.md
|
||||
|
||||
# Specify style
|
||||
/baoyu-comic posts/turing-story/source.md --style dramatic
|
||||
/baoyu-comic posts/turing-story/source.md --style ohmsha
|
||||
|
||||
# Specify layout
|
||||
/baoyu-comic posts/turing-story/source.md --layout cinematic
|
||||
/baoyu-comic posts/turing-story/source.md --layout webtoon
|
||||
|
||||
# Direct content input
|
||||
/baoyu-comic "The story of Alan Turing and the birth of computer science"
|
||||
```
|
||||
|
||||
**Styles** (visual aesthetics):
|
||||
|
||||
| Style | Description | Best For |
|
||||
|-------|-------------|----------|
|
||||
| `classic` (default) | Traditional Ligne Claire with clean uniform outlines, flat colors, detailed backgrounds | Biographies, balanced narratives, educational content |
|
||||
| `dramatic` | High contrast with heavy shadows, intense expressions, angular compositions | Pivotal discoveries, conflicts, climactic scenes |
|
||||
| `warm` | Soft edges, golden tones, cozy interiors with nostalgic feel | Personal stories, childhood scenes, mentorship |
|
||||
| `tech` | Precise geometric lines, circuit motifs, neon accents on dark backgrounds | Computing history, AI stories, modern tech |
|
||||
| `sepia` | Vintage illustration style with aged paper effect, period-accurate details | Pre-1950s stories, classical science, historical figures |
|
||||
| `vibrant` | Energetic lines with weight variation, bright colors, dynamic poses | Science explanations, "aha" moments, young audience |
|
||||
| `ohmsha` | Manga guide style with visual metaphors, gadgets, student/mentor dynamic | Technical tutorials, complex concepts (ML, physics) |
|
||||
| `realistic` | Full-color realistic manga with digital painting, smooth gradients, accurate proportions | Wine, food, business, lifestyle, professional topics |
|
||||
|
||||
**Layouts** (panel arrangement):
|
||||
| Layout | Panels/Page | Best for |
|
||||
|--------|-------------|----------|
|
||||
| `standard` | 4-6 | Dialogue, narrative flow |
|
||||
| `cinematic` | 2-4 | Dramatic moments, establishing shots |
|
||||
| `dense` | 6-9 | Technical explanations, timelines |
|
||||
| `splash` | 1-2 large | Key moments, revelations |
|
||||
| `mixed` | 3-7 varies | Complex narratives, emotional arcs |
|
||||
| `webtoon` | 3-5 vertical | Ohmsha tutorials, mobile reading |
|
||||
|
||||
### baoyu-post-to-wechat
|
||||
|
||||
Post content to WeChat Official Account (微信公众号). Two modes available:
|
||||
|
||||
**Image-Text (图文)** - Multiple images with short title/content:
|
||||
|
||||
```bash
|
||||
/post-to-wechat 图文 --markdown article.md --images ./photos/
|
||||
/post-to-wechat 图文 --markdown article.md --image img1.png --image img2.png --image img3.png
|
||||
/post-to-wechat 图文 --title "标题" --content "内容" --image img1.png --submit
|
||||
/baoyu-post-to-wechat 图文 --markdown article.md --images ./photos/
|
||||
/baoyu-post-to-wechat 图文 --markdown article.md --image img1.png --image img2.png --image img3.png
|
||||
/baoyu-post-to-wechat 图文 --title "标题" --content "内容" --image img1.png --submit
|
||||
```
|
||||
|
||||
**Article (文章)** - Full markdown/HTML with rich formatting:
|
||||
|
||||
```bash
|
||||
/post-to-wechat 文章 --markdown article.md
|
||||
/post-to-wechat 文章 --markdown article.md --theme grace
|
||||
/post-to-wechat 文章 --html article.html
|
||||
/baoyu-post-to-wechat 文章 --markdown article.md
|
||||
/baoyu-post-to-wechat 文章 --markdown article.md --theme grace
|
||||
/baoyu-post-to-wechat 文章 --html article.html
|
||||
```
|
||||
|
||||
Prerequisites: Google Chrome installed. First run requires QR code login (session preserved).
|
||||
|
||||
## Disclaimer
|
||||
|
||||
### gemini-web
|
||||
### baoyu-gemini-web
|
||||
|
||||
This skill uses the Gemini Web API (reverse-engineered).
|
||||
|
||||
|
||||
+95
-31
@@ -11,6 +11,12 @@
|
||||
|
||||
## 安装
|
||||
|
||||
### 快速安装(推荐)
|
||||
|
||||
```bash
|
||||
npx add-skill jimliu/baoyu-skills
|
||||
```
|
||||
|
||||
### 注册插件市场
|
||||
|
||||
在 Claude Code 中运行:
|
||||
@@ -55,43 +61,43 @@
|
||||
|
||||
## 可用技能
|
||||
|
||||
### gemini-web
|
||||
### baoyu-gemini-web
|
||||
|
||||
与 Gemini Web 交互,生成文本和图片。
|
||||
|
||||
**文本生成:**
|
||||
|
||||
```bash
|
||||
/gemini-web "你好,Gemini"
|
||||
/gemini-web --prompt "解释量子计算"
|
||||
/baoyu-gemini-web "你好,Gemini"
|
||||
/baoyu-gemini-web --prompt "解释量子计算"
|
||||
```
|
||||
|
||||
**图片生成:**
|
||||
|
||||
```bash
|
||||
/gemini-web --prompt "一只可爱的猫" --image cat.png
|
||||
/gemini-web --promptfiles system.md content.md --image out.png
|
||||
/baoyu-gemini-web --prompt "一只可爱的猫" --image cat.png
|
||||
/baoyu-gemini-web --promptfiles system.md content.md --image out.png
|
||||
```
|
||||
|
||||
### xhs-images
|
||||
### baoyu-xhs-images
|
||||
|
||||
小红书信息图系列生成器。将内容拆解为 1-10 张卡通风格信息图,支持 **风格 × 布局** 二维系统。
|
||||
|
||||
```bash
|
||||
# 自动选择风格和布局
|
||||
/xhs-images posts/ai-future/article.md
|
||||
/baoyu-xhs-images posts/ai-future/article.md
|
||||
|
||||
# 指定风格
|
||||
/xhs-images posts/ai-future/article.md --style notion
|
||||
/baoyu-xhs-images posts/ai-future/article.md --style notion
|
||||
|
||||
# 指定布局
|
||||
/xhs-images posts/ai-future/article.md --layout dense
|
||||
/baoyu-xhs-images posts/ai-future/article.md --layout dense
|
||||
|
||||
# 组合风格和布局
|
||||
/xhs-images posts/ai-future/article.md --style tech --layout list
|
||||
/baoyu-xhs-images posts/ai-future/article.md --style tech --layout list
|
||||
|
||||
# 直接输入内容
|
||||
/xhs-images 今日星座运势
|
||||
/baoyu-xhs-images 今日星座运势
|
||||
```
|
||||
|
||||
**风格**(视觉美学):`cute`(默认)、`fresh`、`tech`、`warm`、`bold`、`minimal`、`retro`、`pop`、`notion`
|
||||
@@ -106,70 +112,128 @@
|
||||
| `comparison` | 双栏 | 对比、优劣 |
|
||||
| `flow` | 3-6 步 | 流程、时间线 |
|
||||
|
||||
### cover-image
|
||||
### baoyu-cover-image
|
||||
|
||||
为文章生成手绘风格封面图,支持多种风格选项。
|
||||
|
||||
```bash
|
||||
# 从 markdown 文件生成(自动选择风格)
|
||||
/cover-image path/to/article.md
|
||||
/baoyu-cover-image path/to/article.md
|
||||
|
||||
# 指定风格
|
||||
/cover-image path/to/article.md --style tech
|
||||
/cover-image path/to/article.md --style warm
|
||||
/baoyu-cover-image path/to/article.md --style tech
|
||||
/baoyu-cover-image path/to/article.md --style warm
|
||||
|
||||
# 不包含标题文字
|
||||
/cover-image path/to/article.md --no-title
|
||||
/baoyu-cover-image path/to/article.md --no-title
|
||||
```
|
||||
|
||||
可用风格:`elegant`(默认)、`tech`、`warm`、`bold`、`minimal`、`playful`、`nature`、`retro`
|
||||
|
||||
### slide-deck
|
||||
### baoyu-slide-deck
|
||||
|
||||
从内容生成专业的幻灯片图片。先创建包含样式说明的完整大纲,然后逐页生成幻灯片图片。
|
||||
|
||||
```bash
|
||||
# 从 markdown 文件生成
|
||||
/slide-deck path/to/article.md
|
||||
/baoyu-slide-deck path/to/article.md
|
||||
|
||||
# 指定风格和受众
|
||||
/slide-deck path/to/article.md --style corporate
|
||||
/slide-deck path/to/article.md --audience executives
|
||||
/baoyu-slide-deck path/to/article.md --style corporate
|
||||
/baoyu-slide-deck path/to/article.md --audience executives
|
||||
|
||||
# 仅生成大纲(不生成图片)
|
||||
/slide-deck path/to/article.md --outline-only
|
||||
/baoyu-slide-deck path/to/article.md --outline-only
|
||||
|
||||
# 指定语言
|
||||
/slide-deck path/to/article.md --lang zh
|
||||
/baoyu-slide-deck path/to/article.md --lang zh
|
||||
```
|
||||
|
||||
可用风格:`editorial`(默认)、`corporate`、`technical`、`playful`、`minimal`、`storytelling`、`warm`、`retro-flat`、`notion`
|
||||
**风格**(视觉美学):
|
||||
|
||||
### post-to-wechat
|
||||
| 风格 | 描述 | 适用场景 |
|
||||
|------|------|----------|
|
||||
| `notion`(默认) | SaaS 仪表盘美学,卡片式布局,数据展示清晰 | 产品演示、SaaS、生产力工具、B2B |
|
||||
| `sketch-notes` | 手绘风格,柔和笔触,暖白色背景 | 教育、教程、知识分享 |
|
||||
| `blueprint` | 技术蓝图风格,网格纹理,工程精度 | 架构设计、系统设计、数据分析 |
|
||||
| `bold-editorial` | 杂志社论风格,粗体排版,深色背景,高冲击力 | 产品发布、营销、主题演讲 |
|
||||
| `vector-illustration` | 扁平矢量风格,黑色轮廓线,复古柔和配色,玩具模型感 | 创意提案、儿童内容、说明性内容 |
|
||||
| `minimal` | 极简风格,大量留白,单一强调色,禅意美学 | 高管简报、主题演讲、高端品牌 |
|
||||
| `storytelling` | 电影风格,全幅视觉,情感化摄影 | 案例研究、叙事、客户旅程 |
|
||||
| `warm` | 柔和渐变,圆润形状,健康生活配色 | 生活方式、健康养生、个人成长 |
|
||||
| `corporate` | 海军蓝/金色配色,结构化布局,专业图标 | 投资者演示、客户提案、季度报告 |
|
||||
| `playful` | 活力珊瑚/青色/黄色,圆润形状,动感布局 | 工作坊、培训、创意提案 |
|
||||
|
||||
生成完成后,所有幻灯片会自动合并为 `.pptx` 文件,方便分享。
|
||||
|
||||
### baoyu-comic
|
||||
|
||||
知识漫画创作器,支持多种风格(Logicomix/清线风格、欧姆社漫画教程风格)。创作带有详细分镜布局的原创教育漫画,逐页生成图片。
|
||||
|
||||
```bash
|
||||
# 从素材文件生成
|
||||
/baoyu-comic posts/turing-story/source.md
|
||||
|
||||
# 指定风格
|
||||
/baoyu-comic posts/turing-story/source.md --style dramatic
|
||||
/baoyu-comic posts/turing-story/source.md --style ohmsha
|
||||
|
||||
# 指定布局
|
||||
/baoyu-comic posts/turing-story/source.md --layout cinematic
|
||||
/baoyu-comic posts/turing-story/source.md --layout webtoon
|
||||
|
||||
# 直接输入内容
|
||||
/baoyu-comic "图灵的故事与计算机科学的诞生"
|
||||
```
|
||||
|
||||
**风格**(视觉美学):
|
||||
|
||||
| 风格 | 描述 | 适用场景 |
|
||||
|------|------|----------|
|
||||
| `classic`(默认) | 传统清线风格,统一线条、平涂色彩、精细背景 | 传记、平衡叙事、教育内容 |
|
||||
| `dramatic` | 高对比度,重阴影、紧张表情、棱角分明的构图 | 重大发现、冲突、高潮场景 |
|
||||
| `warm` | 柔和边缘、金色调、温馨室内、怀旧感 | 个人故事、童年场景、师生情 |
|
||||
| `tech` | 精确几何线条、电路纹理、深色背景配霓虹色 | 计算机史、AI 故事、现代科技 |
|
||||
| `sepia` | 复古插画风格、做旧纸张效果、时代准确细节 | 1950 年前故事、古典科学、历史人物 |
|
||||
| `vibrant` | 富有活力的线条、明亮色彩、动感姿态 | 科学解说、"顿悟"时刻、青少年读者 |
|
||||
| `ohmsha` | 欧姆社漫画风格,视觉比喻、道具、学生/导师互动 | 技术教程、复杂概念(机器学习、物理) |
|
||||
| `realistic` | 全彩写实日漫风格,数字绘画、平滑渐变、准确人体比例 | 红酒、美食、商业、生活方式、专业话题 |
|
||||
|
||||
**布局**(分镜排列):
|
||||
| 布局 | 每页分镜数 | 适用场景 |
|
||||
|------|-----------|----------|
|
||||
| `standard` | 4-6 | 对话、叙事推进 |
|
||||
| `cinematic` | 2-4 | 戏剧性时刻、建立镜头 |
|
||||
| `dense` | 6-9 | 技术说明、时间线 |
|
||||
| `splash` | 1-2 大图 | 关键时刻、揭示 |
|
||||
| `mixed` | 3-7 不等 | 复杂叙事、情感弧线 |
|
||||
| `webtoon` | 3-5 竖向 | 欧姆社教程、手机阅读 |
|
||||
|
||||
### baoyu-post-to-wechat
|
||||
|
||||
发布内容到微信公众号,支持两种模式:
|
||||
|
||||
**图文模式** - 多图配短标题和正文:
|
||||
|
||||
```bash
|
||||
/post-to-wechat 图文 --markdown article.md --images ./photos/
|
||||
/post-to-wechat 图文 --markdown article.md --image img1.png --image img2.png --image img3.png
|
||||
/post-to-wechat 图文 --title "标题" --content "内容" --image img1.png --submit
|
||||
/baoyu-post-to-wechat 图文 --markdown article.md --images ./photos/
|
||||
/baoyu-post-to-wechat 图文 --markdown article.md --image img1.png --image img2.png --image img3.png
|
||||
/baoyu-post-to-wechat 图文 --title "标题" --content "内容" --image img1.png --submit
|
||||
```
|
||||
|
||||
**文章模式** - 完整 markdown/HTML 富文本格式:
|
||||
|
||||
```bash
|
||||
/post-to-wechat 文章 --markdown article.md
|
||||
/post-to-wechat 文章 --markdown article.md --theme grace
|
||||
/post-to-wechat 文章 --html article.html
|
||||
/baoyu-post-to-wechat 文章 --markdown article.md
|
||||
/baoyu-post-to-wechat 文章 --markdown article.md --theme grace
|
||||
/baoyu-post-to-wechat 文章 --html article.html
|
||||
```
|
||||
|
||||
前置要求:已安装 Google Chrome,首次运行需扫码登录(登录状态会保存)
|
||||
|
||||
## 免责声明
|
||||
|
||||
### gemini-web
|
||||
### baoyu-gemini-web
|
||||
|
||||
此技能使用 Gemini Web API(逆向工程)。
|
||||
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
---
|
||||
name: baoyu-comic
|
||||
description: Knowledge comic creator supporting multiple styles (Logicomix/Ligne Claire, Ohmsha manga guide). Creates original educational comics with detailed panel layouts and sequential image generation. Use when user asks to create "知识漫画", "教育漫画", "biography comic", "tutorial comic", or "Logicomix-style comic".
|
||||
---
|
||||
|
||||
# Knowledge Comic Creator
|
||||
|
||||
Create original knowledge comics with multiple visual styles.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
/baoyu-comic posts/turing-story/source.md
|
||||
/baoyu-comic posts/turing-story/source.md --style dramatic --layout cinematic
|
||||
/baoyu-comic # then paste content
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
| Option | Values |
|
||||
|--------|--------|
|
||||
| `--style` | classic (default), dramatic, warm, tech, sepia, vibrant, ohmsha, realistic |
|
||||
| `--layout` | standard (default), cinematic, dense, splash, mixed, webtoon |
|
||||
|
||||
Style × Layout can be freely combined.
|
||||
|
||||
## Auto Selection
|
||||
|
||||
| Content Signals | Style | Layout |
|
||||
|-----------------|-------|--------|
|
||||
| Tutorial, how-to, beginner | ohmsha | webtoon |
|
||||
| Computing, AI, programming | tech | dense |
|
||||
| Pre-1950, classical, ancient | sepia | cinematic |
|
||||
| Personal story, mentor | warm | standard |
|
||||
| Conflict, breakthrough | dramatic | splash |
|
||||
| Wine, food, business, lifestyle, professional | realistic | cinematic |
|
||||
| Biography, balanced | classic | mixed |
|
||||
|
||||
## Script Directory
|
||||
|
||||
**Important**: All scripts are located in the `scripts/` subdirectory of this skill.
|
||||
|
||||
**Agent Execution Instructions**:
|
||||
1. Determine this SKILL.md file's directory path as `SKILL_DIR`
|
||||
2. Script path = `${SKILL_DIR}/scripts/<script-name>.ts`
|
||||
3. Replace all `${SKILL_DIR}` in this document with the actual path
|
||||
|
||||
**Script Reference**:
|
||||
| Script | Purpose |
|
||||
|--------|---------|
|
||||
| `scripts/merge-to-pdf.ts` | Merge comic pages into PDF |
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
[target]/
|
||||
├── outline.md
|
||||
├── characters/
|
||||
│ ├── characters.md # Character definitions
|
||||
│ └── characters.png # Character reference sheet
|
||||
├── prompts/
|
||||
│ ├── 00-cover.md
|
||||
│ └── XX-page.md
|
||||
├── 00-cover.png
|
||||
├── XX-page.png
|
||||
└── {topic-slug}.pdf
|
||||
```
|
||||
|
||||
**Target directory**:
|
||||
- With source path: `[source-dir]/comic/`
|
||||
- Without source: `comic-outputs/YYYY-MM-DD/[topic-slug]/`
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Analyze Content
|
||||
|
||||
1. Read source content
|
||||
2. Select style (from `--style` or auto-detect)
|
||||
3. Select layout (from `--layout` or auto-detect per page)
|
||||
4. Determine page count:
|
||||
- Short story: 5-8 pages
|
||||
- Medium complexity: 9-15 pages
|
||||
- Full biography: 16-25 pages
|
||||
|
||||
### Step 2: Define Characters
|
||||
|
||||
**Purpose**: Establish visual consistency across all pages.
|
||||
|
||||
1. Extract all characters from content (protagonist, supporting, antagonist, narrator)
|
||||
2. Create `characters/characters.md` with visual specs for each character
|
||||
3. Generate `characters/characters.png` (character reference sheet)
|
||||
|
||||
**Reference**: `references/character-template.md` for detailed format and examples.
|
||||
|
||||
### Step 3: Generate Outline
|
||||
|
||||
Create `outline.md` with:
|
||||
- Metadata (title, style, layout, page count, character reference path)
|
||||
- Cover design
|
||||
- Each page: layout, panel breakdown, visual prompts
|
||||
|
||||
**Reference**: `references/outline-template.md` for detailed format.
|
||||
|
||||
### Step 4: Generate Images
|
||||
|
||||
For each page (cover + pages):
|
||||
|
||||
1. Save prompt to `prompts/XX-page.md`
|
||||
2. Call image generation skill with:
|
||||
- Base prompt: `references/base-prompt.md`
|
||||
- Character reference (text or image, depending on skill capability)
|
||||
- Page prompt
|
||||
- Output path
|
||||
|
||||
**Image Generation Skill Selection**:
|
||||
- Check available image generation skills in the environment
|
||||
- If multiple skills available, ask user preference
|
||||
|
||||
**Character Reference Handling**:
|
||||
- If skill supports reference image: pass `characters/characters.png` as reference image
|
||||
- If skill does NOT support reference image: include `characters/characters.md` content in the prompt
|
||||
- This ensures character visual consistency across all pages
|
||||
|
||||
**Session Management**:
|
||||
If the image generation skill supports `--sessionId`:
|
||||
1. Generate a unique session ID at the start (e.g., `comic-{topic-slug}-{timestamp}`)
|
||||
2. Use the same session ID for character sheet and all pages
|
||||
3. This ensures visual consistency (character appearance, style) across all generated images
|
||||
|
||||
3. Report progress after each generation
|
||||
|
||||
### Step 5: Merge to PDF
|
||||
|
||||
After all images are generated, merge them into a PDF file:
|
||||
|
||||
```bash
|
||||
npx -y bun ${SKILL_DIR}/scripts/merge-to-pdf.ts <comic-dir>
|
||||
```
|
||||
|
||||
This creates `{topic-slug}.pdf` in the comic directory with all pages as full-page images.
|
||||
|
||||
### Step 6: Completion Report
|
||||
|
||||
```
|
||||
Comic Complete!
|
||||
Title: [title] | Style: [style] | Pages: [count]
|
||||
Location: [path]
|
||||
✓ characters.png
|
||||
✓ 00-cover.png ... XX-page.png
|
||||
✓ {topic-slug}.pdf
|
||||
```
|
||||
|
||||
## Style-Specific Guidelines
|
||||
|
||||
### Ohmsha Style (`--style ohmsha`)
|
||||
|
||||
Additional requirements for educational manga:
|
||||
- Default characters: Student (大雄), Mentor (哆啦A梦), Antagonist (胖虎)
|
||||
- Custom: `--characters "Student:小明,Mentor:教授"`
|
||||
- Must use visual metaphors (gadgets, action scenes) - NO talking heads
|
||||
- Page titles: narrative style, not "Page X: Topic"
|
||||
|
||||
**Reference**: `references/ohmsha-guide.md` for detailed guidelines.
|
||||
|
||||
## References
|
||||
|
||||
Detailed templates and guidelines in `references/` directory:
|
||||
- `character-template.md` - Character definition format and examples
|
||||
- `outline-template.md` - Outline structure and panel breakdown
|
||||
- `ohmsha-guide.md` - Ohmsha manga style specifics
|
||||
- `styles/` - Detailed style definitions
|
||||
- `layouts/` - Detailed layout definitions
|
||||
@@ -0,0 +1,98 @@
|
||||
Create a knowledge biography comic page following these guidelines:
|
||||
|
||||
## Image Specifications
|
||||
|
||||
- **Type**: Comic book page with multiple panels
|
||||
- **Orientation**: Portrait (vertical)
|
||||
- **Aspect Ratio**: 2:3
|
||||
- **Style**: See style-specific reference for visual guidelines
|
||||
|
||||
## Panel Structure
|
||||
|
||||
### Panel Borders
|
||||
- Clean black lines (1-2px) around each panel
|
||||
- White gutters between panels (8-12px)
|
||||
- Panels arranged for clear reading flow
|
||||
- Variety in panel sizes for visual rhythm
|
||||
|
||||
### Panel Composition
|
||||
- Clear focal points in each panel
|
||||
- Proper use of foreground, midground, background
|
||||
- Camera angles vary: eye level, bird's eye, low angle, close-up, wide shot
|
||||
- Action flows logically between panels
|
||||
- Negative space used intentionally
|
||||
|
||||
## Text Elements
|
||||
|
||||
### Speech Bubbles
|
||||
- **Dialogue**: Oval/elliptical bubbles with pointed tails
|
||||
- White fill with thin black outline
|
||||
- Tail points clearly to speaker
|
||||
- Hand-lettered style font (not computer-generated)
|
||||
|
||||
### Narrator Boxes
|
||||
- **Fourth Wall/Narrator**: Rectangular boxes
|
||||
- Often positioned at panel edges (top or bottom)
|
||||
- Slightly different fill color (cream or light yellow)
|
||||
- Used for commentary, time jumps, explanations
|
||||
|
||||
### Thought Bubbles
|
||||
- Cloud-shaped with bubble trail leading to thinker
|
||||
- Softer outline than speech bubbles
|
||||
- For internal monologue
|
||||
|
||||
### Caption Bars
|
||||
- Rectangular bars at panel edges
|
||||
- Time and place information
|
||||
- "Meanwhile...", "Three years later..." type transitions
|
||||
- Darker fill with white text, or vice versa
|
||||
|
||||
### Typography
|
||||
- Hand-drawn lettering style throughout
|
||||
- Bold for emphasis and key terms
|
||||
- Consistent letter sizing
|
||||
- Chinese text: use full-width punctuation "",。!
|
||||
- Clear hierarchy: titles > dialogue > captions
|
||||
|
||||
## Scientific/Concept Visualization
|
||||
|
||||
When depicting abstract concepts:
|
||||
|
||||
| Concept | Visual Metaphor |
|
||||
|---------|----------------|
|
||||
| Neural networks | Glowing nodes connected by clean lines |
|
||||
| Data flow | Luminous particles along simple paths |
|
||||
| Algorithms | Geometric patterns, building blocks |
|
||||
| Logic/proof | Interlocking puzzle pieces |
|
||||
| Discovery | Light breaking through darkness |
|
||||
| Uncertainty | Forking paths, question marks |
|
||||
| Time | Clock motifs, calendar pages |
|
||||
|
||||
- Integrate diagrams naturally into narrative panels
|
||||
- Use inset panels or thought-bubble style for explanations
|
||||
- Simplified iconography over realistic depiction
|
||||
|
||||
## Fourth Wall / Narrator Character
|
||||
|
||||
When depicting narrator characters addressing the reader:
|
||||
- Character may look directly out of panel
|
||||
- Can appear in "present day" framing scenes
|
||||
- Distinct visual treatment from main timeline
|
||||
- Often at page edges or in dedicated panels
|
||||
- May comment on or question the events shown
|
||||
|
||||
## Historical Accuracy
|
||||
|
||||
- Research period-specific details: costumes, technology, architecture
|
||||
- Show aging naturally for characters across time periods
|
||||
- Iconic items and locations rendered recognizably
|
||||
- Balance accuracy with stylization
|
||||
|
||||
## Language
|
||||
|
||||
- All text in Chinese (中文) unless source material is in another language
|
||||
- Use Chinese full-width punctuation: "",。!
|
||||
|
||||
---
|
||||
|
||||
Please generate the comic page based on the content provided below:
|
||||
@@ -0,0 +1,180 @@
|
||||
# Character Definition Template
|
||||
|
||||
## Character Document Format
|
||||
|
||||
Create `characters/characters.md` with the following structure:
|
||||
|
||||
```markdown
|
||||
# Character Definitions - [Comic Title]
|
||||
|
||||
**Style**: [selected style]
|
||||
**Art Direction**: [Ligne Claire / Manga / etc.]
|
||||
|
||||
---
|
||||
|
||||
## Character 1: [Name]
|
||||
|
||||
**Role**: [Protagonist / Mentor / Antagonist / Narrator]
|
||||
**Age**: [approximate age or age range in story]
|
||||
|
||||
**Appearance**:
|
||||
- Face shape: [oval/square/round]
|
||||
- Hair: [color, style, length]
|
||||
- Eyes: [color, shape, distinctive features]
|
||||
- Build: [height, body type]
|
||||
- Distinguishing features: [glasses, beard, scar, etc.]
|
||||
|
||||
**Costume**:
|
||||
- Default outfit: [detailed description]
|
||||
- Color palette: [primary colors for this character]
|
||||
- Accessories: [hat, bag, tools, etc.]
|
||||
|
||||
**Expression Range**:
|
||||
- Neutral: [description]
|
||||
- Happy/Excited: [description]
|
||||
- Thinking/Confused: [description]
|
||||
- Determined: [description]
|
||||
|
||||
**Visual Reference Notes**:
|
||||
[Any specific artistic direction]
|
||||
|
||||
---
|
||||
|
||||
## Character 2: [Name]
|
||||
...
|
||||
```
|
||||
|
||||
## Reference Sheet Image Prompt
|
||||
|
||||
After character definitions, include a prompt for generating the reference sheet:
|
||||
|
||||
```markdown
|
||||
## Reference Sheet Prompt
|
||||
|
||||
Character reference sheet in [style] style, clean lines, flat colors:
|
||||
|
||||
[ROW 1 - Character Name]:
|
||||
- Front view: [detailed description]
|
||||
- 3/4 view: [description]
|
||||
- Expression sheet: Neutral | Happy | Focused | Worried
|
||||
|
||||
[ROW 2 - Character Name]:
|
||||
...
|
||||
|
||||
COLOR PALETTE:
|
||||
- [Character 1]: [colors]
|
||||
- [Character 2]: [colors]
|
||||
|
||||
White background, clear labels under each character.
|
||||
```
|
||||
|
||||
## Example: Turing Biography
|
||||
|
||||
```markdown
|
||||
# Character Definitions - The Imitation Game
|
||||
|
||||
**Style**: classic (Ligne Claire)
|
||||
**Art Direction**: Clean lines, muted colors, period-accurate details
|
||||
|
||||
---
|
||||
|
||||
## Character 1: Alan Turing
|
||||
|
||||
**Role**: Protagonist
|
||||
**Age**: 25-40 (varies across story)
|
||||
|
||||
**Appearance**:
|
||||
- Face shape: Oval, slightly angular
|
||||
- Hair: Dark brown, wavy, slightly disheveled
|
||||
- Eyes: Deep-set, intense gaze
|
||||
- Build: Tall, lean, slightly awkward posture
|
||||
- Distinguishing features: Prominent brow, thoughtful expression
|
||||
|
||||
**Costume**:
|
||||
- Default outfit: Tweed jacket with elbow patches, white shirt, no tie
|
||||
- Color palette: Muted browns, navy blue, cream
|
||||
- Accessories: Occasionally a pipe, papers/notebooks
|
||||
|
||||
**Expression Range**:
|
||||
- Neutral: Thoughtful, slightly distant
|
||||
- Happy/Excited: Eureka moment, eyes bright, subtle smile
|
||||
- Thinking/Confused: Furrowed brow, looking at abstract space
|
||||
- Determined: Jaw set, focused eyes
|
||||
|
||||
---
|
||||
|
||||
## Character 2: The Bombe Machine
|
||||
|
||||
**Role**: Supporting (anthropomorphized)
|
||||
**Appearance**:
|
||||
- Large brass and wood cabinet
|
||||
- Dial "eyes" that can express states
|
||||
- Paper tape "mouth"
|
||||
- Indicator lights for emotions
|
||||
|
||||
**Expression Range**:
|
||||
- Processing: Spinning dials, humming
|
||||
- Success: Lights up warmly
|
||||
- Stuck: Smoke wisps, stuttering
|
||||
|
||||
---
|
||||
|
||||
## Reference Sheet Prompt
|
||||
|
||||
Character reference sheet in Ligne Claire style, clean lines, flat colors:
|
||||
|
||||
TOP ROW - Alan Turing:
|
||||
- Front view: Young man, 30s, short dark wavy hair, thoughtful expression, wearing tweed jacket with elbow patches, white shirt
|
||||
- 3/4 view: Same character, slight smile, showing profile of nose
|
||||
- Expression sheet: Neutral | Excited (eureka moment) | Focused (working) | Worried
|
||||
|
||||
BOTTOM ROW - The Bombe Machine (anthropomorphized):
|
||||
- Bombe machine as character: Large, brass and wood, dial "eyes", paper tape "mouth"
|
||||
- Expressions: Processing (spinning dials) | Success (lights up) | Stuck (smoke wisps)
|
||||
|
||||
COLOR PALETTE:
|
||||
- Turing: Muted browns (#8B7355), navy blue (#2C3E50), cream (#F5F5DC)
|
||||
- Machine: Brass (#B5A642), mahogany (#4E2728), emerald indicators (#2ECC71)
|
||||
|
||||
White background, clear labels under each character.
|
||||
```
|
||||
|
||||
## Handling Age Variants
|
||||
|
||||
For biographies spanning many years, define age variants:
|
||||
|
||||
```markdown
|
||||
## Alan Turing - Age Variants
|
||||
|
||||
### Young (1920s, age 10-18)
|
||||
- Boyish features, round face
|
||||
- School uniform (Sherborne)
|
||||
- Curious, eager expression
|
||||
|
||||
### Adult (1930s-40s, age 25-35)
|
||||
- Angular face, defined jaw
|
||||
- Tweed jacket, rumpled appearance
|
||||
- Intense, focused expression
|
||||
|
||||
### Later (1950s, age 40+)
|
||||
- Slightly weathered
|
||||
- More casual dress
|
||||
- Thoughtful, sometimes melancholic
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
| Practice | Description |
|
||||
|----------|-------------|
|
||||
| Be specific | "Short dark wavy hair, parted left" not just "dark hair" |
|
||||
| Use distinguishing features | Glasses, scars, accessories that identify character |
|
||||
| Define color codes | Use specific color names or hex codes |
|
||||
| Include age markers | Wrinkles, posture, clothing style matching era |
|
||||
| Reference real people | For historical figures, note "based on 1940s photographs" |
|
||||
|
||||
## Why Character Reference Matters
|
||||
|
||||
Without unified character definition, AI generates inconsistent appearances. The reference sheet provides:
|
||||
1. Visual anchors for consistent features
|
||||
2. Color palettes for consistent coloring
|
||||
3. Expression documentation for emotional portrayals
|
||||
@@ -0,0 +1,23 @@
|
||||
# cinematic
|
||||
|
||||
Wide panels, filmic feel
|
||||
|
||||
## Panel Structure
|
||||
|
||||
- **Panels per page**: 2-4
|
||||
- **Structure**: Horizontal emphasis, wide aspect panels
|
||||
- **Gutters**: Generous spacing (12-15px)
|
||||
|
||||
## Grid Configuration
|
||||
|
||||
- 1-2 columns, horizontal emphasis
|
||||
- Panel sizes: Wide aspect ratios (3:1, 4:1)
|
||||
- Reading flow: Horizontal sweep, filmic rhythm
|
||||
|
||||
## Best For
|
||||
|
||||
Establishing shots, dramatic moments, landscapes
|
||||
|
||||
## Best Style Pairings
|
||||
|
||||
dramatic, classic, sepia
|
||||
@@ -0,0 +1,23 @@
|
||||
# dense
|
||||
|
||||
Information-rich, educational focus
|
||||
|
||||
## Panel Structure
|
||||
|
||||
- **Panels per page**: 6-9
|
||||
- **Structure**: Compact grid, smaller panels
|
||||
- **Gutters**: Tight spacing (4-6px)
|
||||
|
||||
## Grid Configuration
|
||||
|
||||
- 3 columns × 3 rows
|
||||
- Panel sizes: Compact, uniform
|
||||
- Reading flow: Rapid progression, information-rich
|
||||
|
||||
## Best For
|
||||
|
||||
Technical explanations, complex narratives, timelines
|
||||
|
||||
## Best Style Pairings
|
||||
|
||||
tech, ohmsha, vibrant
|
||||
@@ -0,0 +1,23 @@
|
||||
# mixed
|
||||
|
||||
Dynamic, varied rhythm
|
||||
|
||||
## Panel Structure
|
||||
|
||||
- **Panels per page**: 3-7 (varies)
|
||||
- **Structure**: Intentionally varied for pacing
|
||||
- **Gutters**: Dynamic spacing
|
||||
|
||||
## Grid Configuration
|
||||
|
||||
- Intentionally irregular
|
||||
- Panel sizes: Varied for pacing and emphasis
|
||||
- Reading flow: Guides eye through varied rhythm
|
||||
|
||||
## Best For
|
||||
|
||||
Action sequences, emotional arcs, complex stories
|
||||
|
||||
## Best Style Pairings
|
||||
|
||||
dramatic, vibrant, ohmsha
|
||||
@@ -0,0 +1,23 @@
|
||||
# splash
|
||||
|
||||
Impact-focused, key moments
|
||||
|
||||
## Panel Structure
|
||||
|
||||
- **Panels per page**: 1-2 large + 2-3 small
|
||||
- **Structure**: Dominant splash with supporting panels
|
||||
- **Gutters**: Varied for emphasis
|
||||
|
||||
## Grid Configuration
|
||||
|
||||
- 1 dominant panel + 2-3 supporting
|
||||
- Panel sizes: 50-70% splash, remainder small
|
||||
- Reading flow: Splash dominates, supporting panels accent
|
||||
|
||||
## Best For
|
||||
|
||||
Revelations, breakthroughs, chapter openings
|
||||
|
||||
## Best Style Pairings
|
||||
|
||||
dramatic, classic, vibrant
|
||||
@@ -0,0 +1,23 @@
|
||||
# standard
|
||||
|
||||
Classic comic grid, versatile
|
||||
|
||||
## Panel Structure
|
||||
|
||||
- **Panels per page**: 4-6
|
||||
- **Structure**: Regular grid with occasional variation
|
||||
- **Gutters**: Consistent white space (8-10px)
|
||||
|
||||
## Grid Configuration
|
||||
|
||||
- 2-3 columns × 2-3 rows
|
||||
- Panel sizes: Mostly equal, occasional variation
|
||||
- Reading flow: Left→right, top→bottom (Z-pattern)
|
||||
|
||||
## Best For
|
||||
|
||||
Narrative flow, dialogue scenes
|
||||
|
||||
## Best Style Pairings
|
||||
|
||||
classic, warm, sepia
|
||||
@@ -0,0 +1,30 @@
|
||||
# webtoon
|
||||
|
||||
Vertical scrolling comic (竖版条漫)
|
||||
|
||||
## Panel Structure
|
||||
|
||||
- **Panels per page**: 3-5 vertically stacked
|
||||
- **Structure**: Single column, vertical flow optimized for scrolling
|
||||
- **Gutters**: Generous vertical spacing (20-40px), panels often bleed horizontally
|
||||
|
||||
## Grid Configuration
|
||||
|
||||
- Single column, vertical stack
|
||||
- Panel sizes: Full width, variable height (1:1 to 1:2 aspect)
|
||||
- Reading flow: Top→bottom continuous scroll
|
||||
|
||||
## Special Features
|
||||
|
||||
- Panels can extend beyond frame for dramatic effect
|
||||
- Generous whitespace between beats
|
||||
- Character close-ups alternate with wide explanation panels
|
||||
- "Float" effect - elements can exist between panels
|
||||
|
||||
## Best For
|
||||
|
||||
Ohmsha-style tutorials, mobile reading, step-by-step guides
|
||||
|
||||
## Best Style Pairings
|
||||
|
||||
ohmsha, tech, vibrant
|
||||
@@ -0,0 +1,85 @@
|
||||
# Ohmsha Manga Guide Style
|
||||
|
||||
Guidelines for `--style ohmsha` educational manga comics.
|
||||
|
||||
## Character Setup
|
||||
|
||||
| Role | Default | Traits |
|
||||
|------|---------|--------|
|
||||
| Student (Role A) | 大雄 | Confused, asks basic but crucial questions, represents reader |
|
||||
| Mentor (Role B) | 哆啦A梦 | Knowledgeable, patient, uses gadgets as technical metaphors |
|
||||
| Antagonist (Role C, optional) | 胖虎 | Represents misunderstanding, or "noise" in the data |
|
||||
|
||||
Custom characters: `--characters "Student:小明,Mentor:教授,Antagonist:Bug怪"`
|
||||
|
||||
## Character Reference Sheet Style
|
||||
|
||||
For Ohmsha style, use manga/anime style with:
|
||||
- Exaggerated expressions for educational clarity
|
||||
- Simple, distinctive silhouettes
|
||||
- Bright, saturated color palettes
|
||||
- Chibi/SD (super-deformed) variants for comedic reactions
|
||||
|
||||
## Outline Spec Block
|
||||
|
||||
Every ohmsha outline must start with:
|
||||
|
||||
```markdown
|
||||
【漫画规格单】
|
||||
- Language: [Same as input content]
|
||||
- Style: Ohmsha (Manga Guide), Full Color
|
||||
- Layout: Vertical Scrolling Comic (竖版条漫)
|
||||
- Characters: [List character names and roles]
|
||||
- Character Reference: characters/characters.png
|
||||
- Page Limit: ≤20 pages
|
||||
```
|
||||
|
||||
## Visual Metaphor Rules (Critical)
|
||||
|
||||
**NEVER** create "talking heads" panels. Every technical concept must become:
|
||||
|
||||
1. **A tangible gadget/prop** - Something characters can hold, use, demonstrate
|
||||
2. **An action scene** - Characters doing something that illustrates the concept
|
||||
3. **A visual environment** - Stepping into a metaphorical space
|
||||
|
||||
### Examples
|
||||
|
||||
| Concept | Bad (Talking Heads) | Good (Visual Metaphor) |
|
||||
|---------|---------------------|------------------------|
|
||||
| Word embeddings | Characters discussing vectors | 哆啦A梦拿出"词向量压缩机",把书本压缩成彩色小球 |
|
||||
| Gradient descent | Explaining math formula | 大雄在山谷地形上滚球,寻找最低点 |
|
||||
| Neural network | Diagram on whiteboard | 角色走进由发光节点组成的网络迷宫 |
|
||||
|
||||
## Page Title Convention
|
||||
|
||||
Avoid AI-style "Title: Subtitle" format. Use narrative descriptions:
|
||||
|
||||
- ❌ "Page 3: Introduction to Neural Networks"
|
||||
- ✓ "Page 3: 大雄被海量单词淹没,哆啦A梦拿出'词向量压缩机'"
|
||||
|
||||
## Ending Requirements
|
||||
|
||||
- NO generic endings ("What will you choose?", "Thanks for reading")
|
||||
- End with: Technical summary moment OR character achieving a small goal
|
||||
- Final panel: Sense of accomplishment, not open-ended question
|
||||
|
||||
### Good Endings
|
||||
|
||||
- Student successfully applies learned concept
|
||||
- Visual callback to opening problem, now solved
|
||||
- Mentor gives summary while student demonstrates understanding
|
||||
|
||||
### Bad Endings
|
||||
|
||||
- "What do you think?" open questions
|
||||
- "Thanks for reading this tutorial"
|
||||
- Cliffhanger without resolution
|
||||
|
||||
## Layout Preference
|
||||
|
||||
Ohmsha style typically uses:
|
||||
- `webtoon` (vertical scrolling) - Primary choice
|
||||
- `dense` - For information-heavy sections
|
||||
- `mixed` - For varied pacing
|
||||
|
||||
Avoid `cinematic` and `splash` for educational content.
|
||||
@@ -0,0 +1,136 @@
|
||||
# Outline Template
|
||||
|
||||
## Outline Document Format
|
||||
|
||||
```markdown
|
||||
# [Comic Title] - Knowledge Comic Outline
|
||||
|
||||
**Topic**: [topic description]
|
||||
**Time Span**: [e.g., 1912-1954]
|
||||
**Style**: [selected style]
|
||||
**Default Layout**: [selected layout or "varies"]
|
||||
**Page Count**: Cover + N pages
|
||||
**Character Reference**: characters/characters.png
|
||||
**Generated**: YYYY-MM-DD HH:mm
|
||||
|
||||
---
|
||||
|
||||
## Cover
|
||||
|
||||
**Filename**: 00-cover.png
|
||||
**Core Message**: [one-liner]
|
||||
|
||||
**Visual Design**:
|
||||
- Title typography style
|
||||
- Main visual composition
|
||||
- Color scheme
|
||||
- Subtitle / time span notation
|
||||
|
||||
**Visual Prompt**:
|
||||
[Detailed image generation prompt]
|
||||
|
||||
---
|
||||
|
||||
## Page 1 / N
|
||||
|
||||
**Filename**: 01-page.png
|
||||
**Layout**: [standard/cinematic/dense/splash/mixed]
|
||||
**Narrative Layer**: [Main narrative / Narrator layer / Mixed]
|
||||
**Core Message**: [What this page conveys]
|
||||
|
||||
### Panel Layout
|
||||
|
||||
**Panel Count**: X
|
||||
**Layout Type**: [grid/irregular/splash]
|
||||
|
||||
#### Panel 1 (Size: 1/3 page, Position: Top)
|
||||
|
||||
**Scene**: [Time, location]
|
||||
**Image Description**:
|
||||
- Camera angle: [bird's eye / low angle / eye level / close-up / wide shot]
|
||||
- Characters: [pose, expression, action]
|
||||
- Environment: [scene details, period markers]
|
||||
- Lighting: [atmosphere description]
|
||||
- Color tone: [palette reference]
|
||||
|
||||
**Text Elements**:
|
||||
- Dialogue bubble (oval): "Character line"
|
||||
- Narrator box (rectangular): 「Narrator commentary」
|
||||
- Caption bar: [Background info text]
|
||||
|
||||
#### Panel 2...
|
||||
|
||||
**Page Hook**: [Cliffhanger or transition at page end]
|
||||
|
||||
**Visual Prompt**:
|
||||
[Full page image generation prompt]
|
||||
|
||||
---
|
||||
|
||||
## Page 2 / N
|
||||
...
|
||||
```
|
||||
|
||||
## Cover Design Principles
|
||||
|
||||
- Academic gravitas with visual appeal
|
||||
- Title typography reflecting knowledge/science theme
|
||||
- Composition hinting at core theme (character silhouette, iconic symbol, concept diagram)
|
||||
- Subtitle or time span for epic scope
|
||||
|
||||
## Panel Composition Guidelines
|
||||
|
||||
| Panel Type | Recommended Count | Usage |
|
||||
|-----------|-------------------|-------|
|
||||
| Main narrative | 3-5 per page | Story progression |
|
||||
| Concept diagram | 1-2 per page | Visualize abstractions |
|
||||
| Narrator panel | 0-1 per page | Commentary, transition |
|
||||
| Splash (full/half) | Occasional | Major moments |
|
||||
|
||||
## Panel Size Reference
|
||||
|
||||
- **Full page (Splash)**: Major moments, key breakthroughs
|
||||
- **Half page**: Important scenes, turning points
|
||||
- **1/3 page**: Standard narrative panels
|
||||
- **1/4 or smaller**: Quick progression, sequential action
|
||||
|
||||
## Concept Visualization Techniques
|
||||
|
||||
Transform abstract concepts into concrete visuals:
|
||||
|
||||
| Abstract Concept | Visual Approach |
|
||||
|-----------------|-----------------|
|
||||
| Neural network | Glowing nodes with connecting lines |
|
||||
| Gradient descent | Ball rolling down valley terrain |
|
||||
| Data flow | Luminous particles flowing through pipes |
|
||||
| Algorithm iteration | Ascending spiral staircase |
|
||||
| Breakthrough moment | Shattering barrier, piercing light |
|
||||
| Logical proof | Building blocks assembling |
|
||||
| Uncertainty | Forking paths, fog, multiple shadows |
|
||||
|
||||
## Text Element Design
|
||||
|
||||
| Text Type | Style | Usage |
|
||||
|-----------|-------|-------|
|
||||
| Character dialogue | Oval speech bubble | Main narrative speech |
|
||||
| Narrator commentary | Rectangular box | Explanation, commentary |
|
||||
| Caption bar | Edge-mounted rectangle | Time, location info |
|
||||
| Thought bubble | Cloud shape | Character inner monologue |
|
||||
| Term label | Bold / special color | First appearance of technical terms |
|
||||
|
||||
## Prompt Structure for Consistency
|
||||
|
||||
Each page prompt should include character reference:
|
||||
|
||||
```
|
||||
[CHARACTER REFERENCE]
|
||||
(Key details from characters.md for characters in this page)
|
||||
|
||||
[PAGE CONTENT]
|
||||
(Specific scene, panel layout, and visual elements)
|
||||
|
||||
[CONSISTENCY REMINDER]
|
||||
Maintain exact character appearances as defined in character reference.
|
||||
- [Character A]: [key identifying features]
|
||||
- [Character B]: [key identifying features]
|
||||
```
|
||||
@@ -0,0 +1,54 @@
|
||||
# classic
|
||||
|
||||
Traditional Ligne Claire, balanced and timeless
|
||||
|
||||
## Style Guidelines
|
||||
|
||||
### Line Work
|
||||
- Uniform, clean outlines with consistent weight (approximately 2px)
|
||||
- No hatching or cross-hatching for shading
|
||||
- Sharp, precise edges on all elements
|
||||
- Black ink outlines on all figures and objects
|
||||
- Shadows indicated through flat color areas, not line techniques
|
||||
|
||||
### Character Design
|
||||
- Slightly stylized/cartoonish characters with realistic proportions
|
||||
- Distinctive, recognizable facial features
|
||||
- Expressive faces with clear emotions
|
||||
- Period-appropriate clothing with attention to detail
|
||||
- Consistent character appearance across panels
|
||||
|
||||
### Background Treatment
|
||||
- Detailed, realistic backgrounds with architectural accuracy
|
||||
- Period-specific props and technology
|
||||
- Clear spatial depth and perspective
|
||||
- Environmental storytelling through details
|
||||
- Contrast between simplified characters and detailed backgrounds
|
||||
|
||||
## Color Palette
|
||||
|
||||
- Primary: Clean blue (#3182CE), red (#E53E3E), yellow (#ECC94B)
|
||||
- Skin: Warm tan (#F7CFAE)
|
||||
- Background: Light cream (#FFFAF0), sky blue (#BEE3F8)
|
||||
|
||||
## Color Approach
|
||||
- Flat colors without gradients (true to Ligne Claire tradition)
|
||||
- Limited palette per page for cohesion
|
||||
- Colors support narrative mood
|
||||
- Consistent lighting logic within scenes
|
||||
|
||||
## Quality Markers
|
||||
|
||||
A good Ligne Claire comic page exhibits:
|
||||
- ✓ Clean, uniform line weight throughout
|
||||
- ✓ Flat colors without gradients
|
||||
- ✓ Detailed backgrounds, stylized characters
|
||||
- ✓ Clear panel borders and reading flow
|
||||
- ✓ Hand-drawn text style
|
||||
- ✓ Period-appropriate details
|
||||
- ✓ Expressive but consistent characters
|
||||
- ✓ Proper perspective in environments
|
||||
|
||||
## Best For
|
||||
|
||||
Educational content, balanced narratives, biography comics
|
||||
@@ -0,0 +1,34 @@
|
||||
# dramatic
|
||||
|
||||
High contrast, intense moments
|
||||
|
||||
## Style Guidelines
|
||||
|
||||
### Line Work
|
||||
- 2-3px outlines, heavier on shadows
|
||||
- Dramatic angles and perspectives
|
||||
- Strong contrast between light and dark areas
|
||||
|
||||
### Character Design
|
||||
- Intense expressions, dynamic poses
|
||||
- Dramatic lighting on faces
|
||||
- Sharp angular features emphasized
|
||||
|
||||
### Background Treatment
|
||||
- High contrast, angular shadows
|
||||
- Dramatic lighting effects
|
||||
- Silhouettes and stark compositions
|
||||
|
||||
## Color Palette
|
||||
|
||||
- Primary: Deep navy (#1A365D), crimson (#9B2C2C), stark white
|
||||
- Shadows: Heavy blacks, dramatic contrast
|
||||
- Highlights: Sharp whites, limited mid-tones
|
||||
|
||||
## Mood
|
||||
|
||||
Tension, breakthrough moments, conflict
|
||||
|
||||
## Best For
|
||||
|
||||
Pivotal discoveries, conflicts, climactic scenes
|
||||
@@ -0,0 +1,107 @@
|
||||
# ohmsha
|
||||
|
||||
Ohmsha Manga Guide style - educational manga with visual metaphors
|
||||
|
||||
## Core Philosophy
|
||||
|
||||
Educational manga where every concept becomes a visual metaphor or action. NO talking heads - characters must DO things, not just explain.
|
||||
|
||||
## Visual Style
|
||||
|
||||
- **Type**: Manga-style educational comic
|
||||
- **Orientation**: Portrait (vertical), optimized for scrolling
|
||||
- **Colors**: Full color, bright and clean anime/manga aesthetic
|
||||
- **Lines**: Clean manga lines (1.5-2px), smooth curves, expressive
|
||||
|
||||
## Character Design (Manga Style)
|
||||
|
||||
- Anime/manga proportions: slightly larger eyes, expressive faces
|
||||
- **Student character**: Confused expressions, question marks (?), sweat drops, represents reader
|
||||
- **Mentor character**: Confident poses, explanatory gestures, produces gadgets/tools
|
||||
- Clear emotional indicators using manga conventions (!, ?, sweat drops, sparkles)
|
||||
- Consistent character designs across all panels
|
||||
|
||||
## Background Treatment
|
||||
|
||||
- Simplified backgrounds during dialogue/explanation
|
||||
- Detailed "imagination spaces" for concept visualization
|
||||
- Technical diagrams styled as holographic displays or magical blueprints
|
||||
- Screen tone effects for atmosphere
|
||||
|
||||
## Visual Metaphor Requirements (CRITICAL)
|
||||
|
||||
Every technical concept MUST be visualized as:
|
||||
|
||||
| Concept Type | Visualization Approach |
|
||||
|-------------|----------------------|
|
||||
| Algorithm | Gadget/machine that demonstrates the process |
|
||||
| Data structure | Physical space characters can enter/explore |
|
||||
| Mathematical formula | Transformation visible in environment |
|
||||
| Abstract process | Tangible flow of particles/objects |
|
||||
|
||||
**Wrong approach**: Character points at blackboard explaining
|
||||
**Right approach**: Character uses "Concept Visualizer" gadget, steps into metaphorical space
|
||||
|
||||
### Visual Metaphor Examples
|
||||
|
||||
| Concept | Wrong (Talking Head) | Right (Visual Metaphor) |
|
||||
|---------|---------------------|------------------------|
|
||||
| Attention mechanism | Character points at formula on blackboard | "Attention Flashlight" gadget illuminates key words in dark room |
|
||||
| Gradient descent | "The algorithm minimizes loss" | Character rides ball rolling down mountain valley |
|
||||
| Neural network | Diagram with arrows | Living network of glowing creatures passing messages |
|
||||
| Overfitting | "The model memorized the data" | Character wearing clothes that fit only one specific pose |
|
||||
|
||||
## Panel Layout for Ohmsha
|
||||
|
||||
- Vertical scroll optimized (webtoon style)
|
||||
- Single column, panels stack vertically
|
||||
- Generous whitespace between major beats
|
||||
- Panels can bleed to edges for impact
|
||||
- "Float" elements between panels for emphasis
|
||||
|
||||
## Special Visual Elements
|
||||
|
||||
- **Gadget reveals**: Dramatic unveiling with sparkle effects
|
||||
- **Concept spaces**: Rounded borders, glowing edges for "imagination mode"
|
||||
- **Information displays**: Holographic UI style for technical details
|
||||
- **Aha moments**: Radial lines, light burst effects
|
||||
- **Confusion**: Spiral eyes, question marks floating above head
|
||||
|
||||
## Text Elements (Ohmsha)
|
||||
|
||||
- Hand-lettered manga style
|
||||
- Sound effects integrated visually (ドキドキ, ピカーン, etc.)
|
||||
- Speech bubbles: rounded for normal, spiky for excitement/shock
|
||||
- Thought bubbles for internal process visualization
|
||||
- Technical terms in bold with furigana-style annotations if needed
|
||||
|
||||
## Color Palette
|
||||
|
||||
- Primary: Bright blue (#4299E1), warm orange (#ED8936), soft green (#68D391)
|
||||
- Skin: Anime-style warm (#FEEBC8)
|
||||
- Background: Clean white, soft gradients
|
||||
- Gadgets: Metallic accents (#FFD700, #C0C0C0), vibrant highlights
|
||||
- Concept spaces: Pastel backgrounds, glowing accents
|
||||
|
||||
## Quality Markers (Ohmsha)
|
||||
|
||||
- ✓ Every concept is a visual metaphor, not just explained
|
||||
- ✓ Characters are DOING things, not just talking
|
||||
- ✓ Clear student/mentor dynamic
|
||||
- ✓ Gadgets and props drive the explanation
|
||||
- ✓ Expressive manga-style emotions
|
||||
- ✓ Information density through visual design, not text walls
|
||||
|
||||
## Character Setup (Required)
|
||||
|
||||
Define characters before generating:
|
||||
|
||||
| Role | Default | Traits |
|
||||
|------|---------|--------|
|
||||
| Student (Role A) | 大雄 | Confused, asks basic but crucial questions, represents reader |
|
||||
| Mentor (Role B) | 哆啦A梦 | Knowledgeable, patient, uses gadgets as technical metaphors |
|
||||
| Antagonist (Role C, optional) | 胖虎 | Represents misunderstanding, or "noise" in the data |
|
||||
|
||||
## Best For
|
||||
|
||||
Technical tutorials, complex concepts (ML, physics, math), self-study material
|
||||
@@ -0,0 +1,66 @@
|
||||
# realistic
|
||||
|
||||
Full-color realistic manga style with digital painting techniques
|
||||
|
||||
## Style Guidelines
|
||||
|
||||
### Line Work
|
||||
- Clean, precise outlines with clear contours
|
||||
- Uniform line weight for character definition
|
||||
- No excessive hatching - rely on color for depth
|
||||
- Smooth curves and realistic anatomical lines
|
||||
- Ligne Claire influence: clean but not overly simplified
|
||||
|
||||
### Character Design
|
||||
- Realistic human proportions (7-8 head heights)
|
||||
- Anatomically accurate features and expressions
|
||||
- Detailed facial structure without exaggeration
|
||||
- Natural poses and body language
|
||||
- Consistent character appearance across all panels
|
||||
- Subtle expressions rather than manga-style exaggeration
|
||||
|
||||
### Rendering Style
|
||||
- Full-color digital painting with rich gradients
|
||||
- Soft shadow transitions on skin and fabric
|
||||
- Realistic material textures (glass, liquid, fabric, wood)
|
||||
- Detailed hair with natural shine and volume
|
||||
- Environmental lighting affects all elements
|
||||
- NOT flat cel-shading - use smooth color blending
|
||||
|
||||
### Background Treatment
|
||||
- Highly detailed, realistic environments
|
||||
- Accurate perspective and spatial depth
|
||||
- Atmospheric lighting (warm indoor, cool outdoor)
|
||||
- Professional settings rendered with precision
|
||||
- Props and objects with realistic textures
|
||||
|
||||
## Color Palette
|
||||
|
||||
- Skin: Natural warm tones (#F5D6C6, #E8C4B0)
|
||||
- Hair: Rich browns and blacks with highlights
|
||||
- Environment: Warm wood tones (#8B7355), cool stone (#9CA3AF)
|
||||
- Accent: Wine red (#722F37), gold (#D4AF37)
|
||||
- Lighting: Warm amber (#FFB347), cool blue (#B0C4DE)
|
||||
|
||||
## Color Approach
|
||||
- Rich gradients for depth and volume
|
||||
- Realistic lighting with warm/cool contrast
|
||||
- Material-specific rendering (glass transparency, liquid reflection)
|
||||
- Subtle color temperature shifts for atmosphere
|
||||
- Professional, sophisticated palette
|
||||
|
||||
## Quality Markers
|
||||
|
||||
A good realistic manga page exhibits:
|
||||
- ✓ Anatomically accurate character proportions
|
||||
- ✓ Smooth color gradients (not flat fills)
|
||||
- ✓ Realistic material textures
|
||||
- ✓ Detailed, atmospheric backgrounds
|
||||
- ✓ Natural lighting with soft shadows
|
||||
- ✓ Expressive but subtle facial expressions
|
||||
- ✓ Professional, sophisticated aesthetic
|
||||
- ✓ Clean speech bubbles with clear typography
|
||||
|
||||
## Best For
|
||||
|
||||
Professional topics (wine, food, business), lifestyle content, adult-oriented narratives, educational guides for mature audiences, documentary-style storytelling
|
||||
@@ -0,0 +1,34 @@
|
||||
# sepia
|
||||
|
||||
Historical, archival feel
|
||||
|
||||
## Style Guidelines
|
||||
|
||||
### Line Work
|
||||
- 2px, classic weight with aged texture
|
||||
- Vintage illustration style
|
||||
- Period-appropriate techniques
|
||||
|
||||
### Character Design
|
||||
- Period-accurate attire, formal poses
|
||||
- Historical accuracy emphasized
|
||||
- Classical proportions
|
||||
|
||||
### Background Treatment
|
||||
- Historical settings, vintage details
|
||||
- Aged paper effect
|
||||
- Period architecture and props
|
||||
|
||||
## Color Palette
|
||||
|
||||
- Primary: Sepia brown (#8B7355), aged paper (#F5E6D3)
|
||||
- Accents: Faded teal, muted burgundy
|
||||
- Background: Yellowed paper, vintage tones
|
||||
|
||||
## Mood
|
||||
|
||||
Historical distance, period authenticity
|
||||
|
||||
## Best For
|
||||
|
||||
Pre-1950s stories, classical science, historical figures
|
||||
@@ -0,0 +1,34 @@
|
||||
# tech
|
||||
|
||||
Modern, digital-age narratives
|
||||
|
||||
## Style Guidelines
|
||||
|
||||
### Line Work
|
||||
- 2px, precise geometric undertones
|
||||
- Clean, technical precision
|
||||
- Circuit-like patterns in backgrounds
|
||||
|
||||
### Character Design
|
||||
- Contemporary clothing, focused expressions
|
||||
- Modern tech accessories
|
||||
- Clean, precise features
|
||||
|
||||
### Background Treatment
|
||||
- Digital elements, screens, circuit motifs
|
||||
- Grid patterns
|
||||
- Glowing interface elements
|
||||
|
||||
## Color Palette
|
||||
|
||||
- Primary: Cyan (#00D4FF), deep blue (#1A365D), white
|
||||
- Accents: Neon green (#00FF88), electric purple (#805AD5)
|
||||
- Background: Dark gray (#1A202C), grid patterns
|
||||
|
||||
## Mood
|
||||
|
||||
Innovation, digital, contemporary
|
||||
|
||||
## Best For
|
||||
|
||||
Computing history, AI stories, modern tech
|
||||
@@ -0,0 +1,34 @@
|
||||
# vibrant
|
||||
|
||||
Energetic, engaging, educational
|
||||
|
||||
## Style Guidelines
|
||||
|
||||
### Line Work
|
||||
- 2-2.5px, expressive weight variation
|
||||
- Dynamic, energetic lines
|
||||
- Emphasis on movement and action
|
||||
|
||||
### Character Design
|
||||
- Expressive, animated, approachable
|
||||
- Wide eyes, big reactions
|
||||
- Dynamic poses
|
||||
|
||||
### Background Treatment
|
||||
- Simplified, focus on action
|
||||
- Bright, clean compositions
|
||||
- Energy effects and motion lines
|
||||
|
||||
## Color Palette
|
||||
|
||||
- Primary: Bright red (#F56565), sunny yellow (#F6E05E), sky blue (#63B3ED)
|
||||
- Accents: Magenta, lime green
|
||||
- Background: Clean white, bright pastels
|
||||
|
||||
## Mood
|
||||
|
||||
Excitement, discovery, wonder
|
||||
|
||||
## Best For
|
||||
|
||||
Science explanations, "aha" moments, young audience
|
||||
@@ -0,0 +1,34 @@
|
||||
# warm
|
||||
|
||||
Nostalgic, personal storytelling
|
||||
|
||||
## Style Guidelines
|
||||
|
||||
### Line Work
|
||||
- 1.5-2px, slightly softer edges
|
||||
- Gentle curves, friendly feel
|
||||
- Less rigid than classic style
|
||||
|
||||
### Character Design
|
||||
- Friendly expressions, relaxed poses
|
||||
- Warm, inviting character designs
|
||||
- Approachable proportions
|
||||
|
||||
### Background Treatment
|
||||
- Cozy interiors, warm lighting
|
||||
- Nostalgic feel
|
||||
- Soft focus on backgrounds
|
||||
|
||||
## Color Palette
|
||||
|
||||
- Primary: Golden (#D69E2E), orange (#DD6B20), soft brown (#8B6F47)
|
||||
- Skin: Warm golden (#FEEBC8)
|
||||
- Background: Warm cream (#FEF3C7), sunset tones
|
||||
|
||||
## Mood
|
||||
|
||||
Memory, personal journey, reflection
|
||||
|
||||
## Best For
|
||||
|
||||
Personal stories, childhood scenes, mentorship
|
||||
@@ -0,0 +1,116 @@
|
||||
import { existsSync, readdirSync, readFileSync } from "fs";
|
||||
import { join, basename } from "path";
|
||||
import { PDFDocument } from "pdf-lib";
|
||||
|
||||
interface PageInfo {
|
||||
filename: string;
|
||||
path: string;
|
||||
index: number;
|
||||
promptPath?: string;
|
||||
}
|
||||
|
||||
function parseArgs(): { dir: string; output?: string } {
|
||||
const args = process.argv.slice(2);
|
||||
let dir = "";
|
||||
let output: string | undefined;
|
||||
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
if (args[i] === "--output" || args[i] === "-o") {
|
||||
output = args[++i];
|
||||
} else if (!args[i].startsWith("-")) {
|
||||
dir = args[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (!dir) {
|
||||
console.error("Usage: bun merge-to-pdf.ts <comic-dir> [--output filename.pdf]");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
return { dir, output };
|
||||
}
|
||||
|
||||
function findComicPages(dir: string): PageInfo[] {
|
||||
if (!existsSync(dir)) {
|
||||
console.error(`Directory not found: ${dir}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const files = readdirSync(dir);
|
||||
const pagePattern = /^(\d+)-(cover|page)\.(png|jpg|jpeg)$/i;
|
||||
const promptsDir = join(dir, "prompts");
|
||||
const hasPrompts = existsSync(promptsDir);
|
||||
|
||||
const pages: PageInfo[] = files
|
||||
.filter((f) => pagePattern.test(f))
|
||||
.map((f) => {
|
||||
const match = f.match(pagePattern);
|
||||
const baseName = f.replace(/\.(png|jpg|jpeg)$/i, "");
|
||||
const promptPath = hasPrompts ? join(promptsDir, `${baseName}.md`) : undefined;
|
||||
|
||||
return {
|
||||
filename: f,
|
||||
path: join(dir, f),
|
||||
index: parseInt(match![1], 10),
|
||||
promptPath: promptPath && existsSync(promptPath) ? promptPath : undefined,
|
||||
};
|
||||
})
|
||||
.sort((a, b) => a.index - b.index);
|
||||
|
||||
if (pages.length === 0) {
|
||||
console.error(`No comic pages found in: ${dir}`);
|
||||
console.error("Expected format: 00-cover.png, 01-page.png, etc.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
return pages;
|
||||
}
|
||||
|
||||
async function createPdf(pages: PageInfo[], outputPath: string) {
|
||||
const pdfDoc = await PDFDocument.create();
|
||||
pdfDoc.setAuthor("baoyu-comic");
|
||||
pdfDoc.setSubject("Generated Comic");
|
||||
|
||||
for (const page of pages) {
|
||||
const imageData = readFileSync(page.path);
|
||||
const ext = page.filename.toLowerCase();
|
||||
const image = ext.endsWith(".png")
|
||||
? await pdfDoc.embedPng(imageData)
|
||||
: await pdfDoc.embedJpg(imageData);
|
||||
|
||||
const { width, height } = image;
|
||||
const pdfPage = pdfDoc.addPage([width, height]);
|
||||
|
||||
pdfPage.drawImage(image, {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width,
|
||||
height,
|
||||
});
|
||||
|
||||
console.log(`Added: ${page.filename}${page.promptPath ? " (prompt available)" : ""}`);
|
||||
}
|
||||
|
||||
const pdfBytes = await pdfDoc.save();
|
||||
await Bun.write(outputPath, pdfBytes);
|
||||
|
||||
console.log(`\nCreated: ${outputPath}`);
|
||||
console.log(`Total pages: ${pages.length}`);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const { dir, output } = parseArgs();
|
||||
const pages = findComicPages(dir);
|
||||
|
||||
const dirName = basename(dir) === "comic" ? basename(join(dir, "..")) : basename(dir);
|
||||
const outputPath = output || join(dir, `${dirName}.pdf`);
|
||||
|
||||
console.log(`Found ${pages.length} pages in: ${dir}\n`);
|
||||
|
||||
await createPdf(pages, outputPath);
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error("Error:", err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -42,53 +42,18 @@ Generate hand-drawn style cover images for articles with multiple style options.
|
||||
|
||||
## Style Gallery
|
||||
|
||||
### 1. `elegant` (Default)
|
||||
Refined, sophisticated, understated
|
||||
- **Colors**: Soft coral, muted teal, dusty rose, cream background
|
||||
- **Elements**: Delicate line work, subtle icons, balanced composition
|
||||
- **Best for**: Professional content, thought leadership, business topics
|
||||
| Style | Description |
|
||||
|-------|-------------|
|
||||
| `elegant` (Default) | Refined, sophisticated, understated |
|
||||
| `tech` | Modern, clean, futuristic |
|
||||
| `warm` | Friendly, approachable, human-centered |
|
||||
| `bold` | High contrast, attention-grabbing, energetic |
|
||||
| `minimal` | Ultra-clean, zen-like, focused |
|
||||
| `playful` | Fun, creative, whimsical |
|
||||
| `nature` | Organic, calm, earthy |
|
||||
| `retro` | Vintage, nostalgic, classic |
|
||||
|
||||
### 2. `tech`
|
||||
Modern, clean, futuristic
|
||||
- **Colors**: Deep blue, electric cyan, dark gray, white accents
|
||||
- **Elements**: Geometric shapes, circuit patterns, glowing effects, tech icons
|
||||
- **Best for**: AI, programming, technology, digital transformation
|
||||
|
||||
### 3. `warm`
|
||||
Friendly, approachable, human-centered
|
||||
- **Colors**: Warm orange, golden yellow, terracotta, cream
|
||||
- **Elements**: Rounded shapes, friendly characters, sun/light motifs
|
||||
- **Best for**: Personal growth, lifestyle, education, human stories
|
||||
|
||||
### 4. `bold`
|
||||
High contrast, attention-grabbing, energetic
|
||||
- **Colors**: Vibrant red/orange, deep black, bright yellow accents
|
||||
- **Elements**: Strong typography, dramatic contrast, dynamic shapes
|
||||
- **Best for**: Opinion pieces, controversial takes, urgent topics
|
||||
|
||||
### 5. `minimal`
|
||||
Ultra-clean, zen-like, focused
|
||||
- **Colors**: Black, white, single accent color
|
||||
- **Elements**: Maximum whitespace, single focal element, simple lines
|
||||
- **Best for**: Philosophy, minimalism, focused concepts
|
||||
|
||||
### 6. `playful`
|
||||
Fun, creative, whimsical
|
||||
- **Colors**: Pastel rainbow, bright pops of color, light backgrounds
|
||||
- **Elements**: Doodles, quirky characters, speech bubbles, emoji-style icons
|
||||
- **Best for**: Casual content, tutorials, beginner guides, fun topics
|
||||
|
||||
### 7. `nature`
|
||||
Organic, calm, earthy
|
||||
- **Colors**: Forest green, earth brown, sky blue, sand beige
|
||||
- **Elements**: Plant motifs, natural textures, flowing lines, organic shapes
|
||||
- **Best for**: Sustainability, wellness, outdoor topics, slow living
|
||||
|
||||
### 8. `retro`
|
||||
Vintage, nostalgic, classic
|
||||
- **Colors**: Muted pastels, sepia tones, faded colors
|
||||
- **Elements**: Vintage typography, halftone dots, classic illustrations
|
||||
- **Best for**: History, retrospectives, classic topics, throwback content
|
||||
Detailed style definitions: `references/styles/<style>.md`
|
||||
|
||||
## Auto Style Selection
|
||||
|
||||
@@ -211,80 +176,6 @@ Location: [output path]
|
||||
Preview the image to verify it matches your expectations.
|
||||
```
|
||||
|
||||
## Style Reference Details
|
||||
|
||||
### elegant
|
||||
```
|
||||
Colors: Soft coral (#E8A598), muted teal (#5B8A8A), dusty rose (#D4A5A5)
|
||||
Background: Warm cream (#F5F0E6), soft beige
|
||||
Accents: Gold (#C9A962), copper
|
||||
Elements: Delicate lines, refined icons, subtle gradients
|
||||
Typography: Elegant serif-style hand lettering
|
||||
```
|
||||
|
||||
### tech
|
||||
```
|
||||
Colors: Deep blue (#1A365D), electric cyan (#00D4FF), purple (#6B46C1)
|
||||
Background: Dark gray (#1A202C), near-black (#0D1117)
|
||||
Accents: Neon green (#00FF88), bright white
|
||||
Elements: Circuit patterns, data nodes, geometric grids, code snippets
|
||||
Typography: Monospace-style hand lettering, glowing effects
|
||||
```
|
||||
|
||||
### warm
|
||||
```
|
||||
Colors: Warm orange (#ED8936), golden yellow (#F6AD55), terracotta (#C05621)
|
||||
Background: Cream (#FFFAF0), soft peach (#FED7AA)
|
||||
Accents: Deep brown (#744210), soft red
|
||||
Elements: Rounded shapes, smiling faces, sun rays, hearts, warm lighting
|
||||
Typography: Friendly rounded hand lettering
|
||||
```
|
||||
|
||||
### bold
|
||||
```
|
||||
Colors: Vibrant red (#E53E3E), bright orange (#DD6B20), electric yellow (#F6E05E)
|
||||
Background: Deep black (#000000), dark charcoal
|
||||
Accents: White, neon highlights
|
||||
Elements: Exclamation marks, lightning bolts, arrows, strong shapes
|
||||
Typography: Bold, impactful, large hand lettering with shadows
|
||||
```
|
||||
|
||||
### minimal
|
||||
```
|
||||
Colors: Pure black (#000000), white (#FFFFFF)
|
||||
Background: White or off-white (#FAFAFA)
|
||||
Accents: Single color (user's choice or content-derived)
|
||||
Elements: Single focal point, maximum negative space, thin lines
|
||||
Typography: Clean, simple hand lettering, lots of breathing room
|
||||
```
|
||||
|
||||
### playful
|
||||
```
|
||||
Colors: Pastel pink (#FED7E2), mint (#C6F6D5), lavender (#E9D8FD), sky blue (#BEE3F8)
|
||||
Background: Light cream (#FFFBEB), soft white
|
||||
Accents: Bright pops - yellow, coral, turquoise
|
||||
Elements: Doodles, stars, swirls, cute characters, emoji-style icons
|
||||
Typography: Bouncy, irregular hand lettering, playful angles
|
||||
```
|
||||
|
||||
### nature
|
||||
```
|
||||
Colors: Forest green (#276749), sage (#9AE6B4), earth brown (#744210)
|
||||
Background: Sand beige (#F5E6D3), sky blue (#E0F2FE)
|
||||
Accents: Sunset orange, water blue
|
||||
Elements: Leaves, trees, mountains, sun, clouds, organic flowing lines
|
||||
Typography: Organic, flowing hand lettering with natural textures
|
||||
```
|
||||
|
||||
### retro
|
||||
```
|
||||
Colors: Muted orange (#ED8936 at 70%), dusty pink (#FED7E2 at 80%), faded teal
|
||||
Background: Aged paper (#F5E6D3), sepia tones
|
||||
Accents: Faded red, vintage gold
|
||||
Elements: Halftone dots, vintage badges, classic icons, aged textures
|
||||
Typography: Vintage-style hand lettering, classic serif influence
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Cover should be instantly understandable at small preview sizes
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# bold
|
||||
|
||||
High contrast, attention-grabbing, energetic
|
||||
|
||||
## Color Palette
|
||||
|
||||
- Primary: Vibrant red (#E53E3E), bright orange (#DD6B20), electric yellow (#F6E05E)
|
||||
- Background: Deep black (#000000), dark charcoal
|
||||
- Accents: White, neon highlights
|
||||
|
||||
## Visual Elements
|
||||
|
||||
- Exclamation marks, lightning bolts
|
||||
- Arrows, strong shapes
|
||||
- Dramatic compositions
|
||||
|
||||
## Typography
|
||||
|
||||
- Bold, impactful, large hand lettering with shadows
|
||||
|
||||
## Best For
|
||||
|
||||
Opinion pieces, controversial takes, urgent topics
|
||||
@@ -0,0 +1,23 @@
|
||||
# elegant
|
||||
|
||||
Refined, sophisticated, understated
|
||||
|
||||
## Color Palette
|
||||
|
||||
- Primary: Soft coral (#E8A598), muted teal (#5B8A8A), dusty rose (#D4A5A5)
|
||||
- Background: Warm cream (#F5F0E6), soft beige
|
||||
- Accents: Gold (#C9A962), copper
|
||||
|
||||
## Visual Elements
|
||||
|
||||
- Delicate lines, refined icons
|
||||
- Subtle gradients
|
||||
- Balanced composition
|
||||
|
||||
## Typography
|
||||
|
||||
- Elegant serif-style hand lettering
|
||||
|
||||
## Best For
|
||||
|
||||
Professional content, thought leadership, business topics
|
||||
@@ -0,0 +1,23 @@
|
||||
# minimal
|
||||
|
||||
Ultra-clean, zen-like, focused
|
||||
|
||||
## Color Palette
|
||||
|
||||
- Primary: Pure black (#000000), white (#FFFFFF)
|
||||
- Background: White or off-white (#FAFAFA)
|
||||
- Accents: Single color (user's choice or content-derived)
|
||||
|
||||
## Visual Elements
|
||||
|
||||
- Single focal point
|
||||
- Maximum negative space
|
||||
- Thin lines
|
||||
|
||||
## Typography
|
||||
|
||||
- Clean, simple hand lettering, lots of breathing room
|
||||
|
||||
## Best For
|
||||
|
||||
Philosophy, minimalism, focused concepts
|
||||
@@ -0,0 +1,22 @@
|
||||
# nature
|
||||
|
||||
Organic, calm, earthy
|
||||
|
||||
## Color Palette
|
||||
|
||||
- Primary: Forest green (#276749), sage (#9AE6B4), earth brown (#744210)
|
||||
- Background: Sand beige (#F5E6D3), sky blue (#E0F2FE)
|
||||
- Accents: Sunset orange, water blue
|
||||
|
||||
## Visual Elements
|
||||
|
||||
- Leaves, trees, mountains
|
||||
- Sun, clouds, organic flowing lines
|
||||
|
||||
## Typography
|
||||
|
||||
- Organic, flowing hand lettering with natural textures
|
||||
|
||||
## Best For
|
||||
|
||||
Sustainability, wellness, outdoor topics, slow living
|
||||
@@ -0,0 +1,23 @@
|
||||
# playful
|
||||
|
||||
Fun, creative, whimsical
|
||||
|
||||
## Color Palette
|
||||
|
||||
- Primary: Pastel pink (#FED7E2), mint (#C6F6D5), lavender (#E9D8FD), sky blue (#BEE3F8)
|
||||
- Background: Light cream (#FFFBEB), soft white
|
||||
- Accents: Bright pops - yellow, coral, turquoise
|
||||
|
||||
## Visual Elements
|
||||
|
||||
- Doodles, stars, swirls
|
||||
- Cute characters, emoji-style icons
|
||||
- Playful compositions
|
||||
|
||||
## Typography
|
||||
|
||||
- Bouncy, irregular hand lettering, playful angles
|
||||
|
||||
## Best For
|
||||
|
||||
Casual content, tutorials, beginner guides, fun topics
|
||||
@@ -0,0 +1,22 @@
|
||||
# retro
|
||||
|
||||
Vintage, nostalgic, classic
|
||||
|
||||
## Color Palette
|
||||
|
||||
- Primary: Muted orange (#ED8936 at 70%), dusty pink (#FED7E2 at 80%), faded teal
|
||||
- Background: Aged paper (#F5E6D3), sepia tones
|
||||
- Accents: Faded red, vintage gold
|
||||
|
||||
## Visual Elements
|
||||
|
||||
- Halftone dots, vintage badges
|
||||
- Classic icons, aged textures
|
||||
|
||||
## Typography
|
||||
|
||||
- Vintage-style hand lettering, classic serif influence
|
||||
|
||||
## Best For
|
||||
|
||||
History, retrospectives, classic topics, throwback content
|
||||
@@ -0,0 +1,23 @@
|
||||
# tech
|
||||
|
||||
Modern, clean, futuristic
|
||||
|
||||
## Color Palette
|
||||
|
||||
- Primary: Deep blue (#1A365D), electric cyan (#00D4FF), purple (#6B46C1)
|
||||
- Background: Dark gray (#1A202C), near-black (#0D1117)
|
||||
- Accents: Neon green (#00FF88), bright white
|
||||
|
||||
## Visual Elements
|
||||
|
||||
- Circuit patterns, data nodes
|
||||
- Geometric grids, code snippets
|
||||
- Glowing effects
|
||||
|
||||
## Typography
|
||||
|
||||
- Monospace-style hand lettering, glowing effects
|
||||
|
||||
## Best For
|
||||
|
||||
AI, programming, technology, digital transformation
|
||||
@@ -0,0 +1,22 @@
|
||||
# warm
|
||||
|
||||
Friendly, approachable, human-centered
|
||||
|
||||
## Color Palette
|
||||
|
||||
- Primary: Warm orange (#ED8936), golden yellow (#F6AD55), terracotta (#C05621)
|
||||
- Background: Cream (#FFFAF0), soft peach (#FED7AA)
|
||||
- Accents: Deep brown (#744210), soft red
|
||||
|
||||
## Visual Elements
|
||||
|
||||
- Rounded shapes, smiling faces
|
||||
- Sun rays, hearts, warm lighting
|
||||
|
||||
## Typography
|
||||
|
||||
- Friendly rounded hand lettering
|
||||
|
||||
## Best For
|
||||
|
||||
Personal growth, lifestyle, education, human stories
|
||||
@@ -1,10 +1,32 @@
|
||||
---
|
||||
name: baoyu-gemini-web
|
||||
description: Interacts with Gemini Web to generate text and images. Use when the user needs AI-generated content via Gemini, including text responses and image generation.
|
||||
description: Image generation skill using Gemini Web. Generates images from text prompts via Google Gemini. Also supports text generation. Use as the image generation backend for other skills like cover-image, xhs-images, article-illustrator.
|
||||
---
|
||||
|
||||
# Gemini Web Client
|
||||
|
||||
Supports:
|
||||
- Text generation
|
||||
- Image generation (download + save)
|
||||
- Reference image upload (attach images for vision tasks)
|
||||
- Multi-turn conversations within the same executor instance (`keepSession`)
|
||||
- Experimental video generation (`generateVideo`) — Gemini may return an async placeholder; download might require Gemini web UI
|
||||
|
||||
## Script Directory
|
||||
|
||||
**Important**: All scripts are located in the `scripts/` subdirectory of this skill.
|
||||
|
||||
**Agent Execution Instructions**:
|
||||
1. Determine this SKILL.md file's directory path as `SKILL_DIR`
|
||||
2. Script path = `${SKILL_DIR}/scripts/<script-name>.ts`
|
||||
3. Replace all `${SKILL_DIR}` in this document with the actual path
|
||||
|
||||
**Script Reference**:
|
||||
| Script | Purpose |
|
||||
|--------|---------|
|
||||
| `scripts/main.ts` | CLI entry point for text/image generation |
|
||||
| `scripts/executor.ts` | Programmatic Gemini executor API |
|
||||
|
||||
## Quick start
|
||||
|
||||
```bash
|
||||
@@ -12,8 +34,25 @@ npx -y bun scripts/main.ts "Hello, Gemini"
|
||||
npx -y bun scripts/main.ts --prompt "Explain quantum computing"
|
||||
npx -y bun scripts/main.ts --prompt "A cute cat" --image cat.png
|
||||
npx -y bun scripts/main.ts --promptfiles system.md content.md --image out.png
|
||||
|
||||
# Multi-turn conversation (agent generates unique sessionId)
|
||||
npx -y bun scripts/main.ts "Remember this: 42" --sessionId my-unique-id-123
|
||||
npx -y bun scripts/main.ts "What number?" --sessionId my-unique-id-123
|
||||
```
|
||||
|
||||
## Executor options (programmatic)
|
||||
|
||||
This skill is typically consumed via `createGeminiWebExecutor(geminiOptions)` (see `scripts/executor.ts`).
|
||||
|
||||
Key options in `GeminiWebOptions`:
|
||||
- `referenceImages?: string | string[]` Upload local images as references (vision input).
|
||||
- `keepSession?: boolean` Reuse Gemini `chatMetadata` to continue the same conversation across calls (required if you want reference images to persist across multiple messages).
|
||||
- `generateVideo?: string` Generate a video and (best-effort) download to the given path. Gemini may return `video_gen_chip` (async); in that case you must open Gemini web UI to download the result.
|
||||
|
||||
Notes:
|
||||
- `generateVideo` cannot be combined with `generateImage` / `editImage`.
|
||||
- When `keepSession=true` and `referenceImages` is set, reference images are uploaded once per executor instance.
|
||||
|
||||
## Commands
|
||||
|
||||
### Text generation
|
||||
@@ -58,17 +97,21 @@ npx -y bun scripts/main.ts "Hello" --json
|
||||
|
||||
## Options
|
||||
|
||||
| Option | Short | Description |
|
||||
|--------|-------|-------------|
|
||||
| `--prompt <text>` | `-p` | Prompt text |
|
||||
| `--promptfiles <files...>` | | Read prompt from files (concatenated in order) |
|
||||
| `--model <id>` | `-m` | Model: gemini-3-pro (default), gemini-2.5-pro, gemini-2.5-flash |
|
||||
| `--image [path]` | | Generate image, save to path (default: generated.png) |
|
||||
| `--json` | | Output as JSON |
|
||||
| `--login` | | Refresh cookies only, then exit |
|
||||
| `--cookie-path <path>` | | Custom cookie file path |
|
||||
| `--profile-dir <path>` | | Chrome profile directory |
|
||||
| `--help` | `-h` | Show help |
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--prompt <text>`, `-p` | Prompt text |
|
||||
| `--promptfiles <files...>` | Read prompt from files (concatenated in order) |
|
||||
| `--model <id>`, `-m` | Model: gemini-3-pro (default), gemini-2.5-pro, gemini-2.5-flash |
|
||||
| `--image [path]` | Generate image, save to path (default: generated.png) |
|
||||
| `--sessionId <id>` | Session ID for multi-turn conversation (agent generates unique ID) |
|
||||
| `--list-sessions` | List saved sessions (max 100, sorted by update time) |
|
||||
| `--json` | Output as JSON |
|
||||
| `--login` | Refresh cookies only, then exit |
|
||||
| `--cookie-path <path>` | Custom cookie file path |
|
||||
| `--profile-dir <path>` | Chrome profile directory |
|
||||
| `--help`, `-h` | Show help |
|
||||
|
||||
CLI note: `scripts/main.ts` supports text generation, image generation, and multi-turn conversations via `--sessionId`. Reference images and video generation are exposed via the executor API.
|
||||
|
||||
## Models
|
||||
|
||||
@@ -116,3 +159,22 @@ npx -y bun scripts/main.ts "Hello" --json | jq '.text'
|
||||
# Concatenate system.md + content.md as prompt
|
||||
npx -y bun scripts/main.ts --promptfiles system.md content.md --image output.png
|
||||
```
|
||||
|
||||
### Multi-turn conversation
|
||||
```bash
|
||||
# Start a session with unique ID (agent generates this)
|
||||
npx -y bun scripts/main.ts "You are a helpful math tutor." --sessionId task-abc123
|
||||
|
||||
# Continue the conversation (remembers context)
|
||||
npx -y bun scripts/main.ts "What is 2+2?" --sessionId task-abc123
|
||||
npx -y bun scripts/main.ts "Now multiply that by 10" --sessionId task-abc123
|
||||
|
||||
# List recent sessions (max 100, sorted by update time)
|
||||
npx -y bun scripts/main.ts --list-sessions
|
||||
```
|
||||
|
||||
Session files are stored in `~/Library/Application Support/baoyu-skills/gemini-web/sessions/<id>.json` and contain:
|
||||
- `id`: Session ID
|
||||
- `metadata`: Gemini chat metadata for continuation
|
||||
- `messages`: Array of `{role, content, timestamp, error?}`
|
||||
- `createdAt`, `updatedAt`: Timestamps
|
||||
|
||||
@@ -216,6 +216,7 @@ class CdpConnection {
|
||||
export async function getGeminiCookieMapViaChrome(options?: {
|
||||
timeoutMs?: number;
|
||||
debugConnectTimeoutMs?: number;
|
||||
tokenCheckTimeoutMs?: number;
|
||||
pollIntervalMs?: number;
|
||||
log?: GeminiWebLog;
|
||||
userDataDir?: string;
|
||||
@@ -224,6 +225,7 @@ export async function getGeminiCookieMapViaChrome(options?: {
|
||||
const log = options?.log;
|
||||
const timeoutMs = options?.timeoutMs ?? 5 * 60_000;
|
||||
const debugConnectTimeoutMs = options?.debugConnectTimeoutMs ?? 30_000;
|
||||
const tokenCheckTimeoutMs = options?.tokenCheckTimeoutMs ?? 30_000;
|
||||
const pollIntervalMs = options?.pollIntervalMs ?? 2_000;
|
||||
const userDataDir = options?.userDataDir ?? resolveGeminiWebChromeProfileDir();
|
||||
|
||||
@@ -290,7 +292,7 @@ export async function getGeminiCookieMapViaChrome(options?: {
|
||||
if (hasRequiredGeminiCookies(cookieMap)) {
|
||||
try {
|
||||
const controller = new AbortController();
|
||||
const timer = setTimeout(() => controller.abort(), 10_000);
|
||||
const timer = setTimeout(() => controller.abort(), tokenCheckTimeoutMs);
|
||||
try {
|
||||
await fetchGeminiAccessToken(cookieMap, controller.signal);
|
||||
} finally {
|
||||
|
||||
@@ -67,19 +67,69 @@ function buildCookieHeader(cookieMap: Record<string, string>): string {
|
||||
.join('; ');
|
||||
}
|
||||
|
||||
function getSetCookieHeaders(res: Response): string[] {
|
||||
const headers = res.headers as unknown as { getSetCookie?: () => string[] };
|
||||
if (typeof headers.getSetCookie === 'function') {
|
||||
try {
|
||||
return headers.getSetCookie();
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
const raw = res.headers.get('set-cookie');
|
||||
return raw ? [raw] : [];
|
||||
}
|
||||
|
||||
function applySetCookiesToMap(setCookies: string[], cookieMap: Record<string, string>): void {
|
||||
for (const raw of setCookies) {
|
||||
const first = raw.split(';')[0]?.trim();
|
||||
if (!first) continue;
|
||||
const idx = first.indexOf('=');
|
||||
if (idx <= 0) continue;
|
||||
const name = first.slice(0, idx).trim();
|
||||
const value = first.slice(idx + 1).trim();
|
||||
if (!name) continue;
|
||||
cookieMap[name] = value;
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchWithCookieJar(
|
||||
url: string,
|
||||
init: Omit<RequestInit, 'redirect' | 'headers'> & { headers?: Record<string, string> },
|
||||
cookieMap: Record<string, string>,
|
||||
signal?: AbortSignal,
|
||||
maxRedirects = 20,
|
||||
): Promise<Response> {
|
||||
let current = url;
|
||||
for (let i = 0; i <= maxRedirects; i += 1) {
|
||||
const cookieHeader = buildCookieHeader(cookieMap);
|
||||
const headers: Record<string, string> = {
|
||||
...(init.headers ?? {}),
|
||||
...(cookieHeader ? { cookie: cookieHeader } : {}),
|
||||
'user-agent': USER_AGENT,
|
||||
};
|
||||
|
||||
const res = await fetch(current, { ...init, redirect: 'manual', signal, headers });
|
||||
applySetCookiesToMap(getSetCookieHeaders(res), cookieMap);
|
||||
|
||||
if (res.status >= 300 && res.status < 400) {
|
||||
const location = res.headers.get('location');
|
||||
if (!location) return res;
|
||||
current = new URL(location, current).toString();
|
||||
continue;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
throw new Error(`Too many redirects while fetching ${url} (>${maxRedirects}).`);
|
||||
}
|
||||
|
||||
export async function fetchGeminiAccessToken(
|
||||
cookieMap: Record<string, string>,
|
||||
signal?: AbortSignal,
|
||||
): Promise<string> {
|
||||
const cookieHeader = buildCookieHeader(cookieMap);
|
||||
const res = await fetch(GEMINI_APP_URL, {
|
||||
redirect: 'follow',
|
||||
signal,
|
||||
headers: {
|
||||
cookie: cookieHeader,
|
||||
'user-agent': USER_AGENT,
|
||||
},
|
||||
});
|
||||
const res = await fetchWithCookieJar(GEMINI_APP_URL, { method: 'GET' }, cookieMap, signal);
|
||||
const html = await res.text();
|
||||
|
||||
const tokens = ['SNlM0e', 'thykhd'] as const;
|
||||
@@ -107,7 +157,21 @@ function extractErrorCode(responseJson: unknown): number | undefined {
|
||||
}
|
||||
|
||||
function extractGgdlUrls(rawText: string): string[] {
|
||||
const matches = rawText.match(/https:\/\/lh3\.googleusercontent\.com\/gg-dl\/[^\s"']+/g) ?? [];
|
||||
const matches =
|
||||
rawText.match(/https?:\/\/[^/\s"']*googleusercontent\.com\/gg-dl\/[^\s"']+/g) ?? [];
|
||||
const seen = new Set<string>();
|
||||
const urls: string[] = [];
|
||||
for (const match of matches) {
|
||||
if (seen.has(match)) continue;
|
||||
seen.add(match);
|
||||
urls.push(match);
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
|
||||
function extractImageGenerationContentUrls(rawText: string): string[] {
|
||||
const matches =
|
||||
rawText.match(/https?:\/\/googleusercontent\.com\/image_generation_content\/\d+/g) ?? [];
|
||||
const seen = new Set<string>();
|
||||
const urls: string[] = [];
|
||||
for (const match of matches) {
|
||||
@@ -119,9 +183,17 @@ function extractGgdlUrls(rawText: string): string[] {
|
||||
}
|
||||
|
||||
function ensureFullSizeImageUrl(url: string): string {
|
||||
if (url.includes('=s2048')) return url;
|
||||
if (url.includes('=s')) return url;
|
||||
return `${url}=s2048`;
|
||||
const trimmed = url.trim();
|
||||
let normalized = trimmed;
|
||||
const backslashIndex = normalized.indexOf('\\');
|
||||
if (backslashIndex >= 0) normalized = normalized.slice(0, backslashIndex);
|
||||
// Some Gemini responses embed a size suffix as "/=s2048" which breaks downloads.
|
||||
normalized = normalized.replace(/\/=s(?=\d+(?:$|[?#]))/, '=s');
|
||||
normalized = normalized.replace(/\/=s(?=$|[?#])/, '=s');
|
||||
if (normalized.endsWith('/')) normalized = normalized.slice(0, -1);
|
||||
if (normalized.includes('=s2048')) return normalized;
|
||||
if (normalized.includes('=s')) return normalized;
|
||||
return `${normalized}=s2048`;
|
||||
}
|
||||
|
||||
async function fetchWithCookiePreservingRedirects(
|
||||
@@ -190,6 +262,29 @@ async function uploadGeminiFile(filePath: string, signal?: AbortSignal): Promise
|
||||
return { id: text, name: fileName };
|
||||
}
|
||||
|
||||
function guessMimeType(fileName: string): string {
|
||||
const ext = path.extname(fileName).toLowerCase();
|
||||
switch (ext) {
|
||||
case '.png':
|
||||
return 'image/png';
|
||||
case '.jpg':
|
||||
case '.jpeg':
|
||||
return 'image/jpeg';
|
||||
case '.webp':
|
||||
return 'image/webp';
|
||||
case '.gif':
|
||||
return 'image/gif';
|
||||
case '.mp4':
|
||||
return 'video/mp4';
|
||||
case '.mov':
|
||||
return 'video/quicktime';
|
||||
case '.webm':
|
||||
return 'video/webm';
|
||||
default:
|
||||
return 'application/octet-stream';
|
||||
}
|
||||
}
|
||||
|
||||
function buildGeminiFReqPayload(
|
||||
prompt: string,
|
||||
uploaded: Array<{ id: string; name: string }>,
|
||||
@@ -201,9 +296,8 @@ function buildGeminiFReqPayload(
|
||||
prompt,
|
||||
0,
|
||||
null,
|
||||
// Matches gemini-webapi payload format: [[[fileId, 1]]] for a single attachment.
|
||||
// Keep it extensible for multiple uploads by emitting one [[id, 1]] entry per file.
|
||||
uploaded.map((file) => [[file.id, 1]]),
|
||||
// Matches gemini-web payload format: [[[fileId, 1, null, mimeType], fileName]] for an attachment.
|
||||
uploaded.map((file) => [[file.id, 1, null, guessMimeType(file.name)], file.name]),
|
||||
]
|
||||
: [prompt];
|
||||
|
||||
@@ -248,7 +342,19 @@ export function parseGeminiStreamGenerateResponse(rawText: string): {
|
||||
? (getNestedValue<string | null>(firstCandidate, [22, 0], null) ?? textRaw)
|
||||
: textRaw;
|
||||
const thoughts = getNestedValue<string | null>(firstCandidate, [37, 0, 0], null);
|
||||
const metadata = getNestedValue<unknown>(body, [1], []);
|
||||
const conversationMeta = getNestedValue<unknown[]>(body, [1], []);
|
||||
const conversationId =
|
||||
typeof conversationMeta[0] === 'string' && conversationMeta[0].length > 0
|
||||
? conversationMeta[0]
|
||||
: null;
|
||||
const responseId =
|
||||
typeof conversationMeta[1] === 'string' && conversationMeta[1].length > 0
|
||||
? conversationMeta[1]
|
||||
: null;
|
||||
const choiceIdRaw = getNestedValue<string | null>(firstCandidate, [0], null);
|
||||
const choiceId = typeof choiceIdRaw === 'string' && choiceIdRaw.length > 0 ? choiceIdRaw : null;
|
||||
const metadata =
|
||||
conversationId && responseId && choiceId ? [conversationId, responseId, choiceId] : conversationMeta;
|
||||
|
||||
const images: GeminiWebCandidateImage[] = [];
|
||||
|
||||
@@ -305,8 +411,8 @@ export function isGeminiModelUnavailable(errorCode: number | undefined): boolean
|
||||
}
|
||||
|
||||
export async function runGeminiWebOnce(input: GeminiWebRunInput): Promise<GeminiWebRunOutput> {
|
||||
const cookieHeader = buildCookieHeader(input.cookieMap);
|
||||
const at = await fetchGeminiAccessToken(input.cookieMap, input.signal);
|
||||
const cookieHeader = buildCookieHeader(input.cookieMap);
|
||||
|
||||
const uploaded: Array<{ id: string; name: string }> = [];
|
||||
for (const file of input.files ?? []) {
|
||||
@@ -403,11 +509,19 @@ export async function saveFirstGeminiImageFromOutput(
|
||||
return { saved: true, imageCount: output.images.length };
|
||||
}
|
||||
|
||||
const ggdl = extractGgdlUrls(output.rawResponseText);
|
||||
if (ggdl[0]) {
|
||||
await downloadGeminiImage(ggdl[0], cookieMap, outputPath, signal);
|
||||
const ggdl = extractGgdlUrls(`${output.text}\n${output.rawResponseText}`);
|
||||
const preferred = ggdl.length > 0 ? ggdl[ggdl.length - 1] : null;
|
||||
if (preferred) {
|
||||
await downloadGeminiImage(preferred, cookieMap, outputPath, signal);
|
||||
return { saved: true, imageCount: ggdl.length };
|
||||
}
|
||||
|
||||
const imageGen = extractImageGenerationContentUrls(`${output.text}\n${output.rawResponseText}`);
|
||||
const imageGenPreferred = imageGen.length > 0 ? imageGen[imageGen.length - 1] : null;
|
||||
if (imageGenPreferred) {
|
||||
await downloadGeminiImage(imageGenPreferred, cookieMap, outputPath, signal);
|
||||
return { saved: true, imageCount: imageGen.length };
|
||||
}
|
||||
|
||||
return { saved: false, imageCount: 0 };
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { mkdir, writeFile } from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import type { BrowserRunOptions, BrowserRunResult, BrowserLogger, CookieParam } from '../browser/types.js';
|
||||
import { runGeminiWebWithFallback, saveFirstGeminiImageFromOutput } from './client.js';
|
||||
import type { GeminiWebModelId } from './client.js';
|
||||
import type { GeminiWebModelId, GeminiWebRunOutput } from './client.js';
|
||||
import {
|
||||
buildGeminiCookieMap,
|
||||
hasRequiredGeminiCookies,
|
||||
@@ -11,6 +12,9 @@ import type { GeminiWebOptions, GeminiWebResponse } from './types.js';
|
||||
|
||||
export { hasRequiredGeminiCookies } from './cookie-store.js';
|
||||
|
||||
const USER_AGENT =
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36';
|
||||
|
||||
function estimateTokenCount(text: string): number {
|
||||
return Math.ceil(text.length / 4);
|
||||
}
|
||||
@@ -22,6 +26,115 @@ function resolveInvocationPath(value: string | undefined): string | undefined {
|
||||
return path.isAbsolute(trimmed) ? trimmed : path.resolve(process.cwd(), trimmed);
|
||||
}
|
||||
|
||||
function normalizePathList(value: string | string[] | undefined): string[] {
|
||||
if (!value) return [];
|
||||
const raw = Array.isArray(value) ? value : [value];
|
||||
const out: string[] = [];
|
||||
for (const entry of raw) {
|
||||
if (typeof entry !== 'string') continue;
|
||||
const resolved = resolveInvocationPath(entry);
|
||||
if (!resolved) continue;
|
||||
out.push(resolved);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function dedupePaths(paths: string[]): string[] {
|
||||
const seen = new Set<string>();
|
||||
const out: string[] = [];
|
||||
for (const item of paths) {
|
||||
const trimmed = item.trim();
|
||||
if (!trimmed || seen.has(trimmed)) continue;
|
||||
seen.add(trimmed);
|
||||
out.push(trimmed);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function buildCookieHeader(cookieMap: Record<string, string>): string {
|
||||
return Object.entries(cookieMap)
|
||||
.filter(([, value]) => typeof value === 'string' && value.length > 0)
|
||||
.map(([name, value]) => `${name}=${value}`)
|
||||
.join('; ');
|
||||
}
|
||||
|
||||
async function fetchWithCookiePreservingRedirects(
|
||||
url: string,
|
||||
init: Omit<RequestInit, 'redirect'>,
|
||||
signal?: AbortSignal,
|
||||
maxRedirects = 10,
|
||||
): Promise<Response> {
|
||||
let current = url;
|
||||
for (let i = 0; i <= maxRedirects; i += 1) {
|
||||
const res = await fetch(current, { ...init, redirect: 'manual', signal });
|
||||
if (res.status >= 300 && res.status < 400) {
|
||||
const location = res.headers.get('location');
|
||||
if (!location) return res;
|
||||
current = new URL(location, current).toString();
|
||||
continue;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
throw new Error(`Too many redirects while downloading media (>${maxRedirects}).`);
|
||||
}
|
||||
|
||||
async function downloadGeminiMedia(
|
||||
url: string,
|
||||
cookieMap: Record<string, string>,
|
||||
outputPath: string,
|
||||
signal?: AbortSignal,
|
||||
): Promise<void> {
|
||||
const cookieHeader = buildCookieHeader(cookieMap);
|
||||
const res = await fetchWithCookiePreservingRedirects(
|
||||
url,
|
||||
{
|
||||
headers: {
|
||||
cookie: cookieHeader,
|
||||
'user-agent': USER_AGENT,
|
||||
},
|
||||
},
|
||||
signal,
|
||||
);
|
||||
if (!res.ok) {
|
||||
throw new Error(`Failed to download media: ${res.status} ${res.statusText} (${res.url})`);
|
||||
}
|
||||
|
||||
const data = new Uint8Array(await res.arrayBuffer());
|
||||
await mkdir(path.dirname(outputPath), { recursive: true });
|
||||
await writeFile(outputPath, data);
|
||||
}
|
||||
|
||||
function extractGgdlUrls(rawText: string): string[] {
|
||||
const matches =
|
||||
rawText.match(/https?:\/\/[^/\s"']*googleusercontent\.com\/gg-dl\/[^\s"']+/g) ?? [];
|
||||
const seen = new Set<string>();
|
||||
const urls: string[] = [];
|
||||
for (const match of matches) {
|
||||
if (seen.has(match)) continue;
|
||||
seen.add(match);
|
||||
urls.push(match);
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
|
||||
async function saveFirstGeminiVideoFromOutput(
|
||||
output: GeminiWebRunOutput,
|
||||
cookieMap: Record<string, string>,
|
||||
outputPath: string,
|
||||
signal?: AbortSignal,
|
||||
): Promise<{ saved: boolean; videoCount: number }> {
|
||||
const ggdl = extractGgdlUrls(output.rawResponseText);
|
||||
if (!ggdl[0]) return { saved: false, videoCount: 0 };
|
||||
|
||||
const videoCandidates = ggdl.filter((url) => /\.(mp4|webm|mov)(?:$|[?#])/i.test(url));
|
||||
const preferred =
|
||||
(videoCandidates.length > 0 ? videoCandidates[videoCandidates.length - 1] : null) ??
|
||||
ggdl.find((url) => /video/i.test(url)) ??
|
||||
ggdl[ggdl.length - 1];
|
||||
await downloadGeminiMedia(preferred, cookieMap, outputPath, signal);
|
||||
return { saved: true, videoCount: ggdl.length };
|
||||
}
|
||||
|
||||
function resolveGeminiWebModel(
|
||||
desiredModel: string | null | undefined,
|
||||
log?: BrowserLogger,
|
||||
@@ -115,6 +228,9 @@ export async function loadGeminiCookieMap(log?: BrowserLogger): Promise<Record<s
|
||||
export function createGeminiWebExecutor(
|
||||
geminiOptions: GeminiWebOptions,
|
||||
): (runOptions: BrowserRunOptions) => Promise<BrowserRunResult> {
|
||||
let persistedChatMetadata: unknown | null = null;
|
||||
let referenceImagesUploaded = false;
|
||||
|
||||
return async (runOptions: BrowserRunOptions): Promise<BrowserRunResult> => {
|
||||
const startTime = Date.now();
|
||||
const log = runOptions.log;
|
||||
@@ -133,23 +249,38 @@ export function createGeminiWebExecutor(
|
||||
? Math.max(1_000, runOptions.config.timeoutMs)
|
||||
: null;
|
||||
|
||||
const generateVideoPath = resolveInvocationPath(geminiOptions.generateVideo);
|
||||
|
||||
const defaultTimeoutMs = geminiOptions.youtube
|
||||
? 240_000
|
||||
: geminiOptions.generateImage || geminiOptions.editImage
|
||||
: generateVideoPath
|
||||
? 900_000
|
||||
: geminiOptions.generateImage || geminiOptions.editImage
|
||||
? 300_000
|
||||
: 120_000;
|
||||
|
||||
const timeoutMs = Math.min(configTimeout ?? defaultTimeoutMs, 600_000);
|
||||
const timeoutCapMs = generateVideoPath ? 1_800_000 : 600_000;
|
||||
const timeoutMs = Math.min(configTimeout ?? defaultTimeoutMs, timeoutCapMs);
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
||||
|
||||
const keepSession = geminiOptions.keepSession === true;
|
||||
|
||||
const generateImagePath = resolveInvocationPath(geminiOptions.generateImage);
|
||||
const editImagePath = resolveInvocationPath(geminiOptions.editImage);
|
||||
const outputPath = resolveInvocationPath(geminiOptions.outputPath);
|
||||
const attachmentPaths = (runOptions.attachments ?? []).map((attachment) => attachment.path);
|
||||
const referenceImagePaths = normalizePathList(geminiOptions.referenceImages);
|
||||
const requestFilePaths = dedupePaths(
|
||||
keepSession ? attachmentPaths : [...referenceImagePaths, ...attachmentPaths],
|
||||
);
|
||||
|
||||
if (generateVideoPath && (generateImagePath || editImagePath)) {
|
||||
throw new Error('Gemini web executor: generateVideo cannot be combined with generateImage/editImage options.');
|
||||
}
|
||||
|
||||
let prompt = runOptions.prompt;
|
||||
if (geminiOptions.aspectRatio && (generateImagePath || editImagePath)) {
|
||||
if (geminiOptions.aspectRatio && (generateImagePath || editImagePath || generateVideoPath)) {
|
||||
prompt = `${prompt} (aspect ratio: ${geminiOptions.aspectRatio})`;
|
||||
}
|
||||
if (geminiOptions.youtube) {
|
||||
@@ -158,29 +289,50 @@ export function createGeminiWebExecutor(
|
||||
if (generateImagePath && !editImagePath) {
|
||||
prompt = `Generate an image: ${prompt}`;
|
||||
}
|
||||
if (generateVideoPath) {
|
||||
prompt = `Generate a video: ${prompt}`;
|
||||
}
|
||||
|
||||
const model: GeminiWebModelId = resolveGeminiWebModel(runOptions.config?.desiredModel, log);
|
||||
let response: GeminiWebResponse;
|
||||
let videoSaveSummary: { saved: boolean; videoCount: number; outputPath: string } | null = null;
|
||||
|
||||
try {
|
||||
let chatMetadata: unknown = keepSession ? persistedChatMetadata : null;
|
||||
|
||||
if (keepSession && referenceImagePaths.length > 0 && !referenceImagesUploaded) {
|
||||
const intro = await runGeminiWebWithFallback({
|
||||
prompt: 'Here are reference images for future messages.',
|
||||
files: referenceImagePaths,
|
||||
model,
|
||||
cookieMap,
|
||||
chatMetadata,
|
||||
signal: controller.signal,
|
||||
});
|
||||
chatMetadata = intro.metadata;
|
||||
persistedChatMetadata = intro.metadata;
|
||||
referenceImagesUploaded = true;
|
||||
}
|
||||
|
||||
if (editImagePath) {
|
||||
const intro = await runGeminiWebWithFallback({
|
||||
prompt: 'Here is an image to edit',
|
||||
files: [editImagePath],
|
||||
model,
|
||||
cookieMap,
|
||||
chatMetadata: null,
|
||||
chatMetadata,
|
||||
signal: controller.signal,
|
||||
});
|
||||
const editPrompt = `Use image generation tool to ${prompt}`;
|
||||
const out = await runGeminiWebWithFallback({
|
||||
prompt: editPrompt,
|
||||
files: attachmentPaths,
|
||||
files: requestFilePaths,
|
||||
model,
|
||||
cookieMap,
|
||||
chatMetadata: intro.metadata,
|
||||
signal: controller.signal,
|
||||
});
|
||||
if (keepSession) persistedChatMetadata = out.metadata;
|
||||
response = {
|
||||
text: out.text ?? null,
|
||||
thoughts: geminiOptions.showThoughts ? out.thoughts : null,
|
||||
@@ -198,12 +350,13 @@ export function createGeminiWebExecutor(
|
||||
} else if (generateImagePath) {
|
||||
const out = await runGeminiWebWithFallback({
|
||||
prompt,
|
||||
files: attachmentPaths,
|
||||
files: requestFilePaths,
|
||||
model,
|
||||
cookieMap,
|
||||
chatMetadata: null,
|
||||
chatMetadata,
|
||||
signal: controller.signal,
|
||||
});
|
||||
if (keepSession) persistedChatMetadata = out.metadata;
|
||||
response = {
|
||||
text: out.text ?? null,
|
||||
thoughts: geminiOptions.showThoughts ? out.thoughts : null,
|
||||
@@ -216,15 +369,36 @@ export function createGeminiWebExecutor(
|
||||
if (!imageSave.saved) {
|
||||
throw new Error(`No images generated. Response text:\n${out.text || '(empty response)'}`);
|
||||
}
|
||||
} else if (generateVideoPath) {
|
||||
const out = await runGeminiWebWithFallback({
|
||||
prompt,
|
||||
files: requestFilePaths,
|
||||
model,
|
||||
cookieMap,
|
||||
chatMetadata,
|
||||
signal: controller.signal,
|
||||
});
|
||||
if (keepSession) persistedChatMetadata = out.metadata;
|
||||
response = {
|
||||
text: out.text ?? null,
|
||||
thoughts: geminiOptions.showThoughts ? out.thoughts : null,
|
||||
has_images: false,
|
||||
image_count: 0,
|
||||
};
|
||||
|
||||
const resolvedOutputPath = generateVideoPath ?? outputPath ?? 'generated.mp4';
|
||||
const save = await saveFirstGeminiVideoFromOutput(out, cookieMap, resolvedOutputPath, controller.signal);
|
||||
videoSaveSummary = { ...save, outputPath: resolvedOutputPath };
|
||||
} else {
|
||||
const out = await runGeminiWebWithFallback({
|
||||
prompt,
|
||||
files: attachmentPaths,
|
||||
files: requestFilePaths,
|
||||
model,
|
||||
cookieMap,
|
||||
chatMetadata: null,
|
||||
chatMetadata,
|
||||
signal: controller.signal,
|
||||
});
|
||||
if (keepSession) persistedChatMetadata = out.metadata;
|
||||
response = {
|
||||
text: out.text ?? null,
|
||||
thoughts: geminiOptions.showThoughts ? out.thoughts : null,
|
||||
@@ -247,6 +421,15 @@ export function createGeminiWebExecutor(
|
||||
const imagePath = generateImagePath || outputPath || 'generated.png';
|
||||
answerMarkdown += `\n\n*Generated ${response.image_count} image(s). Saved to: ${imagePath}*`;
|
||||
}
|
||||
if (videoSaveSummary) {
|
||||
if (videoSaveSummary.saved) {
|
||||
answerMarkdown += `\n\n*Generated ${videoSaveSummary.videoCount || 1} video(s). Saved to: ${videoSaveSummary.outputPath}*`;
|
||||
} else if (/video_gen_chip/.test(answerMarkdown) || /video_gen_chip/.test(response.text ?? '')) {
|
||||
answerMarkdown += '\n\n*Video generation is asynchronous. Check Gemini web UI to download the result.*';
|
||||
} else {
|
||||
answerMarkdown += '\n\n*No downloadable video URL found in Gemini response.*';
|
||||
}
|
||||
}
|
||||
|
||||
const tookMs = Date.now() - startTime;
|
||||
log?.(`[gemini-web] Completed in ${tookMs}ms`);
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
writeGeminiCookieMapToDisk,
|
||||
} from './cookie-store.js';
|
||||
import { resolveGeminiWebChromeProfileDir, resolveGeminiWebCookiePath } from './paths.js';
|
||||
import { readSession, writeSession, listSessions } from './session-store.js';
|
||||
|
||||
function printUsage(exitCode = 0): never {
|
||||
const cookiePath = resolveGeminiWebCookiePath();
|
||||
@@ -21,12 +22,19 @@ function printUsage(exitCode = 0): never {
|
||||
npx -y bun skills/baoyu-gemini-web/scripts/main.ts --prompt "A cute cat" --image generated.png
|
||||
npx -y bun skills/baoyu-gemini-web/scripts/main.ts --promptfiles system.md content.md --image out.png
|
||||
|
||||
Multi-turn conversation (agent generates unique sessionId):
|
||||
npx -y bun skills/baoyu-gemini-web/scripts/main.ts "Remember 42" --sessionId abc123
|
||||
npx -y bun skills/baoyu-gemini-web/scripts/main.ts "What number?" --sessionId abc123
|
||||
|
||||
Options:
|
||||
-p, --prompt <text> Prompt text
|
||||
--promptfiles <files...> Read prompt from one or more files (concatenated in order)
|
||||
-m, --model <id> gemini-3-pro | gemini-2.5-pro | gemini-2.5-flash (default: gemini-3-pro)
|
||||
--json Output JSON
|
||||
--image [path] Generate an image and save it (default: ./generated.png)
|
||||
--reference <files...> Reference images for vision input
|
||||
--sessionId <id> Session ID for multi-turn conversation (agent should generate unique ID)
|
||||
--list-sessions List saved sessions (max 100, sorted by update time)
|
||||
--login Only refresh cookies, then exit
|
||||
--cookie-path <path> Cookie file path (default: ${cookiePath})
|
||||
--profile-dir <path> Chrome profile dir (default: ${profileDir})
|
||||
@@ -75,6 +83,9 @@ function parseArgs(argv: string[]): {
|
||||
loginOnly?: boolean;
|
||||
cookiePath?: string;
|
||||
profileDir?: string;
|
||||
referenceImages?: string[];
|
||||
sessionId?: string;
|
||||
listSessions?: boolean;
|
||||
} {
|
||||
const out: ReturnType<typeof parseArgs> = {};
|
||||
const positional: string[] = [];
|
||||
@@ -157,6 +168,32 @@ function parseArgs(argv: string[]): {
|
||||
out.profileDir = arg.slice('--profile-dir='.length);
|
||||
continue;
|
||||
}
|
||||
if (arg === '--reference' || arg === '--ref') {
|
||||
out.referenceImages = [];
|
||||
while (i + 1 < argv.length) {
|
||||
const next = argv[i + 1];
|
||||
if (next && !next.startsWith('-')) {
|
||||
out.referenceImages.push(next);
|
||||
i += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (arg === '--sessionId' || arg === '--session-id') {
|
||||
out.sessionId = argv[i + 1] ?? '';
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
if (arg.startsWith('--sessionId=') || arg.startsWith('--session-id=')) {
|
||||
out.sessionId = arg.split('=')[1] ?? '';
|
||||
continue;
|
||||
}
|
||||
if (arg === '--list-sessions') {
|
||||
out.listSessions = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg.startsWith('-')) {
|
||||
throw new Error(`Unknown option: ${arg}`);
|
||||
@@ -178,6 +215,9 @@ function parseArgs(argv: string[]): {
|
||||
if (out.cookiePath === '') delete out.cookiePath;
|
||||
if (out.profileDir === '') delete out.profileDir;
|
||||
if (out.promptFiles?.length === 0) delete out.promptFiles;
|
||||
if (out.referenceImages?.length === 0) delete out.referenceImages;
|
||||
if (out.sessionId != null) out.sessionId = out.sessionId.trim();
|
||||
if (out.sessionId === '') delete out.sessionId;
|
||||
|
||||
return out;
|
||||
}
|
||||
@@ -186,7 +226,7 @@ async function isCookieMapValid(cookieMap: Record<string, string>): Promise<bool
|
||||
if (!hasRequiredGeminiCookies(cookieMap)) return false;
|
||||
|
||||
const controller = new AbortController();
|
||||
const timer = setTimeout(() => controller.abort(), 10_000);
|
||||
const timer = setTimeout(() => controller.abort(), 30_000);
|
||||
try {
|
||||
await fetchGeminiAccessToken(cookieMap, controller.signal);
|
||||
return true;
|
||||
@@ -201,7 +241,7 @@ async function ensureGeminiCookieMap(options: {
|
||||
cookiePath: string;
|
||||
profileDir: string;
|
||||
}): Promise<Record<string, string>> {
|
||||
const log = (msg: string) => console.log(msg);
|
||||
const log = (msg: string) => console.error(msg);
|
||||
|
||||
let cookieMap = await readGeminiCookieMapFromDisk({ cookiePath: options.cookiePath, log });
|
||||
if (await isCookieMapValid(cookieMap)) return cookieMap;
|
||||
@@ -251,85 +291,63 @@ async function main(): Promise<void> {
|
||||
const cookiePath = args.cookiePath ?? resolveGeminiWebCookiePath();
|
||||
const profileDir = args.profileDir ?? resolveGeminiWebChromeProfileDir();
|
||||
|
||||
if (args.listSessions) {
|
||||
const sessions = await listSessions();
|
||||
if (sessions.length === 0) {
|
||||
console.log('No saved sessions.');
|
||||
} else {
|
||||
for (const { id, updatedAt } of sessions) {
|
||||
console.log(`${id}\t${updatedAt}`);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.loginOnly) {
|
||||
await ensureGeminiCookieMap({ cookiePath, profileDir });
|
||||
return;
|
||||
}
|
||||
|
||||
const promptFromStdin = await readPromptFromStdin();
|
||||
const promptFromFiles = args.promptFiles ? readPromptFiles(args.promptFiles) : null;
|
||||
const prompt = promptFromFiles || args.prompt || promptFromStdin;
|
||||
const promptFromArgs = promptFromFiles || args.prompt;
|
||||
const prompt = promptFromArgs || (await readPromptFromStdin());
|
||||
if (!prompt) printUsage(1);
|
||||
|
||||
const sessionData = args.sessionId ? await readSession(args.sessionId) : null;
|
||||
const chatMetadata = sessionData?.metadata ?? null;
|
||||
|
||||
let cookieMap = await ensureGeminiCookieMap({ cookiePath, profileDir });
|
||||
|
||||
const desiredModel = resolveModel(args.model || 'gemini-3-pro');
|
||||
const imagePath = resolveImageOutputPath(args.imagePath);
|
||||
const referenceImages = (args.referenceImages ?? []).map((p) =>
|
||||
path.isAbsolute(p) ? p : path.resolve(process.cwd(), p),
|
||||
);
|
||||
|
||||
try {
|
||||
const effectivePrompt = imagePath ? `Generate an image: ${prompt}` : prompt;
|
||||
const out = await runGeminiWebWithFallback({
|
||||
prompt: effectivePrompt,
|
||||
files: [],
|
||||
model: desiredModel,
|
||||
cookieMap,
|
||||
chatMetadata: null,
|
||||
});
|
||||
|
||||
let imageSaved = false;
|
||||
let imageCount = 0;
|
||||
if (imagePath) {
|
||||
const save = await saveFirstGeminiImageFromOutput(out, cookieMap, imagePath);
|
||||
imageSaved = save.saved;
|
||||
imageCount = save.imageCount;
|
||||
if (!imageSaved) {
|
||||
throw new Error(`No images generated. Response text:\n${out.text || '(empty response)'}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (args.json) {
|
||||
process.stdout.write(
|
||||
`${JSON.stringify(
|
||||
imagePath ? { ...out, imageSaved, imageCount, imagePath } : out,
|
||||
null,
|
||||
2,
|
||||
)}\n`,
|
||||
);
|
||||
if (out.errorMessage) process.exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (out.errorMessage) {
|
||||
throw new Error(out.errorMessage);
|
||||
}
|
||||
|
||||
process.stdout.write(out.text ?? '');
|
||||
if (!out.text?.endsWith('\n')) process.stdout.write('\n');
|
||||
if (imagePath) {
|
||||
process.stdout.write(`Saved image (${imageCount || 1}) to: ${imagePath}\n`);
|
||||
}
|
||||
return;
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
|
||||
if (message.includes('Unable to locate Gemini access token')) {
|
||||
console.error('[gemini-web] Cookies may be expired. Re-opening browser to refresh cookies...');
|
||||
await sleep(500);
|
||||
cookieMap = await getGeminiCookieMapViaChrome({ userDataDir: profileDir, log: (m) => console.log(m) });
|
||||
await writeGeminiCookieMapToDisk(cookieMap, { cookiePath, log: (m) => console.log(m) });
|
||||
const controller = new AbortController();
|
||||
const timeoutMs = imagePath ? 300_000 : 120_000;
|
||||
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
||||
|
||||
try {
|
||||
const effectivePrompt = imagePath ? `Generate an image: ${prompt}` : prompt;
|
||||
const out = await runGeminiWebWithFallback({
|
||||
prompt: imagePath ? `Generate an image: ${prompt}` : prompt,
|
||||
files: [],
|
||||
prompt: effectivePrompt,
|
||||
files: referenceImages,
|
||||
model: desiredModel,
|
||||
cookieMap,
|
||||
chatMetadata: null,
|
||||
chatMetadata,
|
||||
signal: controller.signal,
|
||||
});
|
||||
|
||||
if (args.sessionId && out.metadata) {
|
||||
await writeSession(args.sessionId, out.metadata, prompt, out.text ?? '', out.errorMessage);
|
||||
}
|
||||
|
||||
let imageSaved = false;
|
||||
let imageCount = 0;
|
||||
if (imagePath) {
|
||||
const save = await saveFirstGeminiImageFromOutput(out, cookieMap, imagePath);
|
||||
const save = await saveFirstGeminiImageFromOutput(out, cookieMap, imagePath, controller.signal);
|
||||
imageSaved = save.saved;
|
||||
imageCount = save.imageCount;
|
||||
if (!imageSaved) {
|
||||
@@ -338,13 +356,8 @@ async function main(): Promise<void> {
|
||||
}
|
||||
|
||||
if (args.json) {
|
||||
process.stdout.write(
|
||||
`${JSON.stringify(
|
||||
imagePath ? { ...out, imageSaved, imageCount, imagePath } : out,
|
||||
null,
|
||||
2,
|
||||
)}\n`,
|
||||
);
|
||||
const jsonOut = { ...out, ...(imagePath && { imageSaved, imageCount, imagePath }), ...(args.sessionId && { sessionId: args.sessionId }) };
|
||||
process.stdout.write(`${JSON.stringify(jsonOut, null, 2)}\n`);
|
||||
if (out.errorMessage) process.exit(1);
|
||||
return;
|
||||
}
|
||||
@@ -359,6 +372,67 @@ async function main(): Promise<void> {
|
||||
process.stdout.write(`Saved image (${imageCount || 1}) to: ${imagePath}\n`);
|
||||
}
|
||||
return;
|
||||
} finally {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
|
||||
if (message.includes('Unable to locate Gemini access token')) {
|
||||
console.error('[gemini-web] Cookies may be expired. Re-opening browser to refresh cookies...');
|
||||
await sleep(500);
|
||||
cookieMap = await getGeminiCookieMapViaChrome({ userDataDir: profileDir, log: (m) => console.error(m) });
|
||||
await writeGeminiCookieMapToDisk(cookieMap, { cookiePath, log: (m) => console.error(m) });
|
||||
|
||||
const controller = new AbortController();
|
||||
const timeoutMs = imagePath ? 300_000 : 120_000;
|
||||
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
||||
|
||||
try {
|
||||
const out = await runGeminiWebWithFallback({
|
||||
prompt: imagePath ? `Generate an image: ${prompt}` : prompt,
|
||||
files: referenceImages,
|
||||
model: desiredModel,
|
||||
cookieMap,
|
||||
chatMetadata,
|
||||
signal: controller.signal,
|
||||
});
|
||||
|
||||
if (args.sessionId && out.metadata) {
|
||||
await writeSession(args.sessionId, out.metadata, prompt, out.text ?? '', out.errorMessage);
|
||||
}
|
||||
|
||||
let imageSaved = false;
|
||||
let imageCount = 0;
|
||||
if (imagePath) {
|
||||
const save = await saveFirstGeminiImageFromOutput(out, cookieMap, imagePath, controller.signal);
|
||||
imageSaved = save.saved;
|
||||
imageCount = save.imageCount;
|
||||
if (!imageSaved) {
|
||||
throw new Error(`No images generated. Response text:\n${out.text || '(empty response)'}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (args.json) {
|
||||
const jsonOut = { ...out, ...(imagePath && { imageSaved, imageCount, imagePath }), ...(args.sessionId && { sessionId: args.sessionId }) };
|
||||
process.stdout.write(`${JSON.stringify(jsonOut, null, 2)}\n`);
|
||||
if (out.errorMessage) process.exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (out.errorMessage) {
|
||||
throw new Error(out.errorMessage);
|
||||
}
|
||||
|
||||
process.stdout.write(out.text ?? '');
|
||||
if (!out.text?.endsWith('\n')) process.stdout.write('\n');
|
||||
if (imagePath) {
|
||||
process.stdout.write(`Saved image (${imageCount || 1}) to: ${imagePath}\n`);
|
||||
}
|
||||
return;
|
||||
} finally {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
throw error;
|
||||
|
||||
@@ -34,3 +34,12 @@ export function resolveGeminiWebChromeProfileDir(): string {
|
||||
if (override) return path.resolve(override);
|
||||
return path.join(resolveGeminiWebDataDir(), PROFILE_DIR_NAME);
|
||||
}
|
||||
|
||||
export function resolveGeminiWebSessionsDir(): string {
|
||||
return path.join(resolveGeminiWebDataDir(), 'sessions');
|
||||
}
|
||||
|
||||
export function resolveGeminiWebSessionPath(name: string): string {
|
||||
const sanitized = name.replace(/[^a-zA-Z0-9_-]/g, '_');
|
||||
return path.join(resolveGeminiWebSessionsDir(), `${sanitized}.json`);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
import { mkdir, readFile, writeFile, readdir, stat } from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import { resolveGeminiWebSessionsDir, resolveGeminiWebSessionPath } from './paths.js';
|
||||
|
||||
export interface SessionMessage {
|
||||
role: 'user' | 'assistant';
|
||||
content: string;
|
||||
timestamp: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface SessionData {
|
||||
id: string;
|
||||
metadata: unknown;
|
||||
messages: SessionMessage[];
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface SessionListItem {
|
||||
id: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export async function readSession(id: string): Promise<SessionData | null> {
|
||||
const sessionPath = resolveGeminiWebSessionPath(id);
|
||||
try {
|
||||
const content = await readFile(sessionPath, 'utf8');
|
||||
return JSON.parse(content) as SessionData;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function writeSession(
|
||||
id: string,
|
||||
metadata: unknown,
|
||||
userMessage: string,
|
||||
assistantMessage: string,
|
||||
error?: string,
|
||||
): Promise<void> {
|
||||
const sessionPath = resolveGeminiWebSessionPath(id);
|
||||
const sessionsDir = resolveGeminiWebSessionsDir();
|
||||
await mkdir(sessionsDir, { recursive: true });
|
||||
|
||||
const existing = await readSession(id);
|
||||
const now = new Date().toISOString();
|
||||
|
||||
const newMessages: SessionMessage[] = [
|
||||
{ role: 'user', content: userMessage, timestamp: now },
|
||||
{ role: 'assistant', content: assistantMessage, timestamp: now, ...(error && { error }) },
|
||||
];
|
||||
|
||||
const data: SessionData = {
|
||||
id,
|
||||
metadata,
|
||||
messages: [...(existing?.messages ?? []), ...newMessages],
|
||||
createdAt: existing?.createdAt ?? now,
|
||||
updatedAt: now,
|
||||
};
|
||||
await writeFile(sessionPath, JSON.stringify(data, null, 2));
|
||||
}
|
||||
|
||||
export async function listSessions(limit = 100): Promise<SessionListItem[]> {
|
||||
const sessionsDir = resolveGeminiWebSessionsDir();
|
||||
try {
|
||||
const files = await readdir(sessionsDir);
|
||||
const jsonFiles = files.filter((f) => f.endsWith('.json'));
|
||||
|
||||
const items: { id: string; updatedAt: string; mtime: number }[] = [];
|
||||
for (const file of jsonFiles) {
|
||||
const filePath = path.join(sessionsDir, file);
|
||||
try {
|
||||
const stats = await stat(filePath);
|
||||
items.push({
|
||||
id: file.slice(0, -5),
|
||||
updatedAt: stats.mtime.toISOString(),
|
||||
mtime: stats.mtime.getTime(),
|
||||
});
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
items.sort((a, b) => b.mtime - a.mtime);
|
||||
return items.slice(0, limit).map(({ id, updatedAt }) => ({ id, updatedAt }));
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,18 @@ export interface GeminiWebOptions {
|
||||
youtube?: string;
|
||||
generateImage?: string;
|
||||
editImage?: string;
|
||||
generateVideo?: string;
|
||||
outputPath?: string;
|
||||
showThoughts?: boolean;
|
||||
aspectRatio?: string;
|
||||
/**
|
||||
* One or more local image paths to upload as persistent reference images.
|
||||
* - If `keepSession` is enabled, they are uploaded once per executor session.
|
||||
* - Otherwise, they are attached to each request.
|
||||
*/
|
||||
referenceImages?: string | string[];
|
||||
/** Preserve Gemini chat metadata to continue multi-turn conversations within the same executor instance. */
|
||||
keepSession?: boolean;
|
||||
}
|
||||
|
||||
export interface GeminiWebResponse {
|
||||
|
||||
@@ -481,52 +481,78 @@ export async function publishArticle(options: ArticleOptions): Promise<void> {
|
||||
const img = sortedImages[i]!;
|
||||
console.log(`[x-article] [${i + 1}/${sortedImages.length}] Inserting image at placeholder: ${img.placeholder}`);
|
||||
|
||||
// Find, scroll to, and select the placeholder text in DraftEditor
|
||||
const placeholderFound = await cdp.send<{ result: { value: boolean } }>('Runtime.evaluate', {
|
||||
expression: `(() => {
|
||||
const editor = document.querySelector('.DraftEditor-editorContainer [data-contents="true"]');
|
||||
if (!editor) return false;
|
||||
// Helper to select placeholder with retry
|
||||
const selectPlaceholder = async (maxRetries = 3): Promise<boolean> => {
|
||||
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
||||
// Find, scroll to, and select the placeholder text in DraftEditor
|
||||
await cdp!.send('Runtime.evaluate', {
|
||||
expression: `(() => {
|
||||
const editor = document.querySelector('.DraftEditor-editorContainer [data-contents="true"]');
|
||||
if (!editor) return false;
|
||||
|
||||
const placeholder = ${JSON.stringify(img.placeholder)};
|
||||
const placeholder = ${JSON.stringify(img.placeholder)};
|
||||
|
||||
// Search through all text nodes in the editor
|
||||
const walker = document.createTreeWalker(editor, NodeFilter.SHOW_TEXT, null, false);
|
||||
let node;
|
||||
// Search through all text nodes in the editor
|
||||
const walker = document.createTreeWalker(editor, NodeFilter.SHOW_TEXT, null, false);
|
||||
let node;
|
||||
|
||||
while ((node = walker.nextNode())) {
|
||||
const text = node.textContent || '';
|
||||
const idx = text.indexOf(placeholder);
|
||||
if (idx !== -1) {
|
||||
// Found the placeholder - scroll to it first
|
||||
const parentElement = node.parentElement;
|
||||
if (parentElement) {
|
||||
parentElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
while ((node = walker.nextNode())) {
|
||||
const text = node.textContent || '';
|
||||
const idx = text.indexOf(placeholder);
|
||||
if (idx !== -1) {
|
||||
// Found the placeholder - scroll to it first
|
||||
const parentElement = node.parentElement;
|
||||
if (parentElement) {
|
||||
parentElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
}
|
||||
|
||||
// Select it
|
||||
const range = document.createRange();
|
||||
range.setStart(node, idx);
|
||||
range.setEnd(node, idx + placeholder.length);
|
||||
const sel = window.getSelection();
|
||||
sel.removeAllRanges();
|
||||
sel.addRange(range);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
})()`,
|
||||
}, { sessionId });
|
||||
|
||||
// Select it
|
||||
const range = document.createRange();
|
||||
range.setStart(node, idx);
|
||||
range.setEnd(node, idx + placeholder.length);
|
||||
const sel = window.getSelection();
|
||||
sel.removeAllRanges();
|
||||
sel.addRange(range);
|
||||
return true;
|
||||
}
|
||||
// Wait for scroll and selection to settle
|
||||
await sleep(800);
|
||||
|
||||
// Verify selection matches the placeholder
|
||||
const selectionCheck = await cdp!.send<{ result: { value: string } }>('Runtime.evaluate', {
|
||||
expression: `window.getSelection()?.toString() || ''`,
|
||||
returnByValue: true,
|
||||
}, { sessionId });
|
||||
|
||||
const selectedText = selectionCheck.result.value.trim();
|
||||
if (selectedText === img.placeholder) {
|
||||
console.log(`[x-article] Selection verified: "${selectedText}"`);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
})()`,
|
||||
returnByValue: true,
|
||||
}, { sessionId });
|
||||
|
||||
// Wait for scroll animation
|
||||
await sleep(500);
|
||||
if (attempt < maxRetries) {
|
||||
console.log(`[x-article] Selection attempt ${attempt} got "${selectedText}", retrying...`);
|
||||
await sleep(500);
|
||||
} else {
|
||||
console.warn(`[x-article] Selection failed after ${maxRetries} attempts, got: "${selectedText}"`);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (!placeholderFound.result.value) {
|
||||
console.warn(`[x-article] Placeholder not found in DOM: ${img.placeholder}`);
|
||||
// Try to select the placeholder
|
||||
const selected = await selectPlaceholder(3);
|
||||
if (!selected) {
|
||||
console.warn(`[x-article] Skipping image - could not select placeholder: ${img.placeholder}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
console.log(`[x-article] Placeholder selected, copying image: ${path.basename(img.localPath)}`);
|
||||
console.log(`[x-article] Copying image: ${path.basename(img.localPath)}`);
|
||||
|
||||
// Copy image to clipboard
|
||||
if (!copyImageToClipboard(img.localPath)) {
|
||||
@@ -535,17 +561,48 @@ export async function publishArticle(options: ArticleOptions): Promise<void> {
|
||||
}
|
||||
|
||||
// Wait for clipboard to be fully ready
|
||||
await sleep(800);
|
||||
await sleep(1000);
|
||||
|
||||
// Delete placeholder by pressing Enter (placeholder is already selected)
|
||||
console.log(`[x-article] Deleting placeholder with Enter...`);
|
||||
await cdp.send('Input.dispatchKeyEvent', { type: 'keyDown', key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13 }, { sessionId });
|
||||
await cdp.send('Input.dispatchKeyEvent', { type: 'keyUp', key: 'Enter', code: 'Enter', windowsVirtualKeyCode: 13 }, { sessionId });
|
||||
// Delete placeholder by pressing Backspace (more reliable than Enter for replacing selection)
|
||||
console.log(`[x-article] Deleting placeholder...`);
|
||||
await cdp.send('Input.dispatchKeyEvent', { type: 'keyDown', key: 'Backspace', code: 'Backspace', windowsVirtualKeyCode: 8 }, { sessionId });
|
||||
await cdp.send('Input.dispatchKeyEvent', { type: 'keyUp', key: 'Backspace', code: 'Backspace', windowsVirtualKeyCode: 8 }, { sessionId });
|
||||
|
||||
// Wait and verify placeholder is deleted
|
||||
await sleep(500);
|
||||
|
||||
// Check that placeholder is no longer in editor
|
||||
const afterDelete = await cdp.send<{ result: { value: boolean } }>('Runtime.evaluate', {
|
||||
expression: `(() => {
|
||||
const editor = document.querySelector('.DraftEditor-editorContainer [data-contents="true"]');
|
||||
if (!editor) return true;
|
||||
return !editor.innerText.includes(${JSON.stringify(img.placeholder)});
|
||||
})()`,
|
||||
returnByValue: true,
|
||||
}, { sessionId });
|
||||
|
||||
if (!afterDelete.result.value) {
|
||||
console.warn(`[x-article] Placeholder may not have been deleted, trying again...`);
|
||||
// Try selecting and deleting again
|
||||
await selectPlaceholder(1);
|
||||
await sleep(300);
|
||||
await cdp.send('Input.dispatchKeyEvent', { type: 'keyDown', key: 'Backspace', code: 'Backspace', windowsVirtualKeyCode: 8 }, { sessionId });
|
||||
await cdp.send('Input.dispatchKeyEvent', { type: 'keyUp', key: 'Backspace', code: 'Backspace', windowsVirtualKeyCode: 8 }, { sessionId });
|
||||
await sleep(500);
|
||||
}
|
||||
|
||||
// Focus editor to ensure cursor is in position
|
||||
await cdp.send('Runtime.evaluate', {
|
||||
expression: `(() => {
|
||||
const editor = document.querySelector('.DraftEditor-editorContainer [contenteditable="true"]');
|
||||
if (editor) editor.focus();
|
||||
})()`,
|
||||
}, { sessionId });
|
||||
await sleep(300);
|
||||
|
||||
// Paste image using paste script (activates Chrome, sends real keystroke)
|
||||
console.log(`[x-article] Pasting image...`);
|
||||
if (pasteFromClipboard('Google Chrome', 5, 800)) {
|
||||
if (pasteFromClipboard('Google Chrome', 5, 1000)) {
|
||||
console.log(`[x-article] Image pasted: ${path.basename(img.localPath)}`);
|
||||
} else {
|
||||
console.warn(`[x-article] Failed to paste image after retries`);
|
||||
|
||||
+275
-317
@@ -5,177 +5,168 @@ description: Generate professional slide deck images from content. Creates compr
|
||||
|
||||
# Slide Deck Generator
|
||||
|
||||
Transform content into professional slide deck with comprehensive outlines and generated slide images.
|
||||
Transform content into professional slide deck images with flexible style options.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
# From markdown file
|
||||
/baoyu-slide-deck path/to/article.md
|
||||
# Auto-select style based on content
|
||||
/baoyu-slide-deck path/to/content.md
|
||||
|
||||
# With style preference
|
||||
/baoyu-slide-deck path/to/article.md --style corporate
|
||||
/baoyu-slide-deck path/to/article.md --style playful
|
||||
/baoyu-slide-deck path/to/article.md --style technical
|
||||
# Specify a style
|
||||
/baoyu-slide-deck path/to/content.md --style sketch-notes
|
||||
/baoyu-slide-deck path/to/content.md --style minimal
|
||||
|
||||
# With audience specification
|
||||
/baoyu-slide-deck path/to/article.md --audience beginners
|
||||
/baoyu-slide-deck path/to/article.md --audience executives
|
||||
# Target specific audience
|
||||
/baoyu-slide-deck path/to/content.md --audience executives
|
||||
|
||||
# With language
|
||||
/baoyu-slide-deck path/to/article.md --lang zh
|
||||
/baoyu-slide-deck path/to/article.md --lang en
|
||||
# Set output language
|
||||
/baoyu-slide-deck path/to/content.md --lang zh
|
||||
|
||||
# Outline only (no image generation)
|
||||
/baoyu-slide-deck path/to/article.md --outline-only
|
||||
# Limit slide count
|
||||
/baoyu-slide-deck path/to/content.md --slides 10
|
||||
|
||||
# Generate outline only (skip image generation)
|
||||
/baoyu-slide-deck path/to/content.md --outline-only
|
||||
|
||||
# Direct content input
|
||||
/baoyu-slide-deck
|
||||
[paste content]
|
||||
|
||||
# Combine options
|
||||
/baoyu-slide-deck path/to/content.md --style storytelling --audience experts --slides 15
|
||||
```
|
||||
|
||||
## Script Directory
|
||||
|
||||
**Important**: All scripts are located in the `scripts/` subdirectory of this skill.
|
||||
|
||||
**Agent Execution Instructions**:
|
||||
1. Determine this SKILL.md file's directory path as `SKILL_DIR`
|
||||
2. Script path = `${SKILL_DIR}/scripts/<script-name>.ts`
|
||||
3. Replace all `${SKILL_DIR}` in this document with the actual path
|
||||
|
||||
**Script Reference**:
|
||||
| Script | Purpose |
|
||||
|--------|---------|
|
||||
| `scripts/merge-to-pptx.ts` | Merge slides into PowerPoint |
|
||||
| `scripts/merge-to-pdf.ts` | Merge slides into PDF |
|
||||
|
||||
## Options
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--style <name>` | Visual style preset (see Style Gallery) |
|
||||
| `--audience <type>` | Target audience level |
|
||||
| `--lang <code>` | Output language (en, zh, etc.) |
|
||||
| `--slides <number>` | Target slide count (max 20) |
|
||||
| `--style <name>` | Visual style (see Style Gallery) |
|
||||
| `--audience <type>` | Target audience: beginners, intermediate, experts, executives, general |
|
||||
| `--lang <code>` | Output language for prompts and slides (en, zh, ja, etc.) |
|
||||
| `--slides <number>` | Target slide count |
|
||||
| `--outline-only` | Generate outline only, skip image generation |
|
||||
|
||||
## Style Gallery
|
||||
|
||||
### 1. `editorial` (Default)
|
||||
Clean, sophisticated, minimalist
|
||||
- **Aesthetic**: High-end journal, architectural blueprints
|
||||
- **Colors**: Off-white background (#F8F7F5), dark slate text (#2F3542), blue accents (#007AFF)
|
||||
- **Best for**: Thought leadership, research presentations
|
||||
| Style | Description | Best For |
|
||||
|-------|-------------|----------|
|
||||
| `sketch-notes` | Hand-drawn sketch notes, warm & friendly | Educational, tutorials, knowledge sharing |
|
||||
| `blueprint` | Technical blueprint, precise & analytical | Architecture, system design, data analysis |
|
||||
| `bold-editorial` | Magazine editorial, high-impact & dynamic | Product launches, marketing, keynotes |
|
||||
| `vector-illustration` | Flat vector with black outlines, retro & cute | Creative proposals, children's content, brand showcases |
|
||||
| `minimal` | Ultra-clean, maximum whitespace | Executive briefings, keynotes, premium brands |
|
||||
| `storytelling` | Cinematic, full-bleed visuals | Narratives, case studies, emotional impact |
|
||||
| `warm` | Soft gradients, wellness aesthetic | Lifestyle, wellness, personal development |
|
||||
| `notion` (Default) | SaaS dashboard, clean data focus | Product demos, SaaS, productivity tools |
|
||||
| `corporate` | Navy/gold, professional business | Investor decks, client proposals, quarterly reports |
|
||||
| `playful` | Vibrant colors, dynamic rounded shapes | Workshops, training, creative pitches |
|
||||
|
||||
### 2. `corporate`
|
||||
Professional, trustworthy, polished
|
||||
- **Aesthetic**: Clean lines, structured layouts, business-appropriate
|
||||
- **Colors**: Navy (#1E3A5F), white, gold accents (#C9A227)
|
||||
- **Best for**: Business presentations, investor decks, reports
|
||||
Detailed style definitions: `references/styles/<style>.md`
|
||||
|
||||
### 3. `technical`
|
||||
Precise, data-driven, analytical
|
||||
- **Aesthetic**: Blueprint style, schematic diagrams, grid layouts
|
||||
- **Colors**: Dark charcoal (#1A1A2E), cyan accents (#00D4FF), light gray text (#E8E8E8)
|
||||
- **Best for**: Technical documentation, engineering presentations
|
||||
## Auto Style Selection
|
||||
|
||||
### 4. `playful`
|
||||
Bold, energetic, engaging
|
||||
- **Aesthetic**: Dynamic shapes, vibrant colors, creative layouts
|
||||
- **Colors**: Warm white (#FFFDF7), deep purple (#4A1D96), coral (#FF6B6B)
|
||||
- **Best for**: Creative pitches, educational content, workshops
|
||||
| Content Signals | Selected Style |
|
||||
|-----------------|----------------|
|
||||
| tutorial, learn, education, guide, intro, beginner | `sketch-notes` |
|
||||
| architecture, system, data, analysis, technical, engineering | `blueprint` |
|
||||
| launch, marketing, brand, keynote, impact, showcase | `bold-editorial` |
|
||||
| creative, children, kids, cute, illustration, retro | `vector-illustration` |
|
||||
| executive, minimal, clean, simple, elegant | `minimal` |
|
||||
| story, journey, case study, narrative, emotional | `storytelling` |
|
||||
| wellness, lifestyle, personal, growth, mindfulness | `warm` |
|
||||
| saas, product, dashboard, metrics, productivity | `notion` |
|
||||
| investor, quarterly, business, corporate, proposal, client | `corporate` |
|
||||
| workshop, training, fun, playful, energetic, team | `playful` |
|
||||
| Default | `notion` |
|
||||
|
||||
### 5. `minimal`
|
||||
Ultra-clean, zen-like, focused
|
||||
- **Aesthetic**: Maximum whitespace, single focal points, elegant typography
|
||||
- **Colors**: Black, white, single accent color
|
||||
- **Best for**: Keynotes, philosophical content, product launches
|
||||
## Design Philosophy
|
||||
|
||||
### 6. `storytelling`
|
||||
Narrative-driven, cinematic, immersive
|
||||
- **Aesthetic**: Full-bleed imagery, dramatic typography, chapter-like flow
|
||||
- **Colors**: Rich charcoal (#2D2D2D), warm white (#FAF9F6), gold (#D4AF37)
|
||||
- **Best for**: Case studies, journey narratives, brand stories
|
||||
|
||||
### 7. `warm`
|
||||
Cozy, healing, hand-drawn illustration style
|
||||
- **Aesthetic**: Soft hand-drawn illustrations, cozy and healing atmosphere, gentle curves, watercolor textures
|
||||
- **Colors**: Cream gradient background (#FFF8E7 → #FFE4C4), warm brown text (#5D4037), soft coral accents (#FF8A80)
|
||||
- **Best for**: Personal growth, wellness, emotional content, lifestyle topics
|
||||
|
||||
### 8. `retro-flat`
|
||||
Flat vector illustration with retro palette
|
||||
- **Aesthetic**: Flat vector with clear black outlines (monoline), geometric simplification, toy-model cuteness, NO gradients
|
||||
- **Colors**: Retro muted palette - dusty pink (#E8B4B8), sage green (#A8C686), mustard yellow (#E8B84A), off-white background (#F5F0E6)
|
||||
- **Best for**: Tutorials, explainers, product introductions, educational content
|
||||
|
||||
### 9. `notion`
|
||||
Minimalist hand-drawn line art, intellectual
|
||||
- **Aesthetic**: Simple line doodles with hand-drawn wobble, geometric shapes, maximum whitespace, SaaS product feel
|
||||
- **Colors**: Black outlines (#1A1A1A), white background (#FFFFFF), 1-2 pastel accents (blue #A8D4F0, yellow #F9E79F)
|
||||
- **Best for**: Knowledge sharing, concept explanations, productivity content, SaaS presentations
|
||||
|
||||
## Audience Presets
|
||||
|
||||
| Audience | Approach |
|
||||
|----------|----------|
|
||||
| `beginners` | Step-by-step, more context, simpler visuals |
|
||||
| `intermediate` | Balanced detail, some assumed knowledge |
|
||||
| `experts` | Dense information, technical depth, less hand-holding |
|
||||
| `executives` | High-level insights, key metrics, strategic focus |
|
||||
| `general` | Accessible language, broad appeal, clear takeaways |
|
||||
This deck is designed for **reading and sharing**, not live presentation:
|
||||
- Each slide must be **self-explanatory** without verbal commentary
|
||||
- Structure content for **logical flow** when scrolling
|
||||
- Include **all necessary context** within each slide
|
||||
- Optimize for **social media sharing** and offline reading
|
||||
|
||||
## File Management
|
||||
|
||||
### With Article Path
|
||||
### With Content Path
|
||||
|
||||
Save to `slide-deck/` subdirectory in the same folder as the content:
|
||||
|
||||
```
|
||||
path/to/
|
||||
├── article.md
|
||||
content-dir/
|
||||
├── source-content.md
|
||||
└── slide-deck/
|
||||
├── outline.md
|
||||
├── prompts/
|
||||
│ ├── 01-cover.md
|
||||
│ ├── 02-content-1.md
|
||||
│ ├── 01-slide-cover.md
|
||||
│ ├── 02-slide-{slug}.md
|
||||
│ └── ...
|
||||
├── 01-cover.png
|
||||
├── 02-content-1.png
|
||||
└── ...
|
||||
├── 01-slide-cover.png
|
||||
├── 02-slide-{slug}.png
|
||||
├── ...
|
||||
├── {topic-slug}.pptx
|
||||
└── {topic-slug}.pdf
|
||||
```
|
||||
|
||||
### Without Article Path
|
||||
### Without Content Path
|
||||
|
||||
Save to `slide-outputs/YYYY-MM-DD/[topic-slug]/`:
|
||||
|
||||
```
|
||||
./baoyu-slide-deck-outputs/YYYY-MM-DD/[topic-slug]/
|
||||
├── outline.md
|
||||
├── prompts/
|
||||
│ ├── 01-cover.md
|
||||
│ └── ...
|
||||
├── 01-cover.png
|
||||
└── ...
|
||||
slide-outputs/
|
||||
└── 2026-01-17/
|
||||
└── ai-future-trends/
|
||||
├── outline.md
|
||||
├── prompts/
|
||||
│ ├── 01-slide-cover.md
|
||||
│ └── ...
|
||||
├── 01-slide-cover.png
|
||||
├── ...
|
||||
├── ai-future-trends.pptx
|
||||
└── ai-future-trends.pdf
|
||||
```
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Analyze Content & Select Style
|
||||
### Step 1: Analyze Content & Determine Settings
|
||||
|
||||
1. Read source content
|
||||
2. If `--style` specified, use that style
|
||||
3. Otherwise, analyze content for style signals:
|
||||
1. Read source material
|
||||
2. **Style selection**:
|
||||
- If `--style` specified, use that style
|
||||
- Otherwise, scan for style signals and auto-select
|
||||
3. **Language detection**:
|
||||
- If `--lang` specified, use that language for all prompts and slide text
|
||||
- Otherwise, detect language from source material
|
||||
- If uncertain (mixed languages or unclear), ask user to confirm
|
||||
4. **Slide count**:
|
||||
- If `--slides` specified, use that count
|
||||
- Otherwise, dynamic based on content structure
|
||||
|
||||
| Content Signals | Selected Style |
|
||||
|----------------|----------------|
|
||||
| AI, coding, tech, digital, algorithm, data | `technical` |
|
||||
| Business, strategy, investment, corporate | `corporate` |
|
||||
| Personal story, journey, narrative, emotion | `storytelling` |
|
||||
| Simple, zen, focus, essential, one idea | `minimal` |
|
||||
| Fun, creative, workshop, educational | `playful` |
|
||||
| Research, analysis, thought leadership | `editorial` |
|
||||
| Wellness, healing, cozy, self-care, lifestyle, comfort | `warm` |
|
||||
| Tutorial, explainer, how-to, beginner, product, guide | `retro-flat` |
|
||||
| Knowledge, concept, productivity, SaaS, notion, intellectual | `notion` |
|
||||
### Step 2: Generate Outline with Style Instructions
|
||||
|
||||
4. Extract key information:
|
||||
- Core narrative and key messages
|
||||
- Important data points and statistics
|
||||
- Logical flow and structure
|
||||
- Target audience signals
|
||||
|
||||
### Step 2: Generate Outline
|
||||
|
||||
Create outline with `STYLE_INSTRUCTIONS` block and slide specifications.
|
||||
|
||||
**Outline Format**:
|
||||
Create outline with structured STYLE_INSTRUCTIONS block:
|
||||
|
||||
```markdown
|
||||
# Slide Deck Outline: [Topic]
|
||||
# Slide Deck Outline
|
||||
|
||||
**Source**: [source file or "Direct input"]
|
||||
**Topic**: [topic description]
|
||||
**Style**: [selected style]
|
||||
**Audience**: [target audience]
|
||||
**Language**: [output language]
|
||||
@@ -185,255 +176,222 @@ Create outline with `STYLE_INSTRUCTIONS` block and slide specifications.
|
||||
---
|
||||
|
||||
<STYLE_INSTRUCTIONS>
|
||||
Design Aesthetic: [Overall style description]
|
||||
Background Color: [Description and Hex Code]
|
||||
Primary Font: [Font name for Headlines]
|
||||
Secondary Font: [Font name for Body copy]
|
||||
Design Aesthetic: [2-3 sentence description from style file]
|
||||
|
||||
Background:
|
||||
Color: [Name] ([Hex])
|
||||
Texture: [description]
|
||||
|
||||
Typography:
|
||||
Primary Font: [detailed description for image generation]
|
||||
Secondary Font: [detailed description for image generation]
|
||||
|
||||
Color Palette:
|
||||
Primary Text Color: [Hex Code]
|
||||
Primary Accent Color: [Hex Code]
|
||||
Visual Elements: [Lines, shapes, imagery style, etc.]
|
||||
Primary Text: [Name] ([Hex]) - [usage]
|
||||
Background: [Name] ([Hex]) - [usage]
|
||||
Accent 1: [Name] ([Hex]) - [usage]
|
||||
Accent 2: [Name] ([Hex]) - [usage]
|
||||
|
||||
Visual Elements:
|
||||
- [element 1 with rendering guidance]
|
||||
- [element 2 with rendering guidance]
|
||||
- ...
|
||||
|
||||
Style Rules:
|
||||
Do: [guidelines from style file]
|
||||
Don't: [anti-patterns from style file]
|
||||
</STYLE_INSTRUCTIONS>
|
||||
|
||||
---
|
||||
|
||||
## Slide 1: [Descriptive Title]
|
||||
## Slide 1 of N
|
||||
|
||||
**Position**: Cover
|
||||
**Filename**: 01-cover.png
|
||||
**Type**: Cover
|
||||
**Filename**: 01-slide-cover.png
|
||||
|
||||
// NARRATIVE GOAL
|
||||
[Storytelling purpose within the overall arc]
|
||||
[What this slide achieves in the story arc]
|
||||
|
||||
// KEY CONTENT
|
||||
Headline: [Main message - narrative, not "Title: Subtitle" format]
|
||||
Sub-headline: [Supporting context]
|
||||
Body:
|
||||
- [Key point 1 with specific data from source]
|
||||
- [Key point 2 with specific data from source]
|
||||
Headline: [main title]
|
||||
Sub-headline: [supporting tagline]
|
||||
|
||||
// VISUAL
|
||||
[Detailed description of imagery, charts, graphics, or abstract visuals]
|
||||
[Detailed visual description - specific elements, composition, mood]
|
||||
|
||||
// LAYOUT
|
||||
[Composition, hierarchy, spatial arrangement, focus points]
|
||||
[Composition, hierarchy, spatial arrangement]
|
||||
|
||||
---
|
||||
|
||||
## Slide 2: [First Content]
|
||||
## Slide 2 of N
|
||||
|
||||
**Type**: Content
|
||||
**Filename**: 02-slide-{slug}.png
|
||||
|
||||
// NARRATIVE GOAL
|
||||
[What this slide achieves in the story arc]
|
||||
|
||||
// KEY CONTENT
|
||||
Headline: [main message - narrative, not label]
|
||||
Sub-headline: [supporting context]
|
||||
Body:
|
||||
- [point 1 with specific detail]
|
||||
- [point 2 with specific detail]
|
||||
- [point 3 with specific detail]
|
||||
|
||||
// VISUAL
|
||||
[Detailed visual description]
|
||||
|
||||
// LAYOUT
|
||||
[Composition, hierarchy, spatial arrangement]
|
||||
|
||||
---
|
||||
...
|
||||
|
||||
## Slide N: [Back Cover]
|
||||
...
|
||||
## Slide N of N
|
||||
|
||||
**Type**: Back Cover
|
||||
**Filename**: {NN}-slide-back-cover.png
|
||||
|
||||
// NARRATIVE GOAL
|
||||
[Meaningful closing - not just "thank you"]
|
||||
|
||||
// KEY CONTENT
|
||||
Headline: [memorable closing statement or call-to-action]
|
||||
Body: [optional summary points or next steps]
|
||||
|
||||
// VISUAL
|
||||
[Visual that reinforces the core message]
|
||||
|
||||
// LAYOUT
|
||||
[Clean, impactful composition]
|
||||
```
|
||||
|
||||
**Required Slide Structure**:
|
||||
1. **Slide 1**: Cover Slide (poster-style, heroic typography)
|
||||
2. **Slides 2-N-1**: Content slides (consistent internal style)
|
||||
3. **Slide N**: Back Cover (closing statement, not "Thank You")
|
||||
|
||||
### Step 3: Save Outline
|
||||
|
||||
Save outline as `outline.md` in target directory.
|
||||
Save outline as `outline.md` in the output directory.
|
||||
|
||||
If `--outline-only` flag is set, stop here.
|
||||
If `--outline-only` is specified, stop here.
|
||||
|
||||
### Step 4: Create Prompt Files
|
||||
### Step 4: Generate Prompts
|
||||
|
||||
For each slide, create a style-specific prompt file.
|
||||
Create prompt file per slide in `prompts/` directory:
|
||||
|
||||
**Prompt Format**:
|
||||
|
||||
```markdown
|
||||
Slide theme: [slide title]
|
||||
Style: [style name]
|
||||
Position: [cover/content/back-cover]
|
||||
|
||||
Visual composition:
|
||||
- Main visual: [style-appropriate description from VISUAL section]
|
||||
- Layout: [from LAYOUT section]
|
||||
- Decorative elements: [style-specific decorations]
|
||||
|
||||
Color scheme:
|
||||
- Background: [style background color]
|
||||
- Primary text: [style text color]
|
||||
- Accent: [style accent color]
|
||||
|
||||
Text content:
|
||||
- Headline: [headline text]
|
||||
- Sub-headline: [sub-headline if any]
|
||||
- Body points: [bullet points if any]
|
||||
|
||||
Style notes: [specific style characteristics to emphasize]
|
||||
```
|
||||
1. Read `references/base-prompt.md`
|
||||
2. Combine with style-specific instructions from outline
|
||||
3. Add slide-specific content from outline
|
||||
4. Save as `01-slide-cover.md`, `02-slide-{slug}.md`, etc.
|
||||
|
||||
### Step 5: Generate Images
|
||||
|
||||
For each slide, generate using:
|
||||
**Image Generation Skill Selection**:
|
||||
1. Check available image generation skills
|
||||
2. If multiple skills available, ask user to choose
|
||||
|
||||
**Session Management**:
|
||||
If the image generation skill supports `--sessionId`:
|
||||
1. Generate a unique session ID at the start (e.g., `slides-{topic-slug}-{timestamp}`)
|
||||
2. Use the same session ID for all slides in the series
|
||||
3. This ensures style consistency across all generated slides
|
||||
|
||||
**Generation Flow**:
|
||||
1. Call selected image generation skill with prompt file, output path, and session ID
|
||||
2. Confirm generation success
|
||||
3. Report progress: "Generated X/N"
|
||||
4. Continue to next
|
||||
|
||||
### Step 6: Merge to PPTX and PDF
|
||||
|
||||
After all images are generated, merge them into PowerPoint and PDF files:
|
||||
|
||||
```bash
|
||||
/baoyu-gemini-web --promptfiles [SKILL_ROOT]/skills/baoyu-slide-deck/prompts/system.md [TARGET_DIR]/prompts/01-cover.md --image [TARGET_DIR]/01-cover.png
|
||||
npx -y bun ${SKILL_DIR}/scripts/merge-to-pptx.ts <slide-deck-dir>
|
||||
npx -y bun ${SKILL_DIR}/scripts/merge-to-pdf.ts <slide-deck-dir>
|
||||
```
|
||||
|
||||
Generation flow:
|
||||
1. Generate images sequentially
|
||||
2. After each image, output progress: "Generated X/N"
|
||||
3. On failure, auto-retry once
|
||||
4. If retry fails, log reason, continue to next
|
||||
This creates:
|
||||
- `{topic-slug}.pptx` - PowerPoint with all images as full-bleed 16:9 slides and prompt content as speaker notes
|
||||
- `{topic-slug}.pdf` - PDF with all images as full-page slides
|
||||
|
||||
### Step 6: Completion Report
|
||||
### Step 7: Output Summary
|
||||
|
||||
```
|
||||
Slide Deck Generated!
|
||||
Slide Deck Complete!
|
||||
|
||||
Topic: [topic]
|
||||
Style: [style name]
|
||||
Audience: [audience]
|
||||
Audience: [audience type]
|
||||
Location: [directory path]
|
||||
Slides: N total
|
||||
|
||||
- 01-cover.png ✓ Cover
|
||||
- 02-content-1.png ✓ Content
|
||||
- 03-content-2.png ✓ Content
|
||||
- 01-slide-cover.png ✓ Cover
|
||||
- 02-slide-intro.png ✓ Content
|
||||
- 03-slide-main-point.png ✓ Content
|
||||
- ...
|
||||
- 0N-back-cover.png ✓ Back Cover
|
||||
- {NN}-slide-back-cover.png ✓ Back Cover
|
||||
|
||||
Outline: outline.md
|
||||
|
||||
[If any failures]
|
||||
Failed:
|
||||
- 0X-slide-name.png: [failure reason]
|
||||
PPTX: {topic-slug}.pptx
|
||||
PDF: {topic-slug}.pdf
|
||||
```
|
||||
|
||||
## Content Rules
|
||||
|
||||
1. **Respect reader attention** -
|
||||
2. **Data traceability** - All statistics must include source attribution
|
||||
3. **Self-contained prompts** - Every detail in the image prompt, no external references
|
||||
4. **No placeholders** - Every element must be fully specified
|
||||
|
||||
## Style Rules
|
||||
|
||||
1. **Narrative headlines** - Headlines tell the story, not label the content
|
||||
- Bad: "Key Statistics"
|
||||
- Good: "Usage doubled in 6 months"
|
||||
|
||||
2. **Avoid AI clichés** - No "dive into", "explore", "journey", "let's"
|
||||
|
||||
3. **Meaningful back cover** - Not just "Thank you"
|
||||
- Include call-to-action, key takeaway, or memorable closing
|
||||
|
||||
4. **Consistent visual language** - Same icons, colors, layouts throughout
|
||||
|
||||
## Slide Structure
|
||||
|
||||
1. **Cover (Slide 1)**: Title, visual hook, topic introduction
|
||||
2. **Content (Middle)**: Key points, data, explanations - dynamic count based on content
|
||||
3. **Back Cover (Final)**: Summary, call-to-action, or memorable closing
|
||||
|
||||
## Key Specifications
|
||||
|
||||
- **Aspect Ratio**: 16:9 (landscape)
|
||||
- **Slide Count**: Dynamic based on content
|
||||
- **Required Slides**: Cover + Back Cover minimum
|
||||
- **No slide numbers, footers, or logos**
|
||||
- **Language**: Priority order: `--lang` option → source material language → ask user if uncertain
|
||||
- **Tone**: Direct, confident language (avoid AI-sounding phrases)
|
||||
|
||||
## Style Reference Details
|
||||
|
||||
### editorial
|
||||
```
|
||||
Design Aesthetic: Clean, sophisticated, minimalist editorial inspired by architectural blueprints and high-end technical journals
|
||||
Background Color: Subtle textured off-white #F8F7F5
|
||||
Primary Font: Neue Haas Grotesk Display Pro (bold headlines)
|
||||
Secondary Font: Tiempos Text (body copy, annotations)
|
||||
Primary Text Color: Dark slate grey #2F3542
|
||||
Primary Accent Color: Intelligent blue #007AFF
|
||||
Visual Elements: Thin precise line work, schematic diagrams, clean vectors, spacious layouts
|
||||
```
|
||||
| Style | Description |
|
||||
|-------|-------------|
|
||||
| `sketch-notes` | Hand-drawn feel, soft brush strokes, warm off-white background, conceptual icons |
|
||||
| `blueprint` | Technical schematics, grid texture, precise lines, engineering blue tones |
|
||||
| `bold-editorial` | High contrast, bold typography, dark backgrounds, magazine-level impact |
|
||||
| `vector-illustration` | Flat vector, black outlines, retro colors, toy model aesthetic |
|
||||
| `minimal` | Maximum whitespace, single accent color, clean sans-serif, zen-like |
|
||||
| `storytelling` | Full-bleed imagery, cinematic compositions, emotional photography |
|
||||
| `warm` | Soft gradients, rounded shapes, wellness palette, approachable |
|
||||
| `notion` | Dashboard aesthetic, clean data viz, SaaS-inspired, productivity focus |
|
||||
| `corporate` | Navy/gold palette, structured layouts, professional iconography, business polish |
|
||||
| `playful` | Vibrant coral/teal/yellow, rounded shapes, dynamic layouts, energetic |
|
||||
|
||||
### corporate
|
||||
```
|
||||
Design Aesthetic: Professional, trustworthy, structured business presentation
|
||||
Background Color: Clean white #FFFFFF with navy accents
|
||||
Primary Font: Inter (headlines)
|
||||
Secondary Font: Source Sans Pro (body)
|
||||
Primary Text Color: Navy #1E3A5F
|
||||
Primary Accent Color: Gold #C9A227
|
||||
Visual Elements: Clean charts, professional icons, structured grids, subtle shadows
|
||||
```
|
||||
|
||||
### technical
|
||||
```
|
||||
Design Aesthetic: Blueprint-style, precise, data-driven analytical presentation
|
||||
Background Color: Dark charcoal #1A1A2E
|
||||
Primary Font: JetBrains Mono (headlines)
|
||||
Secondary Font: IBM Plex Sans (body)
|
||||
Primary Text Color: Light gray #E8E8E8
|
||||
Primary Accent Color: Cyan #00D4FF
|
||||
Visual Elements: Grid overlays, circuit patterns, data visualizations, monospace code blocks
|
||||
```
|
||||
|
||||
### playful
|
||||
```
|
||||
Design Aesthetic: Bold, energetic, creative with dynamic visual interest
|
||||
Background Color: Warm white #FFFDF7
|
||||
Primary Font: Poppins (headlines)
|
||||
Secondary Font: Nunito (body)
|
||||
Primary Text Color: Deep purple #4A1D96
|
||||
Primary Accent Color: Vibrant coral #FF6B6B
|
||||
Visual Elements: Rounded shapes, gradients, illustrations, dynamic compositions, bright pops
|
||||
```
|
||||
|
||||
### minimal
|
||||
```
|
||||
Design Aesthetic: Ultra-clean, zen-like focus with elegant restraint
|
||||
Background Color: Pure white #FFFFFF
|
||||
Primary Font: Helvetica Neue (headlines)
|
||||
Secondary Font: Garamond (body)
|
||||
Primary Text Color: Pure black #000000
|
||||
Primary Accent Color: Single accent (content-derived)
|
||||
Visual Elements: Maximum whitespace, single focal points, hairline rules, elegant typography
|
||||
```
|
||||
|
||||
### storytelling
|
||||
```
|
||||
Design Aesthetic: Cinematic, narrative-driven with immersive visual flow
|
||||
Background Color: Rich charcoal #2D2D2D or full-bleed imagery
|
||||
Primary Font: Playfair Display (headlines)
|
||||
Secondary Font: Lora (body)
|
||||
Primary Text Color: Warm white #FAF9F6
|
||||
Primary Accent Color: Warm gold #D4AF37
|
||||
Visual Elements: Full-bleed photos, dramatic typography, chapter markers, emotional imagery
|
||||
```
|
||||
|
||||
### warm
|
||||
```
|
||||
Design Aesthetic: Cozy healing hand-drawn illustration style, soft sketch lines, warm and comforting atmosphere
|
||||
Background Color: Cream gradient #FFF8E7 → #FFE4C4
|
||||
Primary Font: Rounded hand-drawn style lettering
|
||||
Secondary Font: Soft serif hand lettering
|
||||
Primary Text Color: Warm brown #5D4037
|
||||
Primary Accent Color: Soft coral #FF8A80, Peachy pink #FFAB91
|
||||
Visual Elements: Soft watercolor textures, gentle curves, cozy illustrations, warm lighting, hearts and stars, plant motifs, cute characters
|
||||
```
|
||||
|
||||
### retro-flat
|
||||
```
|
||||
Design Aesthetic: Flat vector illustration with clear uniform-width black outlines, geometric simplification, toy-model cuteness
|
||||
Background Color: Off-white #F5F0E6, soft cream
|
||||
Primary Font: Bold geometric sans-serif with black outline
|
||||
Secondary Font: Clean sans-serif
|
||||
Primary Text Color: Black #000000 (clean outlines)
|
||||
Primary Accent Color: Retro muted palette - Dusty pink #E8B4B8, Sage green #A8C686, Mustard yellow #E8B84A, Muted blue #7BA7BC
|
||||
Visual Elements: Clear black monoline outlines (uniform width), flat color fills with NO gradients, geometric simplified shapes, toy-like proportions, minimal shadows, vintage badge style, halftone dots optional
|
||||
Style Rules: MUST use clear black outlines on all elements, NO 3D effects, NO gradients, simple flat color blocks only
|
||||
```
|
||||
|
||||
### notion
|
||||
```
|
||||
Design Aesthetic: Minimalist hand-drawn line art with intellectual SaaS product feel, Notion-style doodles
|
||||
Background Color: Pure white #FFFFFF, off-white #FAFAFA
|
||||
Primary Font: Clean hand-drawn lettering, simple sans-serif
|
||||
Secondary Font: Simple sans-serif labels
|
||||
Primary Text Color: Black #1A1A1A, dark gray #4A4A4A
|
||||
Primary Accent Color: Pastel blue #A8D4F0, Pastel yellow #F9E79F, Pastel pink #FADBD8
|
||||
Visual Elements: Simple line doodles with hand-drawn wobble effect, geometric shapes, stick figures, maximum whitespace, single-weight ink lines
|
||||
Style Rules: Single color lines (black/dark gray), 1-2 pastel accents only, NO complex gradients, NO heavy shadows, imperfect hand-drawn feel
|
||||
```
|
||||
Full style specifications: `references/styles/<style>.md`
|
||||
|
||||
## Notes
|
||||
|
||||
### Design Philosophy
|
||||
- Deck is designed for **reading and sharing**, not live presentation
|
||||
- Structure should be self-explanatory without a presenter
|
||||
- Include enough context for visuals to be understood standalone
|
||||
- Err on the side of audience having **more expertise** than expected
|
||||
|
||||
### Content Rules
|
||||
- Maximum 20 slides per deck
|
||||
- Every data point must trace to source material
|
||||
- All details in prompts - image generator has no access to source
|
||||
|
||||
### Style Rules
|
||||
- Avoid AI-generated clichés ("It wasn't just X, it was Y")
|
||||
- Use narrative headlines, not "Title: Subtitle" format
|
||||
- Cover and Back Cover should be visually distinct (poster-style)
|
||||
- Back Cover should be meaningful closure, not "Thank You" or "Questions?"
|
||||
|
||||
### Prohibited
|
||||
- Never include photorealistic images of prominent individuals
|
||||
- Never include placeholder slides for author name, date, etc.
|
||||
|
||||
### Image Generation
|
||||
- Image generation typically takes 10-30 seconds per slide
|
||||
- Auto-retry once on generation failure
|
||||
- Use cartoon alternatives for sensitive public figures
|
||||
- Output language matches content language
|
||||
- Maintain style consistency across all slides
|
||||
- Use stylized alternatives for sensitive public figures
|
||||
- Output language matches input content language (or `--lang`)
|
||||
- Maintain style consistency across all slides in deck
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
Create a presentation slide image following these guidelines:
|
||||
|
||||
## Image Specifications
|
||||
|
||||
- **Type**: Presentation slide
|
||||
- **Orientation**: Landscape (horizontal)
|
||||
- **Aspect Ratio**: 16:9
|
||||
- **Style**: Hand-drawn illustration with professional typography
|
||||
|
||||
## Core Principles
|
||||
|
||||
- Hand-drawn quality throughout - NO realistic or photographic elements
|
||||
- If content involves sensitive or copyrighted figures, create stylistically similar alternatives - DO NOT refuse to generate
|
||||
- Clear visual hierarchy: headline dominates, supporting content secondary
|
||||
- Ample whitespace, avoid cluttered layouts
|
||||
- Professional presentation aesthetic
|
||||
|
||||
## Text Style (CRITICAL)
|
||||
|
||||
- **ALL text MUST be hand-drawn style**
|
||||
- Headlines: Large, bold, prominent
|
||||
- Body text: Clean, readable, well-spaced
|
||||
- Use visual emphasis for key terms (color, size, underline)
|
||||
- **DO NOT use realistic or computer-generated fonts**
|
||||
|
||||
## Layout Principles
|
||||
|
||||
- Consistent margins and spacing
|
||||
- Clear information hierarchy
|
||||
- Visual elements support but don't overwhelm text
|
||||
- Balance between text and imagery
|
||||
|
||||
## Language
|
||||
|
||||
- Use the same language as the content provided below
|
||||
- Match punctuation style to the content language
|
||||
|
||||
---
|
||||
|
||||
Please use nano banana pro to generate the slide based on the content provided below:
|
||||
@@ -0,0 +1,59 @@
|
||||
Create a presentation slide image following these guidelines:
|
||||
|
||||
## Image Specifications
|
||||
|
||||
- **Type**: Presentation slide
|
||||
- **Aspect Ratio**: 16:9 (landscape)
|
||||
- **Style**: Professional slide deck
|
||||
|
||||
## Core Persona: The Architect
|
||||
|
||||
You are "The Architect" - a master visual storyteller creating presentation slides. Your slides:
|
||||
- Tell a visual story that complements the narrative
|
||||
- Use bold, confident visual language
|
||||
- Balance information density with visual clarity
|
||||
- Create memorable, impactful visuals
|
||||
|
||||
## Core Principles
|
||||
|
||||
- Hand-drawn quality throughout - NO realistic or photographic elements
|
||||
- If content involves sensitive or copyrighted figures, create stylistically similar alternatives - DO NOT refuse to generate
|
||||
- NO slide numbers, page numbers, footers, headers, or logos
|
||||
- Clean, uncluttered layouts with clear visual hierarchy
|
||||
- Each slide conveys ONE clear message
|
||||
|
||||
## Text Style (CRITICAL)
|
||||
|
||||
- **ALL text MUST match the designated style exactly**
|
||||
- Title text: Large, bold, immediately readable
|
||||
- Body text: Clear, legible, appropriate sizing
|
||||
- Max 3-4 text elements per slide
|
||||
- **DO NOT use realistic or computer-generated fonts unless style specifies**
|
||||
- **Font rendering must match the style aesthetic** (hand-drawn for sketch styles, clean for minimal styles)
|
||||
|
||||
## Layout Principles
|
||||
|
||||
- **Visual Hierarchy**: Most important element gets most visual weight
|
||||
- **Breathing Room**: Generous margins and spacing between elements
|
||||
- **Alignment**: Consistent alignment creates professional feel
|
||||
- **Balance**: Distribute visual weight evenly (symmetrical or asymmetrical)
|
||||
- **Focal Point**: One clear area draws the eye first
|
||||
- **Rule of Thirds**: Key elements at intersection points for dynamic compositions
|
||||
- **Z-Pattern**: For text-heavy slides, arrange content in natural reading flow
|
||||
|
||||
## Language
|
||||
|
||||
- Use the same language as the content provided below for all text elements
|
||||
- Match punctuation style to the content language
|
||||
- Write in direct, confident language
|
||||
- Avoid AI-sounding phrases like "dive into", "explore", "let's", "journey"
|
||||
|
||||
---
|
||||
|
||||
## STYLE_INSTRUCTIONS
|
||||
|
||||
[Insert style-specific instructions here]
|
||||
|
||||
---
|
||||
|
||||
Please use nano banana pro to generate the slide image based on the content provided below:
|
||||
@@ -0,0 +1,67 @@
|
||||
# blueprint
|
||||
|
||||
Precise technical blueprint style with professional analytical visual presentation
|
||||
|
||||
## Design Aesthetic
|
||||
|
||||
Clean, structured visual metaphors using blueprints, diagrams, and schematics. Precise, analytical and aesthetically refined. Information presented in triptych or grid-based layouts with engineering precision.
|
||||
|
||||
## Background
|
||||
|
||||
- Color: Blueprint Off-White (#FAF8F5)
|
||||
- Texture: Subtle grid overlay, light engineering paper feel
|
||||
|
||||
## Typography
|
||||
|
||||
### Primary Font (Headlines)
|
||||
|
||||
Neue Haas Grotesk Display Pro or similar clean sans-serif. Bold weight for titles. Precise letterforms with consistent spacing. Technical, authoritative presence.
|
||||
|
||||
### Secondary Font (Body)
|
||||
|
||||
Tiempos Text or similar elegant serif for body explanations. Clean, readable at smaller sizes. Professional editorial quality.
|
||||
|
||||
## Color Palette
|
||||
|
||||
| Role | Color | Hex | Usage |
|
||||
|------|-------|-----|-------|
|
||||
| Background | Blueprint Paper | #FAF8F5 | Primary background |
|
||||
| Grid | Light Gray | #E5E5E5 | Background grid lines |
|
||||
| Primary Text | Deep Slate | #334155 | Headlines, body text |
|
||||
| Primary Accent | Engineering Blue | #2563EB | Key elements, highlights |
|
||||
| Secondary Accent | Navy Blue | #1E3A5F | Supporting elements |
|
||||
| Tertiary | Light Blue | #BFDBFE | Backgrounds, fills |
|
||||
| Warning | Amber | #F59E0B | Warnings, emphasis points |
|
||||
|
||||
## Visual Elements
|
||||
|
||||
- Precise lines with consistent stroke weights
|
||||
- Technical schematics and clean vector graphics
|
||||
- Thin line work in technical drawing style
|
||||
- Connection lines use straight lines or 90-degree angles only
|
||||
- Data visualization with clean, minimal charts
|
||||
- Dimension lines and measurement indicators
|
||||
- Cross-section style diagrams
|
||||
- Isometric or orthographic projections
|
||||
|
||||
## Style Rules
|
||||
|
||||
### Do
|
||||
|
||||
- Maintain consistent line weights throughout
|
||||
- Use grid alignment for all elements
|
||||
- Keep color palette restrained and unified
|
||||
- Create clear visual hierarchy through scale
|
||||
- Use geometric precision for all shapes
|
||||
|
||||
### Don't
|
||||
|
||||
- Use hand-drawn or organic shapes
|
||||
- Add decorative flourishes
|
||||
- Use curved connection lines
|
||||
- Include photographic elements
|
||||
- Add slide numbers, footers, or logos
|
||||
|
||||
## Best For
|
||||
|
||||
Technical architecture, system design, data analysis, professional business presentations, engineering documentation, process flows
|
||||
@@ -0,0 +1,69 @@
|
||||
# bold-editorial
|
||||
|
||||
High-impact magazine editorial style with bold visual expression
|
||||
|
||||
## Design Aesthetic
|
||||
|
||||
Strong visual impact at magazine cover level. Bold typography and dramatic contrast. Full-bleed imagery and large color blocks create commanding presence. Every slide feels like a premium publication cover.
|
||||
|
||||
## Background
|
||||
|
||||
- Color: Deep Black (#0A0A0A) primary, or Deep Blue (#0F172A) alternative
|
||||
- Texture: None - clean solid backgrounds, or pure white with bold color blocks
|
||||
|
||||
## Typography
|
||||
|
||||
### Primary Font (Headlines)
|
||||
|
||||
Bold condensed typeface like Impact, Oswald Bold, or Bebas Neue. Oversized headlines that dominate the slide. All-caps for maximum impact. Tight letter-spacing.
|
||||
|
||||
### Secondary Font (Body)
|
||||
|
||||
Clean sans-serif such as Inter, SF Pro, or Helvetica Neue. Medium weight for body text. High contrast against background.
|
||||
|
||||
## Color Palette
|
||||
|
||||
| Role | Color | Hex | Usage |
|
||||
|------|-------|-----|-------|
|
||||
| Background Dark | Deep Black | #0A0A0A | Primary dark background |
|
||||
| Background Alt | Deep Blue | #0F172A | Alternative dark background |
|
||||
| Background Light | Pure White | #FFFFFF | Light mode background |
|
||||
| Primary Text | Pure White | #FFFFFF | Text on dark backgrounds |
|
||||
| Alt Text | Pure Black | #000000 | Text on light backgrounds |
|
||||
| Accent 1 | Electric Blue | #3B82F6 | Primary highlights |
|
||||
| Accent 2 | Bright Orange | #FB923C | Energy, urgency |
|
||||
| Accent 3 | Magenta | #EC4899 | Creative, bold accents |
|
||||
| Accent 4 | Neon Green | #22C55E | Success, growth |
|
||||
| Accent 5 | Violet | #8B5CF6 | Innovation, premium |
|
||||
|
||||
## Visual Elements
|
||||
|
||||
- Strong typography as visual element itself
|
||||
- Geometric shapes and bold color blocks
|
||||
- Full-bleed images or solid color backgrounds
|
||||
- High contrast gradients (subtle, not garish)
|
||||
- Minimal decoration - let content speak
|
||||
- Dynamic diagonal lines and angles
|
||||
- Dramatic lighting effects on text
|
||||
|
||||
## Style Rules
|
||||
|
||||
### Do
|
||||
|
||||
- Use extreme scale contrast (huge headlines, small body)
|
||||
- Create bold color block compositions
|
||||
- Let negative space create tension
|
||||
- Use full-bleed backgrounds
|
||||
- Make every slide feel like a magazine cover
|
||||
|
||||
### Don't
|
||||
|
||||
- Use soft or muted colors
|
||||
- Add unnecessary decorative elements
|
||||
- Create busy, cluttered layouts
|
||||
- Use thin or delicate typography
|
||||
- Add slide numbers, footers, or logos
|
||||
|
||||
## Best For
|
||||
|
||||
Product launches, marketing presentations, keynote speeches, brand showcases, investor pitches, high-stakes presentations
|
||||
@@ -0,0 +1,69 @@
|
||||
# corporate
|
||||
|
||||
Professional business style with navy/gold palette and structured layouts
|
||||
|
||||
## Design Aesthetic
|
||||
|
||||
Clean lines, structured layouts, and business-appropriate sophistication. Projects competence, reliability, and institutional credibility. Balances professionalism with approachability through careful use of whitespace and refined color choices.
|
||||
|
||||
## Background
|
||||
|
||||
- Color: Pure White (#FFFFFF) with navy structural elements
|
||||
- Texture: None - crisp digital clarity for maximum professionalism
|
||||
|
||||
## Typography
|
||||
|
||||
### Primary Font (Headlines)
|
||||
|
||||
Modern geometric sans-serif (Inter, SF Pro, or similar). Clean, professional, and highly legible. Conveys competence and contemporary business sensibility. Medium to semi-bold weight.
|
||||
|
||||
### Secondary Font (Body)
|
||||
|
||||
Humanist sans-serif (Source Sans Pro style) for body text. Friendly yet professional, optimized for reading comprehension. Regular weight with comfortable line height.
|
||||
|
||||
## Color Palette
|
||||
|
||||
| Role | Color | Hex | Usage |
|
||||
|------|-------|-----|-------|
|
||||
| Background | Pure White | #FFFFFF | Main slide background |
|
||||
| Primary Text | Navy | #1E3A5F | Headlines, key text |
|
||||
| Secondary Text | Dark Gray | #4A5568 | Body text |
|
||||
| Primary Accent | Gold | #C9A227 | Premium highlights, emphasis |
|
||||
| Secondary Accent | Light Navy | #3D5A80 | Secondary elements |
|
||||
| Success | Corporate Green | #059669 | Positive metrics |
|
||||
| Alert | Corporate Red | #DC2626 | Attention items |
|
||||
| Neutral | Light Gray | #F3F4F6 | Background sections |
|
||||
|
||||
## Visual Elements
|
||||
|
||||
- Clean charts and data visualizations
|
||||
- Professional iconography (outlined style)
|
||||
- Structured grid layouts
|
||||
- Subtle shadows for depth (minimal)
|
||||
- Progress bars and metrics displays
|
||||
- Organizational charts
|
||||
- Timeline graphics
|
||||
- Comparison tables
|
||||
|
||||
## Style Rules
|
||||
|
||||
### Do
|
||||
|
||||
- Maintain clear visual hierarchy
|
||||
- Use consistent grid alignment
|
||||
- Apply accent colors strategically (gold for emphasis)
|
||||
- Keep data visualizations clean and readable
|
||||
- Use professional outlined iconography
|
||||
|
||||
### Don't
|
||||
|
||||
- Use playful or casual elements
|
||||
- Apply heavy decorative effects
|
||||
- Mix too many accent colors
|
||||
- Crowd slides with information
|
||||
- Use informal illustration styles
|
||||
- Add slide numbers, footers, or logos
|
||||
|
||||
## Best For
|
||||
|
||||
Business presentations, investor decks, quarterly reports, executive summaries, client proposals, corporate communications, board meetings
|
||||
@@ -0,0 +1,64 @@
|
||||
# minimal
|
||||
|
||||
Ultra-clean keynote style with maximum whitespace and zen-like simplicity
|
||||
|
||||
## Design Aesthetic
|
||||
|
||||
Maximum whitespace with minimal elements. Zen-like simplicity where every element earns its place. Premium, refined aesthetic suitable for executive audiences. Less is more - remove until nothing more can be taken away.
|
||||
|
||||
## Background
|
||||
|
||||
- Color: Pure White (#FFFFFF)
|
||||
- Texture: None - absolute clean, no grain or patterns
|
||||
|
||||
## Typography
|
||||
|
||||
### Primary Font (Headlines)
|
||||
|
||||
Clean geometric sans-serif like SF Pro Display, Inter, or Helvetica Neue. Light to medium weight for elegant restraint. Generous letter-spacing. Large scale for impact without boldness.
|
||||
|
||||
### Secondary Font (Body)
|
||||
|
||||
Same family as headlines in lighter weight. Minimal size contrast. Clean, airy feeling throughout.
|
||||
|
||||
## Color Palette
|
||||
|
||||
| Role | Color | Hex | Usage |
|
||||
|------|-------|-----|-------|
|
||||
| Background | Pure White | #FFFFFF | Primary background |
|
||||
| Primary Text | Near Black | #1A1A1A | Headlines, body |
|
||||
| Secondary Text | Medium Gray | #6B7280 | Captions, metadata |
|
||||
| Accent | Single Brand Color | #2563EB | One accent only, sparingly |
|
||||
| Dividers | Light Gray | #E5E7EB | Subtle separators |
|
||||
|
||||
## Visual Elements
|
||||
|
||||
- Single accent color used sparingly
|
||||
- Thin hairline rules for separation
|
||||
- Generous margins (minimum 15% on all sides)
|
||||
- Center or left-aligned layouts
|
||||
- Simple geometric shapes only when necessary
|
||||
- No decorative elements
|
||||
- Data visualizations in single color or grayscale
|
||||
|
||||
## Style Rules
|
||||
|
||||
### Do
|
||||
|
||||
- Embrace empty space as a design element
|
||||
- Use single accent color only
|
||||
- Keep text minimal (10 words or less per slide)
|
||||
- Create breathing room between elements
|
||||
- Use scale to create hierarchy
|
||||
|
||||
### Don't
|
||||
|
||||
- Fill empty space with decoration
|
||||
- Use multiple accent colors
|
||||
- Add icons or illustrations unless essential
|
||||
- Create dense information layouts
|
||||
- Add slide numbers, footers, or logos
|
||||
|
||||
## Best For
|
||||
|
||||
Executive briefings, keynote presentations, premium brand communications, minimalist products, investor meetings, high-level strategy
|
||||
@@ -0,0 +1,69 @@
|
||||
# notion
|
||||
|
||||
SaaS dashboard aesthetic with clean data focus and productivity tool styling
|
||||
|
||||
## Design Aesthetic
|
||||
|
||||
Clean, functional SaaS interface aesthetic. Dashboard-inspired layouts with clear data hierarchy. Notion, Linear, and modern productivity tool styling. Information-dense but organized. Professional and trustworthy.
|
||||
|
||||
## Background
|
||||
|
||||
- Color: Light Gray (#F7F7F5) or Pure White (#FFFFFF)
|
||||
- Texture: None - clean solid backgrounds
|
||||
|
||||
## Typography
|
||||
|
||||
### Primary Font (Headlines)
|
||||
|
||||
System UI stack or Inter. Semi-bold weight for emphasis. Clean, functional letterforms. Slightly tighter letter-spacing.
|
||||
|
||||
### Secondary Font (Body)
|
||||
|
||||
Same family in regular weight. Optimized for screen reading. Comfortable line height (1.5-1.6).
|
||||
|
||||
## Color Palette
|
||||
|
||||
| Role | Color | Hex | Usage |
|
||||
|------|-------|-----|-------|
|
||||
| Background | Light Gray | #F7F7F5 | Primary background |
|
||||
| Card Background | Pure White | #FFFFFF | Content cards |
|
||||
| Primary Text | Near Black | #1F1F1F | Headlines, body |
|
||||
| Secondary Text | Gray | #6B6B6B | Metadata, labels |
|
||||
| Border | Light Border | #E5E5E5 | Card borders, dividers |
|
||||
| Accent Blue | Notion Blue | #2383E2 | Links, primary actions |
|
||||
| Accent Green | Success | #0F7B6C | Positive metrics |
|
||||
| Accent Red | Alert | #E03E3E | Negative metrics |
|
||||
| Accent Yellow | Warning | #DFAB01 | Cautions |
|
||||
|
||||
## Visual Elements
|
||||
|
||||
- Card-based layouts with subtle borders or shadows
|
||||
- Clean data tables and charts
|
||||
- Progress bars and metric displays
|
||||
- Icon-based navigation hints
|
||||
- Checkbox and toggle styling
|
||||
- Tag and label chips
|
||||
- Subtle hover state styling
|
||||
- Breadcrumb and hierarchy indicators
|
||||
|
||||
## Style Rules
|
||||
|
||||
### Do
|
||||
|
||||
- Use card-based content organization
|
||||
- Create clear data hierarchy
|
||||
- Use subtle shadows and borders
|
||||
- Keep layouts grid-aligned
|
||||
- Present metrics prominently
|
||||
|
||||
### Don't
|
||||
|
||||
- Use decorative illustrations
|
||||
- Add gradients or complex backgrounds
|
||||
- Create artistic layouts
|
||||
- Use rounded blob shapes
|
||||
- Add slide numbers, footers, or logos
|
||||
|
||||
## Best For
|
||||
|
||||
Product demos, SaaS presentations, productivity tool pitches, metrics dashboards, feature walkthroughs, B2B presentations, technical product marketing
|
||||
@@ -0,0 +1,69 @@
|
||||
# playful
|
||||
|
||||
Bold, energetic style with vibrant colors and dynamic shapes
|
||||
|
||||
## Design Aesthetic
|
||||
|
||||
Dynamic shapes, vibrant colors, and creative layouts that capture attention and spark joy. Approachable and fun without sacrificing clarity. Perfect for content that needs to educate while entertaining, making complex topics feel accessible and exciting.
|
||||
|
||||
## Background
|
||||
|
||||
- Color: Warm White (#FFFDF7), soft and inviting
|
||||
- Texture: Light subtle pattern or clean gradient
|
||||
|
||||
## Typography
|
||||
|
||||
### Primary Font (Headlines)
|
||||
|
||||
Bold rounded sans-serif (Poppins, Nunito Bold, or similar). Friendly, modern, and highly readable. Conveys energy and approachability with geometric character.
|
||||
|
||||
### Secondary Font (Body)
|
||||
|
||||
Rounded sans-serif (Nunito style) for body text. Soft edges create warmth and readability, complementing the playful aesthetic.
|
||||
|
||||
## Color Palette
|
||||
|
||||
| Role | Color | Hex | Usage |
|
||||
|------|-------|-----|-------|
|
||||
| Background | Warm White | #FFFDF7 | Main slide background |
|
||||
| Primary Text | Deep Purple | #4A1D96 | Headlines, key text |
|
||||
| Secondary Text | Dark Purple | #6B3FA0 | Body text |
|
||||
| Primary Accent | Vibrant Coral | #FF6B6B | Primary highlights |
|
||||
| Secondary Accent | Electric Teal | #4ECDC4 | Secondary emphasis |
|
||||
| Tertiary | Sunshine Yellow | #FFE66D | Tertiary accent |
|
||||
| Success | Mint Green | #95E1C3 | Positive elements |
|
||||
| Energy | Hot Pink | #FF69B4 | High energy callouts |
|
||||
|
||||
## Visual Elements
|
||||
|
||||
- Rounded shapes and soft corners everywhere
|
||||
- Playful gradients (subtle, not overwhelming)
|
||||
- Character illustrations and mascots
|
||||
- Dynamic asymmetrical compositions
|
||||
- Bright color pops and accents
|
||||
- Confetti and celebration elements
|
||||
- Emoji-style icons
|
||||
- Bubble and cloud shapes
|
||||
|
||||
## Style Rules
|
||||
|
||||
### Do
|
||||
|
||||
- Use bold, contrasting colors
|
||||
- Include rounded, friendly shapes
|
||||
- Create dynamic, engaging layouts
|
||||
- Add implied motion and energy
|
||||
- Keep typography large and readable
|
||||
|
||||
### Don't
|
||||
|
||||
- Use sharp, aggressive shapes
|
||||
- Apply dark or somber colors
|
||||
- Create static, boring layouts
|
||||
- Overload with too many elements
|
||||
- Make it look unprofessional
|
||||
- Add slide numbers, footers, or logos
|
||||
|
||||
## Best For
|
||||
|
||||
Creative pitches, educational workshops, training materials, community presentations, product launches, children's content, team building, startup culture
|
||||
@@ -0,0 +1,66 @@
|
||||
# sketch-notes
|
||||
|
||||
Soft hand-drawn illustration style with fresh, refined minimalist editorial aesthetic
|
||||
|
||||
## Design Aesthetic
|
||||
|
||||
Illustration or hand-drawn feel with soft, relaxed brush strokes. Fresh, refined overall style with minimalist editorial approach. Emphasis on precision, clarity and intelligent elegance while prioritizing warmth, approachability and friendliness.
|
||||
|
||||
## Background
|
||||
|
||||
- Color: Warm Off-White (#FAF8F0)
|
||||
- Texture: Subtle paper grain, slightly warm tone to avoid clinical feel
|
||||
|
||||
## Typography
|
||||
|
||||
### Primary Font (Headlines)
|
||||
|
||||
Bold hand-written marker font or cartoon poster font. Slightly uneven baseline for organic feel. Thick strokes with soft edges. Render as hand-drawn letters, not typed text.
|
||||
|
||||
### Secondary Font (Body)
|
||||
|
||||
Clear handwritten round or hard-pen style mimicking everyday notes. Consistent sizing with slight natural variation. Render as casual handwriting, legible but not mechanical.
|
||||
|
||||
## Color Palette
|
||||
|
||||
| Role | Color | Hex | Usage |
|
||||
|------|-------|-----|-------|
|
||||
| Background | Warm Off-White | #FAF8F0 | Primary background |
|
||||
| Primary Text | Deep Charcoal | #2C3E50 | Headlines, body text |
|
||||
| Alt Text | Deep Brown | #4A4A4A | Secondary text elements |
|
||||
| Accent 1 | Soft Orange | #F4A261 | Highlights, emphasis |
|
||||
| Accent 2 | Mustard Yellow | #E9C46A | Secondary highlights |
|
||||
| Accent 3 | Sage Green | #87A96B | Nature, growth concepts |
|
||||
| Accent 4 | Light Blue | #7EC8E3 | Tech, AI elements |
|
||||
| Accent 5 | Red Brown | #A0522D | Land, infrastructure |
|
||||
|
||||
## Visual Elements
|
||||
|
||||
- Connection lines with hand-drawn wavy feel, not perfectly straight
|
||||
- Conceptual abstract icons illustrating ideas rather than literal scenes
|
||||
- Color fills don't need to completely fill outlines - preserve hand-painted casual feel
|
||||
- Simple geometric shapes with rounded corners
|
||||
- Arrows and pointers with sketchy, informal style
|
||||
- Doodle-style decorative elements: stars, spirals, underlines
|
||||
|
||||
## Style Rules
|
||||
|
||||
### Do
|
||||
|
||||
- Keep layouts open and well-structured
|
||||
- Emphasize information hierarchy and readability
|
||||
- Use hand-drawn quality for all elements
|
||||
- Allow imperfection - slight wobbles add character
|
||||
- Layer elements with subtle overlaps
|
||||
|
||||
### Don't
|
||||
|
||||
- Use perfect geometric shapes
|
||||
- Create photorealistic elements
|
||||
- Overcrowd with too many elements
|
||||
- Use pure white backgrounds
|
||||
- Add slide numbers, footers, or logos
|
||||
|
||||
## Best For
|
||||
|
||||
Educational content, knowledge sharing, technical explanations, friendly presentations, tutorials, onboarding materials
|
||||
@@ -0,0 +1,67 @@
|
||||
# storytelling
|
||||
|
||||
Cinematic narrative style with full-bleed visuals and emotional impact
|
||||
|
||||
## Design Aesthetic
|
||||
|
||||
Cinematic, full-bleed imagery that creates emotional connection. Story-driven compositions that guide the viewer through a narrative arc. Each slide is a scene in a larger story. Photography and illustration work together to create atmosphere.
|
||||
|
||||
## Background
|
||||
|
||||
- Color: Varies by mood - dark for drama (#0F0F0F), warm for comfort (#FDF8F3)
|
||||
- Texture: Photographic or illustrated backgrounds, subtle vignetting
|
||||
|
||||
## Typography
|
||||
|
||||
### Primary Font (Headlines)
|
||||
|
||||
Elegant serif like Playfair Display, Libre Baskerville, or editorial serif. Large, expressive headlines that complement imagery. Can use italic for emotional emphasis.
|
||||
|
||||
### Secondary Font (Body)
|
||||
|
||||
Clean sans-serif for contrast and readability. Light weight to not compete with imagery. White or dark depending on background.
|
||||
|
||||
## Color Palette
|
||||
|
||||
| Role | Color | Hex | Usage |
|
||||
|------|-------|-----|-------|
|
||||
| Background Dark | Near Black | #0F0F0F | Dramatic scenes |
|
||||
| Background Warm | Warm Cream | #FDF8F3 | Comfortable scenes |
|
||||
| Primary Text Light | Off-White | #FAFAFA | Text on dark |
|
||||
| Primary Text Dark | Deep Charcoal | #1F1F1F | Text on light |
|
||||
| Accent Warm | Golden | #D4A853 | Warm highlights |
|
||||
| Accent Cool | Teal | #2DD4BF | Cool accents |
|
||||
| Overlay | Black 40% | rgba(0,0,0,0.4) | Text legibility |
|
||||
|
||||
## Visual Elements
|
||||
|
||||
- Full-bleed photographic or illustrated backgrounds
|
||||
- Cinematic aspect compositions (rule of thirds)
|
||||
- Text overlays with subtle background darkening
|
||||
- Atmospheric lighting and mood
|
||||
- People and human elements when possible
|
||||
- Emotional color grading
|
||||
- Subtle motion blur or depth of field effects
|
||||
- Vignetting to draw focus
|
||||
|
||||
## Style Rules
|
||||
|
||||
### Do
|
||||
|
||||
- Create emotional connection through imagery
|
||||
- Use photography or illustration as primary element
|
||||
- Let visuals tell the story
|
||||
- Create consistent mood throughout deck
|
||||
- Use text sparingly - images speak
|
||||
|
||||
### Don't
|
||||
|
||||
- Use stock photo aesthetic
|
||||
- Crowd slides with text
|
||||
- Mix conflicting visual moods
|
||||
- Use clip art or basic shapes
|
||||
- Add slide numbers, footers, or logos
|
||||
|
||||
## Best For
|
||||
|
||||
Case studies, brand stories, narrative presentations, emotional pitches, documentary-style content, origin stories, customer journeys
|
||||
@@ -0,0 +1,72 @@
|
||||
# vector-illustration
|
||||
|
||||
Flat vector illustration style with clear black outlines and retro soft color palette
|
||||
|
||||
## Design Aesthetic
|
||||
|
||||
Flat vector illustration with no gradients or 3D effects. Clear, uniform-thickness black outlines on all elements. Geometric simplification reducing complex objects to basic shapes. Toy model aesthetic that's cute, playful, and approachable. Panoramic horizontal compositions work well.
|
||||
|
||||
## Background
|
||||
|
||||
- Color: Cream Off-White (#F5F0E6)
|
||||
- Texture: Subtle paper texture, warm nostalgic feel reminiscent of vintage prints
|
||||
|
||||
## Typography
|
||||
|
||||
### Primary Font (Headlines)
|
||||
|
||||
Large, bold retro serif for titles conveying authority and elegance. Think classic advertising posters. Clean letterforms with strong presence.
|
||||
|
||||
### Secondary Font (Subtitles)
|
||||
|
||||
All-caps sans-serif inside colored rectangular blocks. Label-like appearance. High contrast against block color.
|
||||
|
||||
### Body Font
|
||||
|
||||
Clean geometric sans-serif for readability. Futura, Avenir, or similar. Consistent weight throughout.
|
||||
|
||||
## Color Palette
|
||||
|
||||
| Role | Color | Hex | Usage |
|
||||
|------|-------|-----|-------|
|
||||
| Background | Cream Off-White | #F5F0E6 | Primary background |
|
||||
| Outlines | Deep Charcoal | #2D2D2D | All element outlines |
|
||||
| Primary Text | Black | #1A1A1A | Headlines, body |
|
||||
| Accent 1 | Coral Red | #E07A5F | Primary accent, warmth |
|
||||
| Accent 2 | Mint Green | #81B29A | Secondary accent, nature |
|
||||
| Accent 3 | Mustard Yellow | #F2CC8F | Highlights, energy |
|
||||
| Accent 4 | Burnt Orange | #D4764A | Tertiary accent |
|
||||
| Accent 5 | Rock Blue | #577590 | Cool balance, tech |
|
||||
|
||||
## Visual Elements
|
||||
|
||||
- All objects have closed black outlines (coloring book style)
|
||||
- Rounded line endings, avoid sharp corners
|
||||
- Trees simplified to lollipop or triangle shapes
|
||||
- Buildings simplified to rectangular blocks with grid windows
|
||||
- 2.5D perspective (isometric-like but more free-form)
|
||||
- Depth through layering and overlap, not atmospheric perspective
|
||||
- Decorative geometric elements: radiating lines (sunbursts), pill-shaped clouds, dots, stars
|
||||
- People as simple geometric figures with minimal facial detail
|
||||
|
||||
## Style Rules
|
||||
|
||||
### Do
|
||||
|
||||
- Maintain consistent outline thickness throughout
|
||||
- Use soft, vintage color palette
|
||||
- Simplify all objects to basic geometric shapes
|
||||
- Create depth through layering
|
||||
- Add playful decorative elements
|
||||
|
||||
### Don't
|
||||
|
||||
- Use gradients or realistic shading
|
||||
- Create photorealistic elements
|
||||
- Use thin or varying line weights
|
||||
- Include complex detailed illustrations
|
||||
- Add slide numbers, footers, or logos
|
||||
|
||||
## Best For
|
||||
|
||||
Educational presentations, creative proposals, children's content, brand showcases, warm approachable topics, explainer content
|
||||
@@ -0,0 +1,68 @@
|
||||
# warm
|
||||
|
||||
Soft gradients and wellness aesthetic with approachable, friendly feeling
|
||||
|
||||
## Design Aesthetic
|
||||
|
||||
Soft, calming gradients with rounded shapes. Wellness and lifestyle aesthetic that feels approachable and nurturing. Organic flowing forms balanced with clean typography. Warmth and comfort in every element.
|
||||
|
||||
## Background
|
||||
|
||||
- Color: Soft gradient from Warm Peach (#FDF4F0) to Soft Lavender (#F5F0FF)
|
||||
- Texture: Subtle organic shapes, soft blurred elements
|
||||
|
||||
## Typography
|
||||
|
||||
### Primary Font (Headlines)
|
||||
|
||||
Rounded sans-serif like Nunito, Poppins, or Quicksand. Medium to semi-bold weight. Friendly, approachable letterforms. Generous spacing.
|
||||
|
||||
### Secondary Font (Body)
|
||||
|
||||
Same family in regular weight, or complementary rounded sans-serif. Comfortable reading size. Warm, inviting tone.
|
||||
|
||||
## Color Palette
|
||||
|
||||
| Role | Color | Hex | Usage |
|
||||
|------|-------|-----|-------|
|
||||
| Background Start | Warm Peach | #FDF4F0 | Gradient start |
|
||||
| Background End | Soft Lavender | #F5F0FF | Gradient end |
|
||||
| Primary Text | Warm Charcoal | #3D3D3D | Headlines, body |
|
||||
| Secondary Text | Soft Gray | #6B6B6B | Supporting text |
|
||||
| Accent 1 | Coral | #FF8A80 | Primary highlights |
|
||||
| Accent 2 | Soft Teal | #80CBC4 | Balance, growth |
|
||||
| Accent 3 | Lavender | #B39DDB | Calm, premium |
|
||||
| Accent 4 | Soft Yellow | #FFE082 | Energy, joy |
|
||||
|
||||
## Visual Elements
|
||||
|
||||
- Soft gradient backgrounds (avoid harsh transitions)
|
||||
- Organic blob shapes with blurred edges
|
||||
- Rounded rectangles and pill shapes
|
||||
- Soft drop shadows (large blur, low opacity)
|
||||
- Simple line illustrations with rounded endpoints
|
||||
- Abstract organic patterns
|
||||
- Floating elements with gentle motion implied
|
||||
- Layered translucent shapes
|
||||
|
||||
## Style Rules
|
||||
|
||||
### Do
|
||||
|
||||
- Use soft, gentle color transitions
|
||||
- Keep all corners rounded
|
||||
- Create sense of calm and space
|
||||
- Use organic, flowing shapes
|
||||
- Layer elements with transparency
|
||||
|
||||
### Don't
|
||||
|
||||
- Use sharp corners or harsh lines
|
||||
- Create high-contrast jarring combinations
|
||||
- Use dark or aggressive colors
|
||||
- Add busy or complex illustrations
|
||||
- Add slide numbers, footers, or logos
|
||||
|
||||
## Best For
|
||||
|
||||
Wellness content, personal development, lifestyle brands, health and fitness, mindfulness, self-care, coaching, therapy, HR presentations
|
||||
@@ -0,0 +1,116 @@
|
||||
import { existsSync, readdirSync, readFileSync } from "fs";
|
||||
import { join, basename } from "path";
|
||||
import { PDFDocument, rgb } from "pdf-lib";
|
||||
|
||||
interface SlideInfo {
|
||||
filename: string;
|
||||
path: string;
|
||||
index: number;
|
||||
promptPath?: string;
|
||||
}
|
||||
|
||||
function parseArgs(): { dir: string; output?: string } {
|
||||
const args = process.argv.slice(2);
|
||||
let dir = "";
|
||||
let output: string | undefined;
|
||||
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
if (args[i] === "--output" || args[i] === "-o") {
|
||||
output = args[++i];
|
||||
} else if (!args[i].startsWith("-")) {
|
||||
dir = args[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (!dir) {
|
||||
console.error("Usage: bun merge-to-pdf.ts <slide-deck-dir> [--output filename.pdf]");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
return { dir, output };
|
||||
}
|
||||
|
||||
function findSlideImages(dir: string): SlideInfo[] {
|
||||
if (!existsSync(dir)) {
|
||||
console.error(`Directory not found: ${dir}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const files = readdirSync(dir);
|
||||
const slidePattern = /^(\d+)-slide-.*\.(png|jpg|jpeg)$/i;
|
||||
const promptsDir = join(dir, "prompts");
|
||||
const hasPrompts = existsSync(promptsDir);
|
||||
|
||||
const slides: SlideInfo[] = files
|
||||
.filter((f) => slidePattern.test(f))
|
||||
.map((f) => {
|
||||
const match = f.match(slidePattern);
|
||||
const baseName = f.replace(/\.(png|jpg|jpeg)$/i, "");
|
||||
const promptPath = hasPrompts ? join(promptsDir, `${baseName}.md`) : undefined;
|
||||
|
||||
return {
|
||||
filename: f,
|
||||
path: join(dir, f),
|
||||
index: parseInt(match![1], 10),
|
||||
promptPath: promptPath && existsSync(promptPath) ? promptPath : undefined,
|
||||
};
|
||||
})
|
||||
.sort((a, b) => a.index - b.index);
|
||||
|
||||
if (slides.length === 0) {
|
||||
console.error(`No slide images found in: ${dir}`);
|
||||
console.error("Expected format: 01-slide-*.png, 02-slide-*.png, etc.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
return slides;
|
||||
}
|
||||
|
||||
async function createPdf(slides: SlideInfo[], outputPath: string) {
|
||||
const pdfDoc = await PDFDocument.create();
|
||||
pdfDoc.setAuthor("baoyu-slide-deck");
|
||||
pdfDoc.setSubject("Generated Slide Deck");
|
||||
|
||||
for (const slide of slides) {
|
||||
const imageData = readFileSync(slide.path);
|
||||
const ext = slide.filename.toLowerCase();
|
||||
const image = ext.endsWith(".png")
|
||||
? await pdfDoc.embedPng(imageData)
|
||||
: await pdfDoc.embedJpg(imageData);
|
||||
|
||||
const { width, height } = image;
|
||||
const page = pdfDoc.addPage([width, height]);
|
||||
|
||||
page.drawImage(image, {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width,
|
||||
height,
|
||||
});
|
||||
|
||||
console.log(`Added: ${slide.filename}${slide.promptPath ? " (prompt available)" : ""}`);
|
||||
}
|
||||
|
||||
const pdfBytes = await pdfDoc.save();
|
||||
await Bun.write(outputPath, pdfBytes);
|
||||
|
||||
console.log(`\nCreated: ${outputPath}`);
|
||||
console.log(`Total pages: ${slides.length}`);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const { dir, output } = parseArgs();
|
||||
const slides = findSlideImages(dir);
|
||||
|
||||
const dirName = basename(dir) === "slide-deck" ? basename(join(dir, "..")) : basename(dir);
|
||||
const outputPath = output || join(dir, `${dirName}.pdf`);
|
||||
|
||||
console.log(`Found ${slides.length} slides in: ${dir}\n`);
|
||||
|
||||
await createPdf(slides, outputPath);
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error("Error:", err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -0,0 +1,137 @@
|
||||
import { existsSync, readdirSync, readFileSync } from "fs";
|
||||
import { join, basename, extname } from "path";
|
||||
import PptxGenJS from "pptxgenjs";
|
||||
|
||||
interface SlideInfo {
|
||||
filename: string;
|
||||
path: string;
|
||||
index: number;
|
||||
promptPath?: string;
|
||||
}
|
||||
|
||||
function parseArgs(): { dir: string; output?: string } {
|
||||
const args = process.argv.slice(2);
|
||||
let dir = "";
|
||||
let output: string | undefined;
|
||||
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
if (args[i] === "--output" || args[i] === "-o") {
|
||||
output = args[++i];
|
||||
} else if (!args[i].startsWith("-")) {
|
||||
dir = args[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (!dir) {
|
||||
console.error("Usage: bun merge-to-pptx.ts <slide-deck-dir> [--output filename.pptx]");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
return { dir, output };
|
||||
}
|
||||
|
||||
function findSlideImages(dir: string): SlideInfo[] {
|
||||
if (!existsSync(dir)) {
|
||||
console.error(`Directory not found: ${dir}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const files = readdirSync(dir);
|
||||
const slidePattern = /^(\d+)-slide-.*\.(png|jpg|jpeg)$/i;
|
||||
const promptsDir = join(dir, "prompts");
|
||||
const hasPrompts = existsSync(promptsDir);
|
||||
|
||||
const slides: SlideInfo[] = files
|
||||
.filter((f) => slidePattern.test(f))
|
||||
.map((f) => {
|
||||
const match = f.match(slidePattern);
|
||||
const baseName = f.replace(/\.(png|jpg|jpeg)$/i, "");
|
||||
const promptPath = hasPrompts ? join(promptsDir, `${baseName}.md`) : undefined;
|
||||
|
||||
return {
|
||||
filename: f,
|
||||
path: join(dir, f),
|
||||
index: parseInt(match![1], 10),
|
||||
promptPath: promptPath && existsSync(promptPath) ? promptPath : undefined,
|
||||
};
|
||||
})
|
||||
.sort((a, b) => a.index - b.index);
|
||||
|
||||
if (slides.length === 0) {
|
||||
console.error(`No slide images found in: ${dir}`);
|
||||
console.error("Expected format: 01-slide-*.png, 02-slide-*.png, etc.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
return slides;
|
||||
}
|
||||
|
||||
function findBasePrompt(): string | undefined {
|
||||
const scriptDir = import.meta.dir;
|
||||
const basePromptPath = join(scriptDir, "..", "references", "base-prompt.md");
|
||||
if (existsSync(basePromptPath)) {
|
||||
return readFileSync(basePromptPath, "utf-8");
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async function createPptx(slides: SlideInfo[], outputPath: string) {
|
||||
const pptx = new PptxGenJS();
|
||||
|
||||
pptx.layout = "LAYOUT_16x9";
|
||||
pptx.author = "baoyu-slide-deck";
|
||||
pptx.subject = "Generated Slide Deck";
|
||||
|
||||
const basePrompt = findBasePrompt();
|
||||
let notesCount = 0;
|
||||
|
||||
for (const slide of slides) {
|
||||
const s = pptx.addSlide();
|
||||
const imageData = readFileSync(slide.path);
|
||||
const base64 = imageData.toString("base64");
|
||||
const ext = extname(slide.filename).toLowerCase().replace(".", "");
|
||||
const mimeType = ext === "png" ? "image/png" : "image/jpeg";
|
||||
|
||||
s.addImage({
|
||||
data: `data:${mimeType};base64,${base64}`,
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: "100%",
|
||||
h: "100%",
|
||||
sizing: { type: "cover", w: "100%", h: "100%" },
|
||||
});
|
||||
|
||||
if (slide.promptPath) {
|
||||
const slidePrompt = readFileSync(slide.promptPath, "utf-8");
|
||||
const fullNotes = basePrompt ? `${basePrompt}\n\n---\n\n${slidePrompt}` : slidePrompt;
|
||||
s.addNotes(fullNotes);
|
||||
notesCount++;
|
||||
}
|
||||
|
||||
console.log(`Added: ${slide.filename}${slide.promptPath ? " (with notes)" : ""}`);
|
||||
}
|
||||
|
||||
await pptx.writeFile({ fileName: outputPath });
|
||||
console.log(`\nCreated: ${outputPath}`);
|
||||
console.log(`Total slides: ${slides.length}`);
|
||||
if (notesCount > 0) {
|
||||
console.log(`Slides with notes: ${notesCount}${basePrompt ? " (includes base prompt)" : ""}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const { dir, output } = parseArgs();
|
||||
const slides = findSlideImages(dir);
|
||||
|
||||
const dirName = basename(dir) === "slide-deck" ? basename(join(dir, "..")) : basename(dir);
|
||||
const outputPath = output || join(dir, `${dirName}.pptx`);
|
||||
|
||||
console.log(`Found ${slides.length} slides in: ${dir}\n`);
|
||||
|
||||
await createPptx(slides, outputPath);
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error("Error:", err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -49,103 +49,32 @@ Style × Layout can be freely combined. Example: `--style notion --layout dense`
|
||||
|
||||
## Style Gallery
|
||||
|
||||
### 1. `cute` (Default)
|
||||
Sweet, adorable, girly - classic Xiaohongshu aesthetic
|
||||
- **Colors**: Pink, peach, mint, lavender, cream background
|
||||
- **Elements**: Cute stickers, emoji icons, hearts, stars, sparkles
|
||||
- **Best for**: Lifestyle, beauty, fashion, daily tips
|
||||
| Style | Description |
|
||||
|-------|-------------|
|
||||
| `cute` (Default) | Sweet, adorable, girly - classic Xiaohongshu aesthetic |
|
||||
| `fresh` | Clean, refreshing, natural |
|
||||
| `tech` | Modern, smart, digital |
|
||||
| `warm` | Cozy, friendly, approachable |
|
||||
| `bold` | High impact, attention-grabbing |
|
||||
| `minimal` | Ultra-clean, sophisticated |
|
||||
| `retro` | Vintage, nostalgic, trendy |
|
||||
| `pop` | Vibrant, energetic, eye-catching |
|
||||
| `notion` | Minimalist hand-drawn line art, intellectual |
|
||||
|
||||
### 2. `fresh`
|
||||
Clean, refreshing, natural
|
||||
- **Colors**: Mint green, sky blue, white, light yellow
|
||||
- **Elements**: Plant icons, clouds, simple shapes, breathing room
|
||||
- **Best for**: Health, wellness, minimalist lifestyle, self-care
|
||||
|
||||
### 3. `tech`
|
||||
Modern, smart, digital
|
||||
- **Colors**: Deep blue, purple, cyan, dark backgrounds with neon accents
|
||||
- **Elements**: Geometric shapes, data icons, circuit patterns, glowing effects
|
||||
- **Best for**: Tech tutorials, AI content, digital tools, productivity
|
||||
|
||||
### 4. `warm`
|
||||
Cozy, friendly, approachable
|
||||
- **Colors**: Warm orange, golden yellow, brown, cream
|
||||
- **Elements**: Sun motifs, coffee cups, cozy illustrations, warm lighting
|
||||
- **Best for**: Personal stories, life lessons, emotional content
|
||||
|
||||
### 5. `bold`
|
||||
High impact, attention-grabbing
|
||||
- **Colors**: Red, orange, black, yellow accents
|
||||
- **Elements**: Strong typography, exclamation marks, arrows, contrast
|
||||
- **Best for**: Important tips, warnings, must-know content
|
||||
|
||||
### 6. `minimal`
|
||||
Ultra-clean, sophisticated
|
||||
- **Colors**: Black, white, single accent color
|
||||
- **Elements**: Maximum whitespace, simple icons, clean lines
|
||||
- **Best for**: Professional content, serious topics, elegant presentations
|
||||
|
||||
### 7. `retro`
|
||||
Vintage, nostalgic, trendy
|
||||
- **Colors**: Muted pastels, sepia, faded tones
|
||||
- **Elements**: Vintage badges, halftone dots, classic typography
|
||||
- **Best for**: Throwback content, classic tips, timeless advice
|
||||
|
||||
### 8. `pop`
|
||||
Vibrant, energetic, eye-catching
|
||||
- **Colors**: Bright primary colors, neon accents, white
|
||||
- **Elements**: Bold shapes, comic-style elements, dynamic compositions
|
||||
- **Best for**: Exciting announcements, fun facts, engaging tutorials
|
||||
|
||||
### 9. `notion`
|
||||
Minimalist hand-drawn line art, intellectual
|
||||
- **Colors**: Black outlines, white background, 1-2 pastel accents
|
||||
- **Elements**: Simple line doodles, geometric shapes, hand-drawn wobble, maximum whitespace
|
||||
- **Best for**: Knowledge sharing, concept explanations, SaaS content, productivity tips
|
||||
Detailed style definitions: `references/styles/<style>.md`
|
||||
|
||||
## Layout Gallery
|
||||
|
||||
### 1. `sparse` (Default)
|
||||
Minimal information, maximum impact
|
||||
- **Density**: 1-2 key points per image
|
||||
- **Whitespace**: 60-70% of canvas
|
||||
- **Structure**: Single focal point, one core message
|
||||
- **Best for**: Covers, quotes, impactful statements, emotional content
|
||||
| Layout | Description |
|
||||
|--------|-------------|
|
||||
| `sparse` (Default) | Minimal information, maximum impact (1-2 points) |
|
||||
| `balanced` | Standard content layout (3-4 points) |
|
||||
| `dense` | High information density, knowledge card style (5-8 points) |
|
||||
| `list` | Enumeration and ranking format (4-7 items) |
|
||||
| `comparison` | Side-by-side contrast layout |
|
||||
| `flow` | Process and timeline layout (3-6 steps) |
|
||||
|
||||
### 2. `balanced`
|
||||
Standard content layout
|
||||
- **Density**: 3-4 key points per image
|
||||
- **Whitespace**: 40-50% of canvas
|
||||
- **Structure**: Title + 3-4 bullet points or sections
|
||||
- **Best for**: Regular content pages, tutorials, explanations
|
||||
|
||||
### 3. `dense`
|
||||
High information density, knowledge card style
|
||||
- **Density**: 5-8 key points per image
|
||||
- **Whitespace**: 20-30% of canvas
|
||||
- **Structure**: Multiple sections, structured grid, more text
|
||||
- **Best for**: Summary cards, cheat sheets, comprehensive guides, 干货总结
|
||||
|
||||
### 4. `list`
|
||||
Enumeration and ranking format
|
||||
- **Density**: 4-7 items
|
||||
- **Whitespace**: 30-40% of canvas
|
||||
- **Structure**: Numbered or bulleted vertical list, consistent item format
|
||||
- **Best for**: Top N lists, checklists, step-by-step guides, rankings
|
||||
|
||||
### 5. `comparison`
|
||||
Side-by-side contrast layout
|
||||
- **Density**: 2 main sections with 2-4 points each
|
||||
- **Whitespace**: 30-40% of canvas
|
||||
- **Structure**: Left vs Right, Before/After, Pros/Cons
|
||||
- **Best for**: Comparisons, transformations, decision helpers, 对比图
|
||||
|
||||
### 6. `flow`
|
||||
Process and timeline layout
|
||||
- **Density**: 3-6 steps/stages
|
||||
- **Whitespace**: 30-40% of canvas
|
||||
- **Structure**: Connected nodes with arrows, sequential flow
|
||||
- **Best for**: Processes, timelines, cause-effect chains, workflows
|
||||
Detailed layout definitions: `references/layouts/<layout>.md`
|
||||
|
||||
## Auto Style Selection
|
||||
|
||||
@@ -332,8 +261,14 @@ Style notes: [style-specific characteristics]
|
||||
1. Check available image generation skills
|
||||
2. If multiple skills available, ask user to choose
|
||||
|
||||
**Session Management**:
|
||||
If the image generation skill supports `--sessionId`:
|
||||
1. Generate a unique session ID at the start (e.g., `xhs-{topic-slug}-{timestamp}`)
|
||||
2. Use the same session ID for all images in the series
|
||||
3. This ensures style consistency across all generated images
|
||||
|
||||
**Generation Flow**:
|
||||
1. Call selected image generation skill with prompt file and output path
|
||||
1. Call selected image generation skill with prompt file, output path, and session ID
|
||||
2. Confirm generation success
|
||||
3. Report progress: "Generated X/N"
|
||||
4. Continue to next
|
||||
@@ -357,151 +292,6 @@ Images: N total
|
||||
Outline: outline.md
|
||||
```
|
||||
|
||||
## Style Reference Details
|
||||
|
||||
### cute
|
||||
```
|
||||
Colors: Pink (#FED7E2), peach (#FEEBC8), mint (#C6F6D5), lavender (#E9D8FD)
|
||||
Background: Cream (#FFFAF0), soft pink (#FFF5F7)
|
||||
Accents: Hot pink, coral
|
||||
Elements: Hearts, stars, sparkles, cute faces, ribbon decorations, sticker-style
|
||||
Typography: Rounded, bubbly hand lettering
|
||||
```
|
||||
|
||||
### fresh
|
||||
```
|
||||
Colors: Mint green (#9AE6B4), sky blue (#90CDF4), light yellow (#FAF089)
|
||||
Background: Pure white (#FFFFFF), soft mint (#F0FFF4)
|
||||
Accents: Leaf green, water blue
|
||||
Elements: Plant leaves, clouds, water drops, simple geometric shapes
|
||||
Typography: Clean, light hand lettering with breathing room
|
||||
```
|
||||
|
||||
### tech
|
||||
```
|
||||
Colors: Deep blue (#1A365D), purple (#6B46C1), cyan (#00D4FF)
|
||||
Background: Dark gray (#1A202C), near-black (#0D1117)
|
||||
Accents: Neon green (#00FF88), electric blue
|
||||
Elements: Circuit patterns, data icons, geometric grids, glowing effects
|
||||
Typography: Monospace-style hand lettering, subtle glow
|
||||
```
|
||||
|
||||
### warm
|
||||
```
|
||||
Colors: Warm orange (#ED8936), golden yellow (#F6AD55), terracotta (#C05621)
|
||||
Background: Cream (#FFFAF0), soft peach (#FED7AA)
|
||||
Accents: Deep brown (#744210), soft red
|
||||
Elements: Sun rays, coffee cups, cozy items, warm lighting effects
|
||||
Typography: Friendly, rounded hand lettering
|
||||
```
|
||||
|
||||
### bold
|
||||
```
|
||||
Colors: Vibrant red (#E53E3E), orange (#DD6B20), yellow (#F6E05E)
|
||||
Background: Deep black (#000000), dark charcoal
|
||||
Accents: White, neon yellow
|
||||
Elements: Exclamation marks, arrows, warning icons, strong shapes
|
||||
Typography: Bold, impactful hand lettering with shadows
|
||||
```
|
||||
|
||||
### minimal
|
||||
```
|
||||
Colors: Black (#000000), white (#FFFFFF)
|
||||
Background: Off-white (#FAFAFA), pure white
|
||||
Accents: Single color (content-derived - blue, green, or coral)
|
||||
Elements: Single focal point, thin lines, maximum whitespace
|
||||
Typography: Clean, simple hand lettering
|
||||
```
|
||||
|
||||
### retro
|
||||
```
|
||||
Colors: Muted orange, dusty pink (#FED7E2 at 70%), faded teal
|
||||
Background: Aged paper (#F5E6D3), sepia tones
|
||||
Accents: Faded red, vintage gold
|
||||
Elements: Halftone dots, vintage badges, classic icons, tape effects
|
||||
Typography: Vintage-style hand lettering, classic feel
|
||||
```
|
||||
|
||||
### pop
|
||||
```
|
||||
Colors: Bright red (#F56565), yellow (#ECC94B), blue (#4299E1), green (#48BB78)
|
||||
Background: White (#FFFFFF), light gray
|
||||
Accents: Neon pink, electric purple
|
||||
Elements: Bold shapes, speech bubbles, comic-style effects, starburst
|
||||
Typography: Dynamic, energetic hand lettering with outlines
|
||||
```
|
||||
|
||||
### notion
|
||||
```
|
||||
Colors: Black (#1A1A1A), dark gray (#4A4A4A)
|
||||
Background: Pure white (#FFFFFF), off-white (#FAFAFA)
|
||||
Accents: Pastel blue (#A8D4F0), pastel yellow (#F9E79F), pastel pink (#FADBD8)
|
||||
Elements: Simple line doodles, hand-drawn wobble effect, geometric shapes, stick figures, maximum whitespace
|
||||
Typography: Clean hand-drawn lettering, simple sans-serif labels
|
||||
```
|
||||
|
||||
## Layout Reference Details
|
||||
|
||||
### sparse
|
||||
```
|
||||
Information Density: Very Low (1-2 points)
|
||||
Whitespace: 60-70%
|
||||
Structure: Single centered focal point
|
||||
Text Elements: Title only, or title + one subtitle/tagline
|
||||
Visual Balance: Centered, symmetrical, breathing room on all sides
|
||||
Best Pairing: Any style, especially effective with bold, minimal, notion
|
||||
```
|
||||
|
||||
### balanced
|
||||
```
|
||||
Information Density: Medium (3-4 points)
|
||||
Whitespace: 40-50%
|
||||
Structure: Title at top, content sections below
|
||||
Text Elements: Title + 3-4 bullet points or key messages
|
||||
Visual Balance: Top-weighted title, evenly distributed content below
|
||||
Best Pairing: All styles work well
|
||||
```
|
||||
|
||||
### dense
|
||||
```
|
||||
Information Density: High (5-8 points)
|
||||
Whitespace: 20-30%
|
||||
Structure: Multi-section grid or stacked blocks
|
||||
Text Elements: Title + multiple sections with headers + numerous points
|
||||
Visual Balance: Organized chaos, clear section boundaries, compact spacing
|
||||
Best Pairing: tech, notion, minimal (clean styles prevent visual overload)
|
||||
```
|
||||
|
||||
### list
|
||||
```
|
||||
Information Density: Medium-High (4-7 items)
|
||||
Whitespace: 30-40%
|
||||
Structure: Vertical enumeration with numbers or bullets
|
||||
Text Elements: Title + numbered/bulleted items, consistent format per item
|
||||
Visual Balance: Left-aligned list, clear number/bullet hierarchy
|
||||
Best Pairing: All styles, especially cute (checklist), bold (rankings)
|
||||
```
|
||||
|
||||
### comparison
|
||||
```
|
||||
Information Density: Medium (2×2-4 points)
|
||||
Whitespace: 30-40%
|
||||
Structure: Two-column split with center divider
|
||||
Text Elements: Title + left label + right label + mirrored points
|
||||
Visual Balance: Symmetrical left/right, clear visual contrast
|
||||
Best Pairing: bold (dramatic contrast), tech (data comparison), warm (before/after stories)
|
||||
```
|
||||
|
||||
### flow
|
||||
```
|
||||
Information Density: Medium (3-6 steps)
|
||||
Whitespace: 30-40%
|
||||
Structure: Connected nodes with directional arrows
|
||||
Text Elements: Title + step labels + optional descriptions per step
|
||||
Visual Balance: Directional flow (top→bottom or left→right), clear progression
|
||||
Best Pairing: tech (process diagrams), notion (simple flows), fresh (organic flows)
|
||||
```
|
||||
|
||||
## Content Breakdown Principles
|
||||
|
||||
1. **Cover (Image 1)**: Strong visual impact, core title, attention hook → `sparse` layout
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
# balanced
|
||||
|
||||
Standard content layout
|
||||
|
||||
## Information Density
|
||||
|
||||
- 3-4 key points per image
|
||||
- Whitespace: 40-50% of canvas
|
||||
|
||||
## Structure
|
||||
|
||||
- Title at top
|
||||
- 3-4 bullet points or sections below
|
||||
|
||||
## Text Elements
|
||||
|
||||
- Title + 3-4 bullet points or key messages
|
||||
|
||||
## Visual Balance
|
||||
|
||||
- Top-weighted title
|
||||
- Evenly distributed content below
|
||||
|
||||
## Best For
|
||||
|
||||
Regular content pages, tutorials, explanations
|
||||
|
||||
## Best Style Pairings
|
||||
|
||||
All styles work well
|
||||
@@ -0,0 +1,31 @@
|
||||
# comparison
|
||||
|
||||
Side-by-side contrast layout
|
||||
|
||||
## Information Density
|
||||
|
||||
- 2 main sections with 2-4 points each
|
||||
- Whitespace: 30-40% of canvas
|
||||
|
||||
## Structure
|
||||
|
||||
- Left vs Right layout
|
||||
- Before/After, Pros/Cons format
|
||||
- Clear divider between sections
|
||||
|
||||
## Text Elements
|
||||
|
||||
- Title + left label + right label + mirrored points
|
||||
|
||||
## Visual Balance
|
||||
|
||||
- Symmetrical left/right
|
||||
- Clear visual contrast
|
||||
|
||||
## Best For
|
||||
|
||||
Comparisons, transformations, decision helpers, 对比图
|
||||
|
||||
## Best Style Pairings
|
||||
|
||||
bold (dramatic contrast), tech (data comparison), warm (before/after stories)
|
||||
@@ -0,0 +1,31 @@
|
||||
# dense
|
||||
|
||||
High information density, knowledge card style
|
||||
|
||||
## Information Density
|
||||
|
||||
- 5-8 key points per image
|
||||
- Whitespace: 20-30% of canvas
|
||||
|
||||
## Structure
|
||||
|
||||
- Multiple sections, structured grid
|
||||
- More text, compact but organized
|
||||
|
||||
## Text Elements
|
||||
|
||||
- Title + multiple sections with headers + numerous points
|
||||
|
||||
## Visual Balance
|
||||
|
||||
- Organized chaos
|
||||
- Clear section boundaries
|
||||
- Compact spacing
|
||||
|
||||
## Best For
|
||||
|
||||
Summary cards, cheat sheets, comprehensive guides, 干货总结
|
||||
|
||||
## Best Style Pairings
|
||||
|
||||
tech, notion, minimal (clean styles prevent visual overload)
|
||||
@@ -0,0 +1,30 @@
|
||||
# flow
|
||||
|
||||
Process and timeline layout
|
||||
|
||||
## Information Density
|
||||
|
||||
- 3-6 steps/stages
|
||||
- Whitespace: 30-40% of canvas
|
||||
|
||||
## Structure
|
||||
|
||||
- Connected nodes with arrows
|
||||
- Sequential flow, directional
|
||||
|
||||
## Text Elements
|
||||
|
||||
- Title + step labels + optional descriptions per step
|
||||
|
||||
## Visual Balance
|
||||
|
||||
- Directional flow (top→bottom or left→right)
|
||||
- Clear progression
|
||||
|
||||
## Best For
|
||||
|
||||
Processes, timelines, cause-effect chains, workflows
|
||||
|
||||
## Best Style Pairings
|
||||
|
||||
tech (process diagrams), notion (simple flows), fresh (organic flows)
|
||||
@@ -0,0 +1,31 @@
|
||||
# list
|
||||
|
||||
Enumeration and ranking format
|
||||
|
||||
## Information Density
|
||||
|
||||
- 4-7 items
|
||||
- Whitespace: 30-40% of canvas
|
||||
|
||||
## Structure
|
||||
|
||||
- Numbered or bulleted vertical list
|
||||
- Consistent item format
|
||||
|
||||
## Text Elements
|
||||
|
||||
- Title + numbered/bulleted items
|
||||
- Consistent format per item
|
||||
|
||||
## Visual Balance
|
||||
|
||||
- Left-aligned list
|
||||
- Clear number/bullet hierarchy
|
||||
|
||||
## Best For
|
||||
|
||||
Top N lists, checklists, step-by-step guides, rankings
|
||||
|
||||
## Best Style Pairings
|
||||
|
||||
All styles, especially cute (checklist), bold (rankings)
|
||||
@@ -0,0 +1,31 @@
|
||||
# sparse
|
||||
|
||||
Minimal information, maximum impact
|
||||
|
||||
## Information Density
|
||||
|
||||
- 1-2 key points per image
|
||||
- Whitespace: 60-70% of canvas
|
||||
|
||||
## Structure
|
||||
|
||||
- Single focal point centered
|
||||
- One core message
|
||||
- Single centered focal point
|
||||
|
||||
## Text Elements
|
||||
|
||||
- Title only, or title + one subtitle/tagline
|
||||
|
||||
## Visual Balance
|
||||
|
||||
- Centered, symmetrical
|
||||
- Breathing room on all sides
|
||||
|
||||
## Best For
|
||||
|
||||
Covers, quotes, impactful statements, emotional content
|
||||
|
||||
## Best Style Pairings
|
||||
|
||||
Any style, especially effective with bold, minimal, notion
|
||||
@@ -0,0 +1,23 @@
|
||||
# bold
|
||||
|
||||
High impact, attention-grabbing
|
||||
|
||||
## Color Palette
|
||||
|
||||
- Primary: Vibrant red (#E53E3E), orange (#DD6B20), yellow (#F6E05E)
|
||||
- Background: Deep black (#000000), dark charcoal
|
||||
- Accents: White, neon yellow
|
||||
|
||||
## Visual Elements
|
||||
|
||||
- Exclamation marks, arrows, warning icons
|
||||
- Strong shapes, high contrast elements
|
||||
- Dramatic compositions
|
||||
|
||||
## Typography
|
||||
|
||||
- Bold, impactful hand lettering with shadows
|
||||
|
||||
## Best For
|
||||
|
||||
Important tips, warnings, must-know content
|
||||
@@ -0,0 +1,23 @@
|
||||
# cute
|
||||
|
||||
Sweet, adorable, girly - classic Xiaohongshu aesthetic
|
||||
|
||||
## Color Palette
|
||||
|
||||
- Primary: Pink (#FED7E2), peach (#FEEBC8), mint (#C6F6D5), lavender (#E9D8FD)
|
||||
- Background: Cream (#FFFAF0), soft pink (#FFF5F7)
|
||||
- Accents: Hot pink, coral
|
||||
|
||||
## Visual Elements
|
||||
|
||||
- Hearts, stars, sparkles, cute faces
|
||||
- Ribbon decorations, sticker-style
|
||||
- Cute stickers, emoji icons
|
||||
|
||||
## Typography
|
||||
|
||||
- Rounded, bubbly hand lettering
|
||||
|
||||
## Best For
|
||||
|
||||
Lifestyle, beauty, fashion, daily tips
|
||||
@@ -0,0 +1,23 @@
|
||||
# fresh
|
||||
|
||||
Clean, refreshing, natural
|
||||
|
||||
## Color Palette
|
||||
|
||||
- Primary: Mint green (#9AE6B4), sky blue (#90CDF4), light yellow (#FAF089)
|
||||
- Background: Pure white (#FFFFFF), soft mint (#F0FFF4)
|
||||
- Accents: Leaf green, water blue
|
||||
|
||||
## Visual Elements
|
||||
|
||||
- Plant leaves, clouds, water drops
|
||||
- Simple geometric shapes
|
||||
- Breathing room, open composition
|
||||
|
||||
## Typography
|
||||
|
||||
- Clean, light hand lettering with breathing room
|
||||
|
||||
## Best For
|
||||
|
||||
Health, wellness, minimalist lifestyle, self-care
|
||||
@@ -0,0 +1,23 @@
|
||||
# minimal
|
||||
|
||||
Ultra-clean, sophisticated
|
||||
|
||||
## Color Palette
|
||||
|
||||
- Primary: Black (#000000), white (#FFFFFF)
|
||||
- Background: Off-white (#FAFAFA), pure white
|
||||
- Accents: Single color (content-derived - blue, green, or coral)
|
||||
|
||||
## Visual Elements
|
||||
|
||||
- Single focal point, thin lines
|
||||
- Maximum whitespace
|
||||
- Simple, clean decorations
|
||||
|
||||
## Typography
|
||||
|
||||
- Clean, simple hand lettering
|
||||
|
||||
## Best For
|
||||
|
||||
Professional content, serious topics, elegant presentations
|
||||
@@ -0,0 +1,23 @@
|
||||
# notion
|
||||
|
||||
Minimalist hand-drawn line art, intellectual
|
||||
|
||||
## Color Palette
|
||||
|
||||
- Primary: Black (#1A1A1A), dark gray (#4A4A4A)
|
||||
- Background: Pure white (#FFFFFF), off-white (#FAFAFA)
|
||||
- Accents: Pastel blue (#A8D4F0), pastel yellow (#F9E79F), pastel pink (#FADBD8)
|
||||
|
||||
## Visual Elements
|
||||
|
||||
- Simple line doodles, hand-drawn wobble effect
|
||||
- Geometric shapes, stick figures
|
||||
- Maximum whitespace, single-weight ink lines
|
||||
|
||||
## Typography
|
||||
|
||||
- Clean hand-drawn lettering, simple sans-serif labels
|
||||
|
||||
## Best For
|
||||
|
||||
Knowledge sharing, concept explanations, SaaS content, productivity tips
|
||||
@@ -0,0 +1,23 @@
|
||||
# pop
|
||||
|
||||
Vibrant, energetic, eye-catching
|
||||
|
||||
## Color Palette
|
||||
|
||||
- Primary: Bright red (#F56565), yellow (#ECC94B), blue (#4299E1), green (#48BB78)
|
||||
- Background: White (#FFFFFF), light gray
|
||||
- Accents: Neon pink, electric purple
|
||||
|
||||
## Visual Elements
|
||||
|
||||
- Bold shapes, speech bubbles
|
||||
- Comic-style effects, starburst
|
||||
- Dynamic, energetic compositions
|
||||
|
||||
## Typography
|
||||
|
||||
- Dynamic, energetic hand lettering with outlines
|
||||
|
||||
## Best For
|
||||
|
||||
Exciting announcements, fun facts, engaging tutorials
|
||||
@@ -0,0 +1,23 @@
|
||||
# retro
|
||||
|
||||
Vintage, nostalgic, trendy
|
||||
|
||||
## Color Palette
|
||||
|
||||
- Primary: Muted orange, dusty pink (#FED7E2 at 70%), faded teal
|
||||
- Background: Aged paper (#F5E6D3), sepia tones
|
||||
- Accents: Faded red, vintage gold
|
||||
|
||||
## Visual Elements
|
||||
|
||||
- Halftone dots, vintage badges
|
||||
- Classic icons, tape effects
|
||||
- Aged texture overlays
|
||||
|
||||
## Typography
|
||||
|
||||
- Vintage-style hand lettering, classic feel
|
||||
|
||||
## Best For
|
||||
|
||||
Throwback content, classic tips, timeless advice
|
||||
@@ -0,0 +1,23 @@
|
||||
# tech
|
||||
|
||||
Modern, smart, digital
|
||||
|
||||
## Color Palette
|
||||
|
||||
- Primary: Deep blue (#1A365D), purple (#6B46C1), cyan (#00D4FF)
|
||||
- Background: Dark gray (#1A202C), near-black (#0D1117)
|
||||
- Accents: Neon green (#00FF88), electric blue
|
||||
|
||||
## Visual Elements
|
||||
|
||||
- Circuit patterns, data icons
|
||||
- Geometric grids, glowing effects
|
||||
- Tech-inspired decorations
|
||||
|
||||
## Typography
|
||||
|
||||
- Monospace-style hand lettering, subtle glow
|
||||
|
||||
## Best For
|
||||
|
||||
Tech tutorials, AI content, digital tools, productivity
|
||||
@@ -0,0 +1,23 @@
|
||||
# warm
|
||||
|
||||
Cozy, friendly, approachable
|
||||
|
||||
## Color Palette
|
||||
|
||||
- Primary: Warm orange (#ED8936), golden yellow (#F6AD55), terracotta (#C05621)
|
||||
- Background: Cream (#FFFAF0), soft peach (#FED7AA)
|
||||
- Accents: Deep brown (#744210), soft red
|
||||
|
||||
## Visual Elements
|
||||
|
||||
- Sun rays, coffee cups, cozy items
|
||||
- Warm lighting effects
|
||||
- Friendly, inviting decorations
|
||||
|
||||
## Typography
|
||||
|
||||
- Friendly, rounded hand lettering
|
||||
|
||||
## Best For
|
||||
|
||||
Personal stories, life lessons, emotional content
|
||||
Reference in New Issue
Block a user