foliko 1.1.7 → 1.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agent/agents/poster-expert.md +228 -0
- package/.agent/data/default.json +10 -0
- package/.agent/data/plugins-state.json +1 -1
- package/.agent/mcp_config.json +0 -6
- package/.agent/plugins/test-plugin.py +15 -0
- package/.agent/plugins/test_nested_plugin.py +85 -0
- package/.agent/sessions/cli_default.json +83 -803
- package/.agent/sessions/weixin_o9cq80zgZqKPA2-s59PN43GdDy1w@im.wechat.json +189 -0
- package/.claude/settings.local.json +8 -1
- package/cli/src/ui/chat-ui.js +32 -21
- package/foliko_poster.png +0 -0
- package/output/business_poster_final.png +0 -0
- package/output/emoji_test_v2.png +0 -0
- package/output/foliko-ai-launch-poster.png +0 -0
- package/output/foliko-poster.png +0 -0
- package/output/muji_style_poster.png +0 -0
- package/output/new_product_launch.png +0 -0
- package/output/news_poster_625yi_subsidy.png +0 -0
- package/output/tech_future_2026.png +0 -0
- package/output/tech_future_poster.png +0 -0
- package/package.json +2 -2
- package/plugins/default-plugins.js +60 -7
- package/plugins/extension-executor-plugin.js +32 -22
- package/plugins/feishu-plugin.js +2 -2
- package/plugins/python-plugin-loader.js +461 -40
- package/plugins/python-plugin-loader.js.bak +856 -0
- package/plugins/subagent-plugin.js +0 -121
- package/plugins/telegram-plugin.js +2 -2
- package/plugins/weixin-plugin.js +40 -31
- package/poster.png +0 -0
- package/skills/foliko-dev/SKILL.md +6 -0
- package/skills/python-plugin-dev/SKILL.md +124 -2
- package/src/core/agent-chat.js +220 -281
- package/src/core/agent.js +127 -29
- package/src/executors/mcp-executor.js +282 -26
- package/src/utils/plugin-helpers.js +22 -4
- package/system.md +362 -109
- package/test-scan.js +18 -0
- package/.agent/memory/feedback/mnt7jrlt-d67qs7.md +0 -15
- package/.agent/memory/feedback/mnt88ja3-al4fuy.md +0 -9
- package/.agent/plugins/poster-plugin/README.md +0 -304
- package/.agent/plugins/poster-plugin/emojis/rocket.png +0 -1
- package/.agent/plugins/poster-plugin/fonts/PatuaOne-Regular.ttf +0 -0
- package/.agent/plugins/poster-plugin/fonts/SegoeUI Emoji.ttf +0 -0
- package/.agent/plugins/poster-plugin/fonts//345/276/256/350/275/257/351/233/205/351/273/221.ttf +0 -0
- package/.agent/plugins/poster-plugin/fonts//345/276/256/350/275/257/351/233/205/351/273/221/347/262/227/344/275/223.ttf +0 -0
- package/.agent/plugins/poster-plugin/index.js +0 -13
- package/.agent/plugins/poster-plugin/package.json +0 -29
- package/.agent/plugins/poster-plugin/src/canvas.js +0 -224
- package/.agent/plugins/poster-plugin/src/components/arrow.js +0 -84
- package/.agent/plugins/poster-plugin/src/components/avatar.js +0 -71
- package/.agent/plugins/poster-plugin/src/components/badge.js +0 -85
- package/.agent/plugins/poster-plugin/src/components/barcode.js +0 -120
- package/.agent/plugins/poster-plugin/src/components/bubble.js +0 -153
- package/.agent/plugins/poster-plugin/src/components/button.js +0 -124
- package/.agent/plugins/poster-plugin/src/components/card.js +0 -88
- package/.agent/plugins/poster-plugin/src/components/chart.js +0 -127
- package/.agent/plugins/poster-plugin/src/components/chip.js +0 -88
- package/.agent/plugins/poster-plugin/src/components/columns.js +0 -107
- package/.agent/plugins/poster-plugin/src/components/cta.js +0 -87
- package/.agent/plugins/poster-plugin/src/components/divider.js +0 -55
- package/.agent/plugins/poster-plugin/src/components/feature.js +0 -85
- package/.agent/plugins/poster-plugin/src/components/featureGrid.js +0 -117
- package/.agent/plugins/poster-plugin/src/components/frame.js +0 -230
- package/.agent/plugins/poster-plugin/src/components/grid.js +0 -118
- package/.agent/plugins/poster-plugin/src/components/highlightText.js +0 -144
- package/.agent/plugins/poster-plugin/src/components/icon.js +0 -94
- package/.agent/plugins/poster-plugin/src/components/imageFrame.js +0 -155
- package/.agent/plugins/poster-plugin/src/components/index.js +0 -81
- package/.agent/plugins/poster-plugin/src/components/listItem.js +0 -147
- package/.agent/plugins/poster-plugin/src/components/notification.js +0 -123
- package/.agent/plugins/poster-plugin/src/components/progress.js +0 -79
- package/.agent/plugins/poster-plugin/src/components/progressCircle.js +0 -117
- package/.agent/plugins/poster-plugin/src/components/qrcode.js +0 -74
- package/.agent/plugins/poster-plugin/src/components/quote.js +0 -97
- package/.agent/plugins/poster-plugin/src/components/rating.js +0 -85
- package/.agent/plugins/poster-plugin/src/components/ribbon.js +0 -193
- package/.agent/plugins/poster-plugin/src/components/seal.js +0 -146
- package/.agent/plugins/poster-plugin/src/components/star.js +0 -70
- package/.agent/plugins/poster-plugin/src/components/statCard.js +0 -105
- package/.agent/plugins/poster-plugin/src/components/stepper.js +0 -118
- package/.agent/plugins/poster-plugin/src/components/table.js +0 -167
- package/.agent/plugins/poster-plugin/src/components/tagCloud.js +0 -85
- package/.agent/plugins/poster-plugin/src/components/timeline.js +0 -117
- package/.agent/plugins/poster-plugin/src/components/watermark.js +0 -52
- package/.agent/plugins/poster-plugin/src/composer.js +0 -2146
- package/.agent/plugins/poster-plugin/src/elements/artText.js +0 -60
- package/.agent/plugins/poster-plugin/src/elements/background.js +0 -84
- package/.agent/plugins/poster-plugin/src/elements/circle.js +0 -31
- package/.agent/plugins/poster-plugin/src/elements/image.js +0 -28
- package/.agent/plugins/poster-plugin/src/elements/index.js +0 -28
- package/.agent/plugins/poster-plugin/src/elements/line.js +0 -23
- package/.agent/plugins/poster-plugin/src/elements/polygon.js +0 -63
- package/.agent/plugins/poster-plugin/src/elements/rectangle.js +0 -32
- package/.agent/plugins/poster-plugin/src/elements/richText.js +0 -230
- package/.agent/plugins/poster-plugin/src/elements/svg.js +0 -108
- package/.agent/plugins/poster-plugin/src/elements/text.js +0 -109
- package/.agent/plugins/poster-plugin/src/fonts.js +0 -243
- package/.agent/plugins/poster-plugin/src/index.js +0 -2081
- package/.agent/plugins/poster-plugin/src/presets.js +0 -36
- package/.agent/plugins/poster-plugin/src/templates/business.js +0 -60
- package/.agent/plugins/poster-plugin/src/templates/gradient.js +0 -64
- package/.agent/plugins/poster-plugin/src/templates/index.js +0 -43
- package/.agent/plugins/poster-plugin/src/templates/modern.js +0 -69
- package/.agent/plugins/poster-plugin/src/templates/simple.js +0 -58
- package/.agent/plugins/poster-plugin/src/templates/social.js +0 -62
- package/.agent/plugins/poster-plugin/src/templates/tech.js +0 -84
- package/.agent/plugins/poster-plugin/src/utils/imageLoader.js +0 -84
- package/.agent/plugins/poster-plugin/test-background.svg +0 -1
- package/.agent/plugins/poster-plugin/test-full-poster.svg +0 -2
- package/.agent/plugins/poster-plugin/test-image.png +0 -0
- package/.agent/plugins/poster-plugin/yarn.lock +0 -1007
- package/output/zen_silence.png +0 -0
package/test-scan.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const { scanPluginNames, resolvePluginPath } = require('./src/utils/plugin-helpers');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
|
|
5
|
+
const pluginsDir = path.join(process.cwd(), '.agent', 'plugins');
|
|
6
|
+
console.log('Plugins directory:', pluginsDir);
|
|
7
|
+
console.log('Exists:', fs.existsSync(pluginsDir));
|
|
8
|
+
|
|
9
|
+
const names = scanPluginNames(pluginsDir);
|
|
10
|
+
console.log('Scanned plugin names:', names);
|
|
11
|
+
|
|
12
|
+
if (names.includes('poster-plugin')) {
|
|
13
|
+
console.log('poster-plugin found!');
|
|
14
|
+
const result = resolvePluginPath(pluginsDir, 'poster-plugin');
|
|
15
|
+
console.log('poster-plugin path resolved:', result);
|
|
16
|
+
} else {
|
|
17
|
+
console.log('poster-plugin NOT found in scan results');
|
|
18
|
+
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: "mnt7jrlt-d67qs7"
|
|
3
|
-
name: "【避免指南】避免在动作参数中使用未正确解析的模板变量"
|
|
4
|
-
type: "feedback"
|
|
5
|
-
project: "null"
|
|
6
|
-
tags: [error, avoid, email, template-variable]
|
|
7
|
-
created: "2026-04-10"
|
|
8
|
-
---
|
|
9
|
-
【下次这样做】在 Ambient Agent 动作参数中使用模板变量时,必须确保变量能正确解析。错误原因:${event.from} 模板变量未被解析为实际邮箱地址 'chnak@yandex.ru',导致 email_auto_reply 工具收到空的 to 参数。
|
|
10
|
-
|
|
11
|
-
【避免方法】
|
|
12
|
-
1. 在动作 args 中使用模板变量时,需检查变量路径是否正确,如 ${event.from} 应解析为发件人邮箱
|
|
13
|
-
2. 对于嵌套在 _eventRaw 中的数据,需使用正确的变量路径(如 ${event._eventRaw.data.email.from})
|
|
14
|
-
3. 建议在动作执行前添加日志或调试步骤验证变量是否正确解析
|
|
15
|
-
4. 对于 email_auto_reply,to 参数必须为有效的邮箱地址字符串,不能是未解析的模板变量
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: "mnt88ja3-al4fuy"
|
|
3
|
-
name: "【避免指南】避免重复启动已运行的服务或资源"
|
|
4
|
-
type: "feedback"
|
|
5
|
-
project: "null"
|
|
6
|
-
tags: [error, avoid, duplicate-operation, state-conflict]
|
|
7
|
-
created: "2026-04-10"
|
|
8
|
-
---
|
|
9
|
-
【下次这样做】在启动服务前应先检查其当前状态。如果服务已在运行,应跳过启动操作或返回明确提示,而非直接调用启动命令。错误原因:重复启动已运行中的邮件监控服务(email_watch),导致状态冲突。建议在启动前调用 status 接口确认服务状态,或确保工具本身实现幂等性。
|
|
@@ -1,304 +0,0 @@
|
|
|
1
|
-
# Poster Plugin - 海报制作插件
|
|
2
|
-
|
|
3
|
-
基于 Paper.js 的海报/Banner 设计插件,支持**组件化**海报生成。
|
|
4
|
-
|
|
5
|
-
## 功能特性
|
|
6
|
-
|
|
7
|
-
- **预设尺寸**:20+ 常用尺寸(海报、Banner、社交媒体)
|
|
8
|
-
- **基础元素**:矩形、圆形、线条、多边形、图片、文字、艺术文字、图片框
|
|
9
|
-
- **布局组件**:分栏布局、网格布局
|
|
10
|
-
- **装饰组件**:星形、箭头、环形进度条、标签、图表、水印、表格
|
|
11
|
-
- **高级组件**:卡片、徽章、CTA按钮、特性展示、特性网格、分隔线、头像、进度条、评分、引用、统计卡、标签云、步骤条、时间线、列表项、通知
|
|
12
|
-
- **组件化生成**:通过 JSON 配置一次性生成完整海报
|
|
13
|
-
- **模板系统**:modern、business、social、simple、tech、gradient 六种预设模板
|
|
14
|
-
|
|
15
|
-
## 工具列表(共 35 个组件)
|
|
16
|
-
|
|
17
|
-
### 画布管理
|
|
18
|
-
| 工具 | 描述 |
|
|
19
|
-
|------|------|
|
|
20
|
-
| `list_poster_presets` | 列出所有预设尺寸 |
|
|
21
|
-
| `create_poster_canvas` | 创建新画布 |
|
|
22
|
-
| `get_poster_canvas_info` | 获取画布信息 |
|
|
23
|
-
| `clear_poster_canvas` | 清除画布 |
|
|
24
|
-
| `export_poster_canvas` | 导出为 PNG 文件 |
|
|
25
|
-
| `export_poster_svg` | 导出为 SVG 矢量图 |
|
|
26
|
-
| `export_poster_base64` | 导出为 Base64 |
|
|
27
|
-
|
|
28
|
-
### 基础元素 (10)
|
|
29
|
-
| 工具 | 描述 |
|
|
30
|
-
|------|------|
|
|
31
|
-
| `add_poster_background` | 添加纯色/渐变背景 |
|
|
32
|
-
| `add_poster_rectangle` | 添加矩形 |
|
|
33
|
-
| `add_poster_circle` | 添加圆形/椭圆 |
|
|
34
|
-
| `add_poster_line` | 添加线条 |
|
|
35
|
-
| `add_poster_polygon` | 添加多边形 |
|
|
36
|
-
| `add_poster_text` | 添加文字 |
|
|
37
|
-
| `add_poster_art_text` | 添加艺术文字(渐变/描边) |
|
|
38
|
-
| `add_poster_image` | 添加图片 |
|
|
39
|
-
| `add_poster_svg` | 添加 SVG 矢量图 |
|
|
40
|
-
| `add_poster_image_frame` | 添加图片框(带装饰边框) |
|
|
41
|
-
|
|
42
|
-
### 布局组件 (2)
|
|
43
|
-
| 工具 | 描述 |
|
|
44
|
-
|------|------|
|
|
45
|
-
| `add_poster_columns` | 分栏布局(左右分栏、多栏) |
|
|
46
|
-
| `add_poster_grid` | 网格布局(任意行列) |
|
|
47
|
-
|
|
48
|
-
### 装饰组件 (7)
|
|
49
|
-
| 工具 | 描述 |
|
|
50
|
-
|------|------|
|
|
51
|
-
| `add_poster_star` | 星形/多角形装饰 |
|
|
52
|
-
| `add_poster_arrow` | 箭头指示 |
|
|
53
|
-
| `add_poster_progress_circle` | 环形进度条 |
|
|
54
|
-
| `add_poster_chip` | 小型标签 |
|
|
55
|
-
| `add_poster_chart` | 图表(柱状图、饼图) |
|
|
56
|
-
| `add_poster_watermark` | 水印文字 |
|
|
57
|
-
| `add_poster_table` | 数据表格 |
|
|
58
|
-
|
|
59
|
-
### 高级组件 (16)
|
|
60
|
-
| 工具 | 描述 |
|
|
61
|
-
|------|------|
|
|
62
|
-
| `add_poster_card` | 卡片组件 |
|
|
63
|
-
| `add_poster_badge` | 徽章/标签 |
|
|
64
|
-
| `add_poster_cta` | CTA 行动号召按钮 |
|
|
65
|
-
| `add_poster_feature` | 特性展示块 |
|
|
66
|
-
| `add_poster_feature_grid` | 特性网格布局 |
|
|
67
|
-
| `add_poster_divider` | 分隔线 |
|
|
68
|
-
| `add_poster_avatar` | 用户头像 |
|
|
69
|
-
| `add_poster_progress` | 线性进度条 |
|
|
70
|
-
| `add_poster_rating` | 星级评分 |
|
|
71
|
-
| `add_poster_quote` | 引用块 |
|
|
72
|
-
| `add_poster_stat_card` | 统计卡片 |
|
|
73
|
-
| `add_poster_tag_cloud` | 标签云 |
|
|
74
|
-
| `add_poster_stepper` | 步骤指示器 |
|
|
75
|
-
| `add_poster_timeline` | 时间线 |
|
|
76
|
-
| `add_poster_list_item` | 列表项 |
|
|
77
|
-
| `add_poster_notification` | 通知提示 |
|
|
78
|
-
|
|
79
|
-
### 组件化生成 & 模板
|
|
80
|
-
| 工具 | 描述 |
|
|
81
|
-
|------|------|
|
|
82
|
-
| `compose_poster` | 使用组件配置生成海报 |
|
|
83
|
-
| `list_poster_components` | 列出可用组件类型 |
|
|
84
|
-
| `generate_poster` | 一键生成海报(6种模板) |
|
|
85
|
-
| `list_poster_templates` | 列出可用模板 |
|
|
86
|
-
|
|
87
|
-
## 预设尺寸
|
|
88
|
-
|
|
89
|
-
| Key | 尺寸 | 名称 |
|
|
90
|
-
|-----|------|------|
|
|
91
|
-
| `poster_a4` | 2480×3508 | A4海报 (300dpi) |
|
|
92
|
-
| `poster_square` | 2000×2000 | 方形海报 |
|
|
93
|
-
| `poster_16_9` | 1920×1080 | 16:9海报 |
|
|
94
|
-
| `poster_9_16` | 1080×1920 | 9:16竖版海报 |
|
|
95
|
-
| `banner_1920x500` | 1920×500 | 网站Banner |
|
|
96
|
-
| `banner_twitter` | 1500×500 | Twitter封面 |
|
|
97
|
-
| `social_instagram` | 1080×1080 | Instagram正方形 |
|
|
98
|
-
| `social_story` | 1080×1920 | Instagram Story |
|
|
99
|
-
| `social_facebook` | 1200×630 | Facebook封面 |
|
|
100
|
-
| `social_linkedin` | 1200×627 | LinkedIn封面 |
|
|
101
|
-
| `social_youtube` | 2560×1440 | YouTube封面 |
|
|
102
|
-
|
|
103
|
-
## 使用示例
|
|
104
|
-
|
|
105
|
-
### 1. 组件化生成(推荐)
|
|
106
|
-
|
|
107
|
-
```javascript
|
|
108
|
-
compose_poster({
|
|
109
|
-
components: [
|
|
110
|
-
// 背景
|
|
111
|
-
{ type: 'background', color: '#1a1a2e' },
|
|
112
|
-
|
|
113
|
-
// 装饰圆形
|
|
114
|
-
{ type: 'circle', cx: 1600, cy: 200, rx: 200, fill: '#00d9ff', opacity: 0.3 },
|
|
115
|
-
|
|
116
|
-
// 星形装饰
|
|
117
|
-
{ type: 'star', cx: 200, cy: 200, points: 5, outerRadius: 60, fill: '#fbbf24' },
|
|
118
|
-
|
|
119
|
-
// 主标题
|
|
120
|
-
{ type: 'artText', text: 'VB-Agent', x: 960, y: 400, fontSize: 120,
|
|
121
|
-
gradient: { colors: ['#00d9ff', '#00ff88'] } },
|
|
122
|
-
|
|
123
|
-
// 环形进度条
|
|
124
|
-
{ type: 'progressCircle', cx: 400, cy: 600, radius: 80, value: 85,
|
|
125
|
-
strokeWidth: 15, fillColor: '#3b82f6', showLabel: true },
|
|
126
|
-
{ type: 'progressCircle', cx: 700, cy: 600, radius: 80, value: 92,
|
|
127
|
-
strokeWidth: 15, fillColor: '#10b981', showLabel: true },
|
|
128
|
-
|
|
129
|
-
// 图表
|
|
130
|
-
{ type: 'chart', type: 'bar', x: 1100, y: 450, width: 400, height: 250,
|
|
131
|
-
data: [
|
|
132
|
-
{ label: '一月', value: 120, color: '#3b82f6' },
|
|
133
|
-
{ label: '二月', value: 90, color: '#10b981' },
|
|
134
|
-
{ label: '三月', value: 150, color: '#f59e0b' }
|
|
135
|
-
],
|
|
136
|
-
showLabels: true, showValues: true },
|
|
137
|
-
|
|
138
|
-
// 数据表格
|
|
139
|
-
{ type: 'table', x: 100, y: 700, width: 800,
|
|
140
|
-
columns: [
|
|
141
|
-
{ title: '功能', width: 300, align: 'left' },
|
|
142
|
-
{ title: '状态', width: 200 },
|
|
143
|
-
{ title: '价格', width: 150 }
|
|
144
|
-
],
|
|
145
|
-
rows: [
|
|
146
|
-
['智能对话', '可用', '免费'],
|
|
147
|
-
['图片生成', '可用', '$29'],
|
|
148
|
-
['代码助手', 'Beta', '免费']
|
|
149
|
-
],
|
|
150
|
-
headerBg: '#1e293b', headerColor: '#ffffff', striped: true },
|
|
151
|
-
|
|
152
|
-
// 标签
|
|
153
|
-
{ type: 'chip', x: 400, y: 850, text: 'AI驱动', background: '#3b82f6', color: '#ffffff' },
|
|
154
|
-
{ type: 'chip', x: 550, y: 850, text: '开源', background: '#10b981', color: '#ffffff' },
|
|
155
|
-
|
|
156
|
-
// 水印
|
|
157
|
-
{ type: 'watermark', text: 'VB-Agent', cx: 960, cy: 1000, fontSize: 200,
|
|
158
|
-
color: 'rgba(255,255,255,0.03)', rotation: -15 },
|
|
159
|
-
|
|
160
|
-
// CTA 按钮
|
|
161
|
-
{ type: 'cta', x: 960, y: 950, text: '立即体验 →',
|
|
162
|
-
background: '#00d9ff', color: '#0a0a0f', fontSize: 24, radius: 30 }
|
|
163
|
-
]
|
|
164
|
-
})
|
|
165
|
-
export_poster_canvas({ filename: 'my-poster', outputDir: '.' })
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
### 2. 基础使用
|
|
169
|
-
|
|
170
|
-
```javascript
|
|
171
|
-
// 创建画布
|
|
172
|
-
create_poster_canvas({ preset: 'poster_square', background: '#1a1a2e' })
|
|
173
|
-
|
|
174
|
-
// 添加元素
|
|
175
|
-
add_poster_circle({ cx: 500, cy: 500, rx: 100, fill: '#00d9ff' })
|
|
176
|
-
add_poster_text({ text: 'Hello Foliko', x: 500, y: 600, fontSize: 48, color: '#ffffff', align: 'center' })
|
|
177
|
-
|
|
178
|
-
// 导出
|
|
179
|
-
export_poster_canvas({ filename: 'my-poster' })
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
## 新增组件详解
|
|
183
|
-
|
|
184
|
-
### 星形 (star)
|
|
185
|
-
```javascript
|
|
186
|
-
add_poster_star({
|
|
187
|
-
cx: 200, cy: 200, // 中心坐标
|
|
188
|
-
points: 5, // 星形点数
|
|
189
|
-
outerRadius: 60, // 外半径
|
|
190
|
-
fill: '#fbbf24', // 填充颜色
|
|
191
|
-
rotation: 0 // 旋转角度
|
|
192
|
-
})
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
### 环形进度条 (progressCircle)
|
|
196
|
-
```javascript
|
|
197
|
-
add_poster_progress_circle({
|
|
198
|
-
cx: 200, cy: 200, // 圆心坐标
|
|
199
|
-
radius: 80, // 圆环半径
|
|
200
|
-
value: 75, // 进度值 0-100
|
|
201
|
-
strokeWidth: 15, // 环宽度
|
|
202
|
-
trackColor: '#e5e7eb', // 轨道颜色
|
|
203
|
-
fillColor: '#3b82f6', // 进度颜色
|
|
204
|
-
backgroundColor: '#ffffff', // 背景填充
|
|
205
|
-
showLabel: true // 显示百分比
|
|
206
|
-
})
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
### 图表 (chart)
|
|
210
|
-
```javascript
|
|
211
|
-
// 柱状图
|
|
212
|
-
add_poster_chart({
|
|
213
|
-
type: 'bar', // bar 或 pie
|
|
214
|
-
x: 100, y: 300,
|
|
215
|
-
width: 500, height: 250,
|
|
216
|
-
data: [
|
|
217
|
-
{ label: '一月', value: 120, color: '#3b82f6' },
|
|
218
|
-
{ label: '二月', value: 90, color: '#10b981' }
|
|
219
|
-
],
|
|
220
|
-
showLabels: true,
|
|
221
|
-
showValues: true
|
|
222
|
-
})
|
|
223
|
-
|
|
224
|
-
// 饼图
|
|
225
|
-
add_poster_chart({
|
|
226
|
-
type: 'pie',
|
|
227
|
-
x: 700, y: 300,
|
|
228
|
-
width: 250, height: 250,
|
|
229
|
-
data: [
|
|
230
|
-
{ label: 'A', value: 45, color: '#3b82f6' },
|
|
231
|
-
{ label: 'B', value: 35, color: '#10b981' },
|
|
232
|
-
{ label: 'C', value: 20, color: '#f59e0b' }
|
|
233
|
-
],
|
|
234
|
-
showLabels: true
|
|
235
|
-
})
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
### 表格 (table)
|
|
239
|
-
```javascript
|
|
240
|
-
add_poster_table({
|
|
241
|
-
x: 100, y: 400,
|
|
242
|
-
width: 800,
|
|
243
|
-
columns: [
|
|
244
|
-
{ title: '功能', width: 300, align: 'left' },
|
|
245
|
-
{ title: '状态', width: 200 }
|
|
246
|
-
],
|
|
247
|
-
rows: [
|
|
248
|
-
['智能对话', '可用'],
|
|
249
|
-
['代码助手', 'Beta']
|
|
250
|
-
],
|
|
251
|
-
headerBg: '#1e293b',
|
|
252
|
-
headerColor: '#ffffff',
|
|
253
|
-
striped: true
|
|
254
|
-
})
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
### 标签 (chip)
|
|
258
|
-
```javascript
|
|
259
|
-
add_poster_chip({
|
|
260
|
-
x: 200, y: 300,
|
|
261
|
-
text: 'NEW', // 标签文字
|
|
262
|
-
background: '#ef4444', // 背景色
|
|
263
|
-
color: '#ffffff', // 文字颜色
|
|
264
|
-
fontSize: 14,
|
|
265
|
-
radius: 16, // 圆角
|
|
266
|
-
icon: '⭐' // 前置图标(可选)
|
|
267
|
-
})
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
## 项目结构
|
|
271
|
-
|
|
272
|
-
```
|
|
273
|
-
poster-plugin/
|
|
274
|
-
├── index.js # 插件入口
|
|
275
|
-
├── package.json # 包配置
|
|
276
|
-
├── README.md # 文档
|
|
277
|
-
├── src/
|
|
278
|
-
│ ├── index.js # 主模块
|
|
279
|
-
│ ├── canvas.js # 画布管理器
|
|
280
|
-
│ ├── presets.js # 预设尺寸
|
|
281
|
-
│ ├── fonts.js # 字体管理
|
|
282
|
-
│ ├── composer.js # 组件化生成器
|
|
283
|
-
│ ├── elements/ # 基础元素
|
|
284
|
-
│ ├── components/ # 高级组件
|
|
285
|
-
│ └── templates/ # 模板
|
|
286
|
-
└── fonts/ # 字体文件
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
## 更新日志
|
|
290
|
-
|
|
291
|
-
### v1.2.0
|
|
292
|
-
- 新增布局组件:columns(分栏)、grid(网格)
|
|
293
|
-
- 新增装饰组件:star(星形)、arrow(箭头)、progressCircle(环形进度条)
|
|
294
|
-
- 新增 chip(标签)、chart(图表)、watermark(水印)、table(表格)
|
|
295
|
-
- 新增 imageFrame(图片框)
|
|
296
|
-
- 组件总数达到 **35 个**
|
|
297
|
-
- 模板新增 tech(科技)、gradient(渐变)
|
|
298
|
-
- 修复环形进度条绘制逻辑
|
|
299
|
-
|
|
300
|
-
### v1.1.0
|
|
301
|
-
- 重构为模块化架构
|
|
302
|
-
- 新增组件化海报生成(compose_poster)
|
|
303
|
-
- 新增高级组件:card, badge, cta, feature, featureGrid, divider
|
|
304
|
-
- 新增组件:avatar, progress, rating, quote, statCard, tagCloud, stepper, timeline, listItem, notification
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
404: Not Found
|
|
Binary file
|
|
Binary file
|
package/.agent/plugins/poster-plugin/fonts//345/276/256/350/275/257/351/233/205/351/273/221.ttf
DELETED
|
Binary file
|
|
Binary file
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Poster Plugin - 海报制作插件
|
|
3
|
-
*
|
|
4
|
-
* 模块化架构,支持组件化海报生成
|
|
5
|
-
*
|
|
6
|
-
* 使用方法:
|
|
7
|
-
* 1. 基础元素:add_poster_rectangle, add_poster_circle, add_poster_text 等
|
|
8
|
-
* 2. 高级组件:add_poster_card, add_poster_badge, add_poster_cta 等
|
|
9
|
-
* 3. 组件化生成:compose_poster - 通过配置 JSON 一次性生成海报
|
|
10
|
-
* 4. 模板生成:generate_poster - 一键使用预设模板
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
module.exports = require('./src/index.js')
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "poster-plugin",
|
|
3
|
-
"version": "1.2.0",
|
|
4
|
-
"description": "海报/Banner 设计插件 - 基于 Paper.js 实现,支持 35 个组件",
|
|
5
|
-
"main": "index.js",
|
|
6
|
-
"dependencies": {
|
|
7
|
-
"canvas": "^3.2.0",
|
|
8
|
-
"fontkit": "^2.0.4",
|
|
9
|
-
"jsdom": "^16.2.2",
|
|
10
|
-
"paper": "^0.12.18",
|
|
11
|
-
"qrcode": "^1.5.4"
|
|
12
|
-
},
|
|
13
|
-
"overrides": {
|
|
14
|
-
"canvas": "^3.2.0"
|
|
15
|
-
},
|
|
16
|
-
"resolutions": {
|
|
17
|
-
"**/canvas": "^3.2.0"
|
|
18
|
-
},
|
|
19
|
-
"author": "",
|
|
20
|
-
"license": "MIT",
|
|
21
|
-
"keywords": [
|
|
22
|
-
"poster",
|
|
23
|
-
"banner",
|
|
24
|
-
"design",
|
|
25
|
-
"canvas",
|
|
26
|
-
"paper.js",
|
|
27
|
-
"foliko"
|
|
28
|
-
]
|
|
29
|
-
}
|
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 画布管理模块
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
const paper = require('paper')
|
|
6
|
-
const PRESETS = require('./presets')
|
|
7
|
-
const fs = require('fs')
|
|
8
|
-
const path = require('path')
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* 画布管理器类
|
|
12
|
-
*/
|
|
13
|
-
class CanvasManager {
|
|
14
|
-
constructor() {
|
|
15
|
-
this._canvas = null
|
|
16
|
-
this._project = null
|
|
17
|
-
this._paper = null
|
|
18
|
-
this._width = 0
|
|
19
|
-
this._height = 0
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* 创建画布
|
|
24
|
-
*/
|
|
25
|
-
async create({ preset, width, height, background }) {
|
|
26
|
-
let w, h
|
|
27
|
-
|
|
28
|
-
if (preset) {
|
|
29
|
-
const presetConfig = PRESETS[preset]
|
|
30
|
-
if (!presetConfig) {
|
|
31
|
-
throw new Error(`Unknown preset: ${preset}. Available: ${Object.keys(PRESETS).join(', ')}`)
|
|
32
|
-
}
|
|
33
|
-
w = presetConfig.width
|
|
34
|
-
h = presetConfig.height
|
|
35
|
-
} else if (width && height) {
|
|
36
|
-
w = width
|
|
37
|
-
h = height
|
|
38
|
-
} else {
|
|
39
|
-
throw new Error('Must provide preset or width/height')
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
this._canvas = paper.createCanvas(w, h)
|
|
43
|
-
this._project = new paper.Project(this._canvas)
|
|
44
|
-
// 确保活动层存在
|
|
45
|
-
if (!paper.project || !paper.project.activeLayer) {
|
|
46
|
-
paper.setup(this._canvas)
|
|
47
|
-
}
|
|
48
|
-
this._paper = paper
|
|
49
|
-
this._width = w
|
|
50
|
-
this._height = h
|
|
51
|
-
|
|
52
|
-
// 添加背景
|
|
53
|
-
if (background) {
|
|
54
|
-
if (typeof background === 'string' && path.isAbsolute(background)) {
|
|
55
|
-
// 背景是绝对路径图片
|
|
56
|
-
await this._addBackgroundImage(background, w, h)
|
|
57
|
-
} else if (typeof background === 'object' && background.image) {
|
|
58
|
-
// 背景是对象形式 { image: 'path' }
|
|
59
|
-
await this._addBackgroundImage(background.image, w, h)
|
|
60
|
-
} else {
|
|
61
|
-
// 背景是颜色
|
|
62
|
-
const bg = new paper.Path.Rectangle({
|
|
63
|
-
point: [0, 0],
|
|
64
|
-
size: [w, h],
|
|
65
|
-
fillColor: background,
|
|
66
|
-
})
|
|
67
|
-
bg.sendToBack()
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return {
|
|
72
|
-
width: w,
|
|
73
|
-
height: h,
|
|
74
|
-
preset: preset || 'custom',
|
|
75
|
-
background: background || null,
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* 添加背景图片
|
|
81
|
-
*/
|
|
82
|
-
async _addBackgroundImage(imageSrc, w, h) {
|
|
83
|
-
// 本地文件路径
|
|
84
|
-
let absolutePath = imageSrc
|
|
85
|
-
if (!path.isAbsolute(absolutePath)) {
|
|
86
|
-
absolutePath = path.join(process.cwd(), absolutePath)
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (!fs.existsSync(absolutePath)) {
|
|
90
|
-
throw new Error(`背景图片文件不存在: ${absolutePath}`)
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// 使用 loadImage 获取图片数据
|
|
94
|
-
const { loadImage } = require('canvas')
|
|
95
|
-
const imageData = await loadImage(absolutePath)
|
|
96
|
-
|
|
97
|
-
// 创建 Paper.js Raster
|
|
98
|
-
const raster = new paper.Raster(imageData)
|
|
99
|
-
|
|
100
|
-
// 等待 raster 加载完成
|
|
101
|
-
await new Promise((resolve) => {
|
|
102
|
-
if (raster.loaded) {
|
|
103
|
-
resolve()
|
|
104
|
-
} else {
|
|
105
|
-
raster.onLoad = resolve
|
|
106
|
-
}
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
// 计算 cover 模式缩放
|
|
110
|
-
const canvasRatio = w / h
|
|
111
|
-
const imageRatio = raster.width / raster.height
|
|
112
|
-
|
|
113
|
-
let scaledWidth, scaledHeight, offsetX, offsetY
|
|
114
|
-
|
|
115
|
-
if (imageRatio > canvasRatio) {
|
|
116
|
-
scaledHeight = h
|
|
117
|
-
scaledWidth = raster.width * (h / raster.height)
|
|
118
|
-
offsetX = (w - scaledWidth) / 2
|
|
119
|
-
offsetY = 0
|
|
120
|
-
} else {
|
|
121
|
-
scaledWidth = w
|
|
122
|
-
scaledHeight = raster.height * (w / raster.width)
|
|
123
|
-
offsetX = 0
|
|
124
|
-
offsetY = (h - scaledHeight) / 2
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
raster.bounds = new paper.Rectangle(offsetX, offsetY, scaledWidth, scaledHeight)
|
|
128
|
-
raster.sendToBack()
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* 获取画布
|
|
133
|
-
*/
|
|
134
|
-
getCanvas() {
|
|
135
|
-
return this._canvas
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* 获取 Paper.js 项目
|
|
140
|
-
*/
|
|
141
|
-
getProject() {
|
|
142
|
-
return this._project
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* 获取画布尺寸
|
|
147
|
-
*/
|
|
148
|
-
getSize() {
|
|
149
|
-
return { width: this._width, height: this._height }
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* 获取中心点
|
|
154
|
-
*/
|
|
155
|
-
getCenter() {
|
|
156
|
-
return { x: this._width / 2, y: this._height / 2 }
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* 清除画布
|
|
161
|
-
*/
|
|
162
|
-
clear() {
|
|
163
|
-
if (this._project) {
|
|
164
|
-
this._project.activeLayer.removeChildren()
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* 获取元素数量
|
|
170
|
-
*/
|
|
171
|
-
getElementCount() {
|
|
172
|
-
return this._project ? this._project.activeLayer.children.length : 0
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* 导出为 Buffer
|
|
177
|
-
*/
|
|
178
|
-
toBuffer(format = 'png', quality) {
|
|
179
|
-
if (!this._canvas) {
|
|
180
|
-
throw new Error('No canvas created')
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
this._project.view.update()
|
|
184
|
-
this._project.view.draw()
|
|
185
|
-
|
|
186
|
-
const mimeType = format === 'jpg' ? 'image/jpeg' : 'image/png'
|
|
187
|
-
return this._canvas.toBuffer(mimeType, quality)
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* 导出为 Base64
|
|
192
|
-
*/
|
|
193
|
-
toBase64(format = 'png', quality) {
|
|
194
|
-
if (!this._canvas) {
|
|
195
|
-
throw new Error('No canvas created')
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
this._project.view.update()
|
|
199
|
-
this._project.view.draw()
|
|
200
|
-
|
|
201
|
-
const mimeType = format === 'jpg' ? 'image/jpeg' : 'image/png'
|
|
202
|
-
return this._canvas.toDataURL(mimeType, quality)
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* 检查画布是否已创建
|
|
207
|
-
*/
|
|
208
|
-
isCreated() {
|
|
209
|
-
return this._canvas !== null
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* 重置画布
|
|
214
|
-
*/
|
|
215
|
-
reset() {
|
|
216
|
-
this._canvas = null
|
|
217
|
-
this._project = null
|
|
218
|
-
this._paper = null
|
|
219
|
-
this._width = 0
|
|
220
|
-
this._height = 0
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
module.exports = CanvasManager
|