foliko 1.0.87 → 1.1.1

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.
Files changed (259) hide show
  1. package/.agent/.shared/ui-ux-pro-max/data/charts.csv +26 -0
  2. package/.agent/.shared/ui-ux-pro-max/data/colors.csv +97 -0
  3. package/.agent/.shared/ui-ux-pro-max/data/icons.csv +101 -0
  4. package/.agent/.shared/ui-ux-pro-max/data/landing.csv +31 -0
  5. package/.agent/.shared/ui-ux-pro-max/data/products.csv +97 -0
  6. package/.agent/.shared/ui-ux-pro-max/data/prompts.csv +24 -0
  7. package/.agent/.shared/ui-ux-pro-max/data/react-performance.csv +45 -0
  8. package/.agent/.shared/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  9. package/.agent/.shared/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  10. package/.agent/.shared/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  11. package/.agent/.shared/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  12. package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  13. package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  14. package/.agent/.shared/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  15. package/.agent/.shared/ui-ux-pro-max/data/stacks/react.csv +54 -0
  16. package/.agent/.shared/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  17. package/.agent/.shared/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  18. package/.agent/.shared/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  19. package/.agent/.shared/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  20. package/.agent/.shared/ui-ux-pro-max/data/styles.csv +59 -0
  21. package/.agent/.shared/ui-ux-pro-max/data/typography.csv +58 -0
  22. package/.agent/.shared/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  23. package/.agent/.shared/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  24. package/.agent/.shared/ui-ux-pro-max/data/web-interface.csv +31 -0
  25. package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/core.cpython-313.pyc +0 -0
  26. package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-313.pyc +0 -0
  27. package/.agent/.shared/ui-ux-pro-max/scripts/core.py +258 -0
  28. package/.agent/.shared/ui-ux-pro-max/scripts/design_system.py +1067 -0
  29. package/.agent/.shared/ui-ux-pro-max/scripts/search.py +106 -0
  30. package/.agent/ARCHITECTURE.md +288 -0
  31. package/.agent/agents/ambient-agent.md +57 -0
  32. package/.agent/agents/debugger.md +55 -0
  33. package/.agent/agents/email-assistant.md +49 -0
  34. package/.agent/agents/file-manager.md +42 -0
  35. package/.agent/agents/python-developer.md +60 -0
  36. package/.agent/agents/scheduler.md +59 -0
  37. package/.agent/agents/web-developer.md +45 -0
  38. package/.agent/data/default.json +325 -21
  39. package/.agent/data/plugins-state.json +194 -162
  40. package/.agent/data/puppeteer-sessions/undefined.json +6 -0
  41. package/.agent/mcp_config.json +0 -1
  42. package/.agent/mcp_config_updated.json +12 -0
  43. package/.agent/plugins/poster-plugin/README.md +304 -0
  44. package/.agent/plugins/poster-plugin/fonts/NotoColorEmoji-Regular.ttf +0 -0
  45. package/.agent/plugins/poster-plugin/fonts/PatuaOne-Regular.ttf +0 -0
  46. package/.agent/plugins/poster-plugin/fonts//345/276/256/350/275/257/351/233/205/351/273/221.ttf +0 -0
  47. 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
  48. package/.agent/plugins/poster-plugin/index.js +13 -0
  49. package/.agent/plugins/poster-plugin/package.json +28 -0
  50. package/.agent/plugins/poster-plugin/src/canvas.js +161 -0
  51. package/.agent/plugins/poster-plugin/src/components/arrow.js +84 -0
  52. package/.agent/plugins/poster-plugin/src/components/avatar.js +71 -0
  53. package/.agent/plugins/poster-plugin/src/components/badge.js +85 -0
  54. package/.agent/plugins/poster-plugin/src/components/card.js +88 -0
  55. package/.agent/plugins/poster-plugin/src/components/chart.js +127 -0
  56. package/.agent/plugins/poster-plugin/src/components/chip.js +88 -0
  57. package/.agent/plugins/poster-plugin/src/components/columns.js +107 -0
  58. package/.agent/plugins/poster-plugin/src/components/cta.js +85 -0
  59. package/.agent/plugins/poster-plugin/src/components/divider.js +55 -0
  60. package/.agent/plugins/poster-plugin/src/components/feature.js +85 -0
  61. package/.agent/plugins/poster-plugin/src/components/featureGrid.js +112 -0
  62. package/.agent/plugins/poster-plugin/src/components/grid.js +118 -0
  63. package/.agent/plugins/poster-plugin/src/components/imageFrame.js +155 -0
  64. package/.agent/plugins/poster-plugin/src/components/index.js +62 -0
  65. package/.agent/plugins/poster-plugin/src/components/listItem.js +146 -0
  66. package/.agent/plugins/poster-plugin/src/components/notification.js +123 -0
  67. package/.agent/plugins/poster-plugin/src/components/progress.js +79 -0
  68. package/.agent/plugins/poster-plugin/src/components/progressCircle.js +117 -0
  69. package/.agent/plugins/poster-plugin/src/components/quote.js +97 -0
  70. package/.agent/plugins/poster-plugin/src/components/rating.js +85 -0
  71. package/.agent/plugins/poster-plugin/src/components/star.js +70 -0
  72. package/.agent/plugins/poster-plugin/src/components/statCard.js +105 -0
  73. package/.agent/plugins/poster-plugin/src/components/stepper.js +118 -0
  74. package/.agent/plugins/poster-plugin/src/components/table.js +159 -0
  75. package/.agent/plugins/poster-plugin/src/components/tagCloud.js +78 -0
  76. package/.agent/plugins/poster-plugin/src/components/timeline.js +105 -0
  77. package/.agent/plugins/poster-plugin/src/components/watermark.js +52 -0
  78. package/.agent/plugins/poster-plugin/src/composer.js +1904 -0
  79. package/.agent/plugins/poster-plugin/src/elements/artText.js +60 -0
  80. package/.agent/plugins/poster-plugin/src/elements/background.js +52 -0
  81. package/.agent/plugins/poster-plugin/src/elements/circle.js +31 -0
  82. package/.agent/plugins/poster-plugin/src/elements/image.js +71 -0
  83. package/.agent/plugins/poster-plugin/src/elements/index.js +26 -0
  84. package/.agent/plugins/poster-plugin/src/elements/line.js +23 -0
  85. package/.agent/plugins/poster-plugin/src/elements/polygon.js +63 -0
  86. package/.agent/plugins/poster-plugin/src/elements/rectangle.js +32 -0
  87. package/.agent/plugins/poster-plugin/src/elements/svg.js +92 -0
  88. package/.agent/plugins/poster-plugin/src/elements/text.js +107 -0
  89. package/.agent/plugins/poster-plugin/src/fonts.js +233 -0
  90. package/.agent/plugins/poster-plugin/src/index.js +1658 -0
  91. package/.agent/plugins/poster-plugin/src/presets.js +36 -0
  92. package/.agent/plugins/poster-plugin/src/templates/business.js +60 -0
  93. package/.agent/plugins/poster-plugin/src/templates/gradient.js +64 -0
  94. package/.agent/plugins/poster-plugin/src/templates/index.js +43 -0
  95. package/.agent/plugins/poster-plugin/src/templates/modern.js +69 -0
  96. package/.agent/plugins/poster-plugin/src/templates/simple.js +58 -0
  97. package/.agent/plugins/poster-plugin/src/templates/social.js +62 -0
  98. package/.agent/plugins/poster-plugin/src/templates/tech.js +84 -0
  99. package/.agent/plugins/{temp-repo/puppeteer-plugin → puppeteer-plugin}/index.js +1 -1
  100. package/.agent/plugins.json +5 -11
  101. package/.agent/rules/GEMINI.md +273 -0
  102. package/.agent/rules/allow-rule.md +77 -0
  103. package/.agent/rules/log-rule.md +83 -0
  104. package/.agent/rules/security-rule.md +93 -0
  105. package/.agent/scripts/auto_preview.py +148 -0
  106. package/.agent/scripts/checklist.py +217 -0
  107. package/.agent/scripts/session_manager.py +120 -0
  108. package/.agent/scripts/verify_all.py +327 -0
  109. package/.agent/sessions/cli_default.json +419 -0
  110. package/.agent/sessions/weixin_o9cq80zgZqKPA2-s59PN43GdDy1w@im.wechat.json +2195 -0
  111. package/.agent/skills/api-patterns/SKILL.md +81 -0
  112. package/.agent/skills/api-patterns/api-style.md +42 -0
  113. package/.agent/skills/api-patterns/auth.md +24 -0
  114. package/.agent/skills/api-patterns/documentation.md +26 -0
  115. package/.agent/skills/api-patterns/graphql.md +41 -0
  116. package/.agent/skills/api-patterns/rate-limiting.md +31 -0
  117. package/.agent/skills/api-patterns/response.md +37 -0
  118. package/.agent/skills/api-patterns/rest.md +40 -0
  119. package/.agent/skills/api-patterns/scripts/api_validator.py +211 -0
  120. package/.agent/skills/api-patterns/security-testing.md +122 -0
  121. package/.agent/skills/api-patterns/trpc.md +41 -0
  122. package/.agent/skills/api-patterns/versioning.md +22 -0
  123. package/.agent/skills/app-builder/SKILL.md +75 -0
  124. package/.agent/skills/app-builder/agent-coordination.md +71 -0
  125. package/.agent/skills/app-builder/feature-building.md +53 -0
  126. package/.agent/skills/app-builder/project-detection.md +34 -0
  127. package/.agent/skills/app-builder/scaffolding.md +118 -0
  128. package/.agent/skills/app-builder/tech-stack.md +40 -0
  129. package/.agent/skills/app-builder/templates/SKILL.md +39 -0
  130. package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +76 -0
  131. package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +92 -0
  132. package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +88 -0
  133. package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +88 -0
  134. package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +83 -0
  135. package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +90 -0
  136. package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +90 -0
  137. package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +122 -0
  138. package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +122 -0
  139. package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +169 -0
  140. package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +134 -0
  141. package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +83 -0
  142. package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +119 -0
  143. package/.agent/skills/architecture/SKILL.md +55 -0
  144. package/.agent/skills/architecture/context-discovery.md +43 -0
  145. package/.agent/skills/architecture/examples.md +94 -0
  146. package/.agent/skills/architecture/pattern-selection.md +68 -0
  147. package/.agent/skills/architecture/patterns-reference.md +50 -0
  148. package/.agent/skills/architecture/trade-off-analysis.md +77 -0
  149. package/.agent/skills/clean-code/SKILL.md +201 -0
  150. package/.agent/skills/doc.md +177 -0
  151. package/.agent/skills/frontend-design/SKILL.md +418 -0
  152. package/.agent/skills/frontend-design/animation-guide.md +331 -0
  153. package/.agent/skills/frontend-design/color-system.md +311 -0
  154. package/.agent/skills/frontend-design/decision-trees.md +418 -0
  155. package/.agent/skills/frontend-design/motion-graphics.md +306 -0
  156. package/.agent/skills/frontend-design/scripts/accessibility_checker.py +183 -0
  157. package/.agent/skills/frontend-design/scripts/ux_audit.py +722 -0
  158. package/.agent/skills/frontend-design/typography-system.md +345 -0
  159. package/.agent/skills/frontend-design/ux-psychology.md +1116 -0
  160. package/.agent/skills/frontend-design/visual-effects.md +383 -0
  161. package/.agent/skills/i18n-localization/SKILL.md +154 -0
  162. package/.agent/skills/i18n-localization/scripts/i18n_checker.py +241 -0
  163. package/.agent/skills/mcp-builder/SKILL.md +176 -0
  164. package/.agent/skills/web-design-guidelines/SKILL.md +57 -0
  165. package/.agent/workflows/brainstorm.md +113 -0
  166. package/.agent/workflows/create.md +59 -0
  167. package/.agent/workflows/debug.md +103 -0
  168. package/.agent/workflows/deploy.md +176 -0
  169. package/.agent/workflows/enhance.md +63 -0
  170. package/.agent/workflows/orchestrate.md +237 -0
  171. package/.agent/workflows/plan.md +89 -0
  172. package/.agent/workflows/preview.md +81 -0
  173. package/.agent/workflows/simple-test.md +42 -0
  174. package/.agent/workflows/status.md +86 -0
  175. package/.agent/workflows/structured-orchestrate.md +180 -0
  176. package/.agent/workflows/test.md +144 -0
  177. package/.agent/workflows/ui-ux-pro-max.md +296 -0
  178. package/.claude/settings.local.json +20 -8
  179. package/.env.example +56 -56
  180. package/CLAUDE.md +144 -108
  181. package/README.md +441 -441
  182. package/calc_tokens_weixin.js +81 -0
  183. package/cli/src/commands/chat.js +2 -1
  184. package/docs/CONTEXT_DESIGN.md +1596 -0
  185. package/examples/test-concurrent-chat.js +60 -60
  186. package/foliko-creative-3.png +0 -0
  187. package/foliko-creative-4.png +0 -0
  188. package/foliko-creative-5.png +0 -0
  189. package/package.json +2 -2
  190. package/plugins/default-plugins.js +2 -1
  191. package/plugins/extension-executor-plugin.js +91 -2
  192. package/plugins/file-system-plugin.js +2 -2
  193. package/plugins/memory-plugin.js +984 -0
  194. package/plugins/session-plugin.js +57 -1
  195. package/plugins/weixin-plugin.js +33 -23
  196. package/skills/find-skills/AGENTS.md +162 -162
  197. package/skills/find-skills/SKILL.md +133 -133
  198. package/skills/poster-guide/SKILL.md +1059 -0
  199. package/skills/python-plugin-dev/SKILL.md +238 -238
  200. package/skills/skill-guide/SKILL.md +130 -108
  201. package/src/capabilities/skill-manager.js +99 -0
  202. package/src/core/agent-chat.js +620 -141
  203. package/src/core/agent-context.js +188 -0
  204. package/src/core/agent.js +6 -2
  205. package/src/core/context-manager.js +283 -0
  206. package/src/core/framework.js +264 -3
  207. package/src/core/plugin-manager.js +79 -2
  208. package/src/core/request-context.js +98 -0
  209. package/src/core/session-context.js +341 -0
  210. package/src/core/session-storage.js +274 -0
  211. package/src/executors/mcp-executor.js +2 -2
  212. package/src/utils/index.js +239 -67
  213. package/src/utils/plugin-helpers.js +17 -0
  214. package/story-cover-book-v2.png +0 -0
  215. package/story-cover-japanese-1.png +0 -0
  216. package/story-cover-japanese-2.png +0 -0
  217. package/story-cover-japanese-3.png +0 -0
  218. package/story-cover-moran.png +0 -0
  219. package/undefined.png +0 -0
  220. package//346/265/267/346/212/245/346/217/222/344/273/266.md +621 -0
  221. package/.agent/agents/code-assistant.json +0 -14
  222. package/.agent/agents/email-assistant.json +0 -14
  223. package/.agent/agents/file-assistant.json +0 -15
  224. package/.agent/agents/system-assistant.json +0 -15
  225. package/.agent/agents/web-assistant.json +0 -12
  226. package/.agent/data/ambient/goals.json +0 -50
  227. package/.agent/data/ambient/memories.json +0 -7
  228. package/.agent/data/scheduler/tasks.json +0 -1
  229. package/.agent/package.json +0 -8
  230. package/.agent/plugins/__pycache__/test_plugin.cpython-312.pyc +0 -0
  231. package/.agent/plugins/daytona/README.md +0 -89
  232. package/.agent/plugins/daytona/index.js +0 -377
  233. package/.agent/plugins/daytona/package.json +0 -12
  234. package/.agent/plugins/marknative/README.md +0 -134
  235. package/.agent/plugins/marknative/index.js +0 -228
  236. package/.agent/plugins/marknative/package.json +0 -12
  237. package/.agent/plugins/marknative/update-readme.js +0 -134
  238. package/.agent/plugins/system-info/index.js +0 -387
  239. package/.agent/plugins/system-info/package.json +0 -4
  240. package/.agent/plugins/system-info/test.js +0 -40
  241. package/.agent/plugins/temp-repo/LICENSE +0 -201
  242. package/.agent/plugins/test_plugin.py +0 -304
  243. package/.agent/python-scripts/test_sample.py +0 -24
  244. package/.agent/skills/agent-browser/SKILL.md +0 -311
  245. package/.agent/skills/agent-browser/TEST_PLAN.md +0 -200
  246. package/.agent/skills/sysinfo/SKILL.md +0 -38
  247. package/.agent/skills/sysinfo/system-info.sh +0 -130
  248. package/.agent/skills/workflow/SKILL.md +0 -324
  249. package/.agent/workflows/email-digest.json +0 -50
  250. package/.agent/workflows/file-backup.json +0 -21
  251. package/.agent/workflows/get-ip-notify.json +0 -32
  252. package/.agent/workflows/news-aggregator.json +0 -93
  253. package/.agent/workflows/news-dashboard-v2.json +0 -94
  254. package/.agent/workflows/notification-batch.json +0 -32
  255. package/examples/test-chat-debug.js +0 -102
  256. package/examples/test-chat-result.js +0 -76
  257. package/examples/test-chat-stream-diff.js +0 -63
  258. /package/.agent/plugins/{temp-repo/puppeteer-plugin → puppeteer-plugin}/README.md +0 -0
  259. /package/.agent/plugins/{temp-repo/puppeteer-plugin → puppeteer-plugin}/package.json +0 -0
@@ -0,0 +1,60 @@
1
+ /**
2
+ * 艺术文字元素
3
+ */
4
+
5
+ const paper = require('paper')
6
+ const { validateFont, getDefaultFont } = require('../fonts')
7
+
8
+ /**
9
+ * 添加艺术文字
10
+ */
11
+ function addArtText(project, args) {
12
+ const {
13
+ text,
14
+ x, y,
15
+ fontSize,
16
+ fontFamily,
17
+ gradient,
18
+ strokeColor,
19
+ strokeWidth,
20
+ shadow,
21
+ } = args
22
+
23
+ const textItem = new paper.PointText({
24
+ point: [x, y],
25
+ content: text,
26
+ fontSize: fontSize || 120,
27
+ fontFamily: validateFont(fontFamily) || getDefaultFont(),
28
+ fillColor: gradient
29
+ ? new paper.Color(gradient.colors[0])
30
+ : new paper.Color('#ffffff'),
31
+ justification: 'center',
32
+ })
33
+
34
+ // 应用渐变
35
+ if (gradient && gradient.colors.length > 0) {
36
+ const colors = gradient.colors.map(c => new paper.Color(c))
37
+ textItem.fillColor = new paper.Color({
38
+ gradient: { stops: colors },
39
+ origin: textItem.bounds.topLeft,
40
+ destination: textItem.bounds.topRight,
41
+ })
42
+ }
43
+
44
+ // 应用描边
45
+ if (strokeColor) {
46
+ textItem.strokeColor = new paper.Color(strokeColor)
47
+ textItem.strokeWidth = strokeWidth || 2
48
+ }
49
+
50
+ // 应用阴影
51
+ if (shadow) {
52
+ textItem.shadowColor = new paper.Color(shadow.color)
53
+ textItem.shadowBlur = shadow.blur || 10
54
+ textItem.shadowOffset = new paper.Point(shadow.offsetX || 3, shadow.offsetY || 3)
55
+ }
56
+
57
+ return { success: true, id: textItem.id, type: 'artText' }
58
+ }
59
+
60
+ module.exports = addArtText
@@ -0,0 +1,52 @@
1
+ /**
2
+ * 背景元素
3
+ */
4
+
5
+ const paper = require('paper')
6
+
7
+ /**
8
+ * 添加背景
9
+ */
10
+ function addBackground(project, canvas, args) {
11
+ const { color, gradient } = args
12
+
13
+ if (gradient) {
14
+ const { type, colors, direction } = gradient
15
+ const paperColors = colors.map(c => new paper.Color(c))
16
+
17
+ if (type === 'linear') {
18
+ const angle = (direction || 45) * Math.PI / 180
19
+ const diagonal = Math.sqrt(canvas.width ** 2 + canvas.height ** 2)
20
+ const start = new paper.Point(
21
+ canvas.width / 2 - Math.cos(angle) * diagonal / 2,
22
+ canvas.height / 2 - Math.sin(angle) * diagonal / 2
23
+ )
24
+ const stop = new paper.Point(
25
+ canvas.width / 2 + Math.cos(angle) * diagonal / 2,
26
+ canvas.height / 2 + Math.sin(angle) * diagonal / 2
27
+ )
28
+ project.activeLayer.fillColor = new paper.Color({
29
+ gradient: { stops: paperColors },
30
+ origin: start,
31
+ destination: stop,
32
+ })
33
+ } else {
34
+ // radial
35
+ const center = new paper.Point(canvas.width / 2, canvas.height / 2)
36
+ const radius = Math.max(canvas.width, canvas.height) / 2
37
+ project.activeLayer.fillColor = new paper.Color({
38
+ gradient: { stops: paperColors },
39
+ origin: center,
40
+ destination: center.add(new paper.Point(radius, 0)),
41
+ })
42
+ }
43
+ } else if (color) {
44
+ project.activeLayer.fillColor = new paper.Color(color)
45
+ } else {
46
+ throw new Error('Must provide color or gradient')
47
+ }
48
+
49
+ return { success: true, message: 'Background added' }
50
+ }
51
+
52
+ module.exports = addBackground
@@ -0,0 +1,31 @@
1
+ /**
2
+ * 圆形/椭圆元素
3
+ */
4
+
5
+ const paper = require('paper')
6
+
7
+ /**
8
+ * 添加圆形或椭圆
9
+ */
10
+ function addCircle(project, args) {
11
+ const {
12
+ cx, cy, rx, ry,
13
+ fill, stroke, strokeWidth, opacity,
14
+ } = args
15
+
16
+ const circle = new paper.Path.Ellipse({
17
+ center: [cx, cy],
18
+ radius: [rx, ry || rx],
19
+ })
20
+
21
+ if (fill) circle.fillColor = new paper.Color(fill)
22
+ if (stroke) {
23
+ circle.strokeColor = new paper.Color(stroke)
24
+ circle.strokeWidth = strokeWidth || 1
25
+ }
26
+ if (opacity !== undefined) circle.opacity = opacity
27
+
28
+ return { success: true, id: circle.id, type: 'circle' }
29
+ }
30
+
31
+ module.exports = addCircle
@@ -0,0 +1,71 @@
1
+ /**
2
+ * 图片元素
3
+ */
4
+
5
+ const paper = require('paper')
6
+ const fs = require('fs')
7
+ const path = require('path')
8
+
9
+ /**
10
+ * 添加图片(支持本地路径、URL、Base64)
11
+ */
12
+ function addImage(project, args) {
13
+ const { src, x, y, width, height, opacity } = args
14
+
15
+ try {
16
+ // 转换为绝对路径
17
+ let absolutePath = src
18
+ if (!path.isAbsolute(absolutePath)) {
19
+ absolutePath = path.join(process.cwd(), absolutePath)
20
+ }
21
+
22
+ // 检查文件是否存在
23
+ if (!fs.existsSync(absolutePath)) {
24
+ return { success: false, error: `文件不存在: ${absolutePath}` }
25
+ }
26
+
27
+ // 读取文件并转为 Base64
28
+ const buffer = fs.readFileSync(absolutePath)
29
+ const ext = path.extname(absolutePath).toLowerCase()
30
+ const mimeTypes = {
31
+ '.png': 'image/png',
32
+ '.jpg': 'image/jpeg',
33
+ '.jpeg': 'image/jpeg',
34
+ '.gif': 'image/gif',
35
+ '.webp': 'image/webp',
36
+ '.bmp': 'image/bmp'
37
+ }
38
+ const mimeType = mimeTypes[ext] || 'image/png'
39
+ const imageUrl = `data:${mimeType};base64,${buffer.toString('base64')}`
40
+
41
+ const raster = new paper.Raster(imageUrl)
42
+
43
+ // 等待图片加载完成
44
+ raster.onLoad = () => {
45
+ if (width && height) {
46
+ raster.bounds = new paper.Rectangle(x, y, width, height)
47
+ } else if (width) {
48
+ const scale = width / raster.width
49
+ raster.bounds = new paper.Rectangle(x, y, width, raster.height * scale)
50
+ } else if (height) {
51
+ const scale = height / raster.height
52
+ raster.bounds = new paper.Rectangle(x, y, raster.width * scale, height)
53
+ } else {
54
+ raster.position = new paper.Point(x, y)
55
+ }
56
+
57
+ if (opacity !== undefined) raster.opacity = opacity
58
+ }
59
+
60
+ return {
61
+ success: true,
62
+ id: raster.id,
63
+ type: 'image',
64
+ path: absolutePath,
65
+ }
66
+ } catch (err) {
67
+ return { success: false, error: `Failed to load image: ${err.message}` }
68
+ }
69
+ }
70
+
71
+ module.exports = addImage
@@ -0,0 +1,26 @@
1
+ /**
2
+ * 基础元素模块导出
3
+ */
4
+
5
+ const addRectangle = require('./rectangle')
6
+ const addCircle = require('./circle')
7
+ const addLine = require('./line')
8
+ const addPolygon = require('./polygon')
9
+ const addImage = require('./image')
10
+ const addText = require('./text')
11
+ const addArtText = require('./artText')
12
+ const addBackground = require('./background')
13
+ const { addSVG, exportSVG } = require('./svg')
14
+
15
+ module.exports = {
16
+ addRectangle,
17
+ addCircle,
18
+ addLine,
19
+ addPolygon,
20
+ addImage,
21
+ addText,
22
+ addArtText,
23
+ addBackground,
24
+ addSVG,
25
+ exportSVG,
26
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * 线条元素
3
+ */
4
+
5
+ const paper = require('paper')
6
+
7
+ /**
8
+ * 添加线条
9
+ */
10
+ function addLine(project, args) {
11
+ const { x1, y1, x2, y2, stroke, strokeWidth } = args
12
+
13
+ const line = new paper.Path.Line({
14
+ from: [x1, y1],
15
+ to: [x2, y2],
16
+ strokeColor: new paper.Color(stroke || '#ffffff'),
17
+ strokeWidth: strokeWidth || 2,
18
+ })
19
+
20
+ return { success: true, id: line.id, type: 'line' }
21
+ }
22
+
23
+ module.exports = addLine
@@ -0,0 +1,63 @@
1
+ /**
2
+ * 多边形元素
3
+ */
4
+
5
+ const paper = require('paper')
6
+
7
+ /**
8
+ * 添加多边形
9
+ * 支持两种模式:
10
+ * 1. 规则多边形: cx, cy, radius, sides
11
+ * 2. 自定义多边形: points 数组 [[x1,y1], [x2,y2], ...]
12
+ */
13
+ function addPolygon(project, args) {
14
+ const {
15
+ cx, cy, radius, sides,
16
+ points,
17
+ fill, stroke, strokeWidth, opacity,
18
+ x = 0, y = 0,
19
+ } = args
20
+
21
+ let polygon
22
+
23
+ if (points && Array.isArray(points)) {
24
+ // 使用自定义点创建多边形
25
+ // 每个点应该是 [relativeX, relativeY],相对于 x, y 偏移
26
+ const pathData = points.map((pt, i) => {
27
+ const px = (Array.isArray(pt) ? pt[0] : pt) + x
28
+ const py = (Array.isArray(pt) ? pt[1] : 0) + y
29
+ return i === 0 ? [px, py] : [px, py]
30
+ })
31
+
32
+ polygon = new paper.Path({
33
+ segments: pathData,
34
+ closed: true,
35
+ })
36
+ } else if (cx !== undefined && cy !== undefined) {
37
+ // 使用中心点和半径创建规则多边形
38
+ polygon = new paper.Path.RegularPolygon({
39
+ center: [cx, cy],
40
+ radius: radius || 100,
41
+ sides: sides || 6,
42
+ })
43
+ } else {
44
+ throw new Error('Polygon requires either points array or cx/cy coordinates')
45
+ }
46
+
47
+ if (fill) {
48
+ polygon.fillColor = new paper.Color(fill)
49
+ } else {
50
+ polygon.fillColor = null
51
+ }
52
+
53
+ if (stroke) {
54
+ polygon.strokeColor = new paper.Color(stroke)
55
+ polygon.strokeWidth = strokeWidth || 1
56
+ }
57
+
58
+ if (opacity !== undefined) polygon.opacity = opacity
59
+
60
+ return { success: true, id: polygon.id, type: 'polygon' }
61
+ }
62
+
63
+ module.exports = addPolygon
@@ -0,0 +1,32 @@
1
+ /**
2
+ * 矩形元素
3
+ */
4
+
5
+ const paper = require('paper')
6
+
7
+ /**
8
+ * 添加矩形
9
+ */
10
+ function addRectangle(project, args) {
11
+ const {
12
+ x, y, width, height,
13
+ fill, stroke, strokeWidth, radius, opacity,
14
+ } = args
15
+
16
+ const rect = new paper.Path.Rectangle({
17
+ point: [x, y],
18
+ size: [width, height],
19
+ radius: radius || 0,
20
+ })
21
+
22
+ if (fill) rect.fillColor = new paper.Color(fill)
23
+ if (stroke) {
24
+ rect.strokeColor = new paper.Color(stroke)
25
+ rect.strokeWidth = strokeWidth || 1
26
+ }
27
+ if (opacity !== undefined) rect.opacity = opacity
28
+
29
+ return { success: true, id: rect.id, type: 'rectangle' }
30
+ }
31
+
32
+ module.exports = addRectangle
@@ -0,0 +1,92 @@
1
+ /**
2
+ * SVG 元素
3
+ */
4
+
5
+ const paper = require('paper')
6
+ const fs = require('fs')
7
+
8
+ /**
9
+ * 添加 SVG
10
+ *
11
+ * @param {Object} project - Paper.js 项目
12
+ * @param {Object} args - 组件参数
13
+ * @param {string} args.src - SVG 文件路径或 SVG 字符串
14
+ * @param {number} args.x - X坐标
15
+ * @param {number} args.y - Y坐标
16
+ * @param {number} args.width - 宽度
17
+ * @param {number} args.height - 高度
18
+ * @param {number} args.opacity - 透明度 0-1
19
+ */
20
+ function addSVG(project, args) {
21
+ const { src, x, y, width, height, opacity } = args
22
+
23
+ let svgContent = src
24
+
25
+ // 如果是文件路径,读取文件内容
26
+ if (!src.startsWith('<') && !src.startsWith('<?xml')) {
27
+ try {
28
+ svgContent = fs.readFileSync(src, 'utf8')
29
+ } catch (e) {
30
+ return { success: false, error: `Failed to read SVG file: ${e.message}` }
31
+ }
32
+ }
33
+
34
+ // 导入 SVG
35
+ const svg = paper.project.importSVG(svgContent)
36
+
37
+ if (!svg) {
38
+ return { success: false, error: 'Failed to import SVG' }
39
+ }
40
+
41
+ // 设置位置
42
+ svg.position = new paper.Point(x, y)
43
+
44
+ // 设置尺寸
45
+ if (width && height) {
46
+ svg.bounds.width = width
47
+ svg.bounds.height = height
48
+ } else if (width) {
49
+ svg.scale(width / svg.bounds.width)
50
+ } else if (height) {
51
+ svg.scale(height / svg.bounds.height)
52
+ }
53
+
54
+ // 设置透明度
55
+ if (opacity !== undefined) {
56
+ svg.opacity = opacity
57
+ }
58
+
59
+ return {
60
+ success: true,
61
+ id: svg.id,
62
+ type: 'svg',
63
+ width: svg.bounds.width,
64
+ height: svg.bounds.height,
65
+ }
66
+ }
67
+
68
+ /**
69
+ * 创建 SVG 导出
70
+ *
71
+ * @param {Object} project - Paper.js 项目
72
+ * @param {string} filename - 文件名
73
+ * @param {string} outputDir - 输出目录
74
+ */
75
+ function exportSVG(project, filename, outputDir = '.') {
76
+ const svg = project.exportSVG({
77
+ asString: true,
78
+ bounds: 'content',
79
+ })
80
+
81
+ const filepath = require('path').join(outputDir, `${filename}.svg`)
82
+ fs.writeFileSync(filepath, svg)
83
+
84
+ return {
85
+ success: true,
86
+ filepath,
87
+ filename: `${filename}.svg`,
88
+ size: Buffer.byteLength(svg, 'utf8'),
89
+ }
90
+ }
91
+
92
+ module.exports = { addSVG, exportSVG }
@@ -0,0 +1,107 @@
1
+ /**
2
+ * 文字元素
3
+ */
4
+
5
+ const paper = require('paper')
6
+ const { validateFont, getDefaultFont, getRegisteredFonts } = require('../fonts')
7
+
8
+ /**
9
+ * 检测文本是否包含 emoji
10
+ */
11
+ function containsEmoji(text) {
12
+ if (!text || typeof text !== 'string') return false
13
+
14
+ // Emoji Unicode 范围
15
+ const emojiRanges = [
16
+ /\u{1F600}-\u{1F64F}/u, // 表情符号
17
+ /\u{1F300}-\u{1F5FF}/u, // 符号和图片
18
+ /\u{1F680}-\u{1F6FF}/u, // 交通和地图
19
+ /\u{1F700}-\u{1F77F}/u, // 字母符号
20
+ /\u{1F780}-\u{1F7FF}/u, // 几何符号扩展
21
+ /\u{1F800}-\u{1F8FF}/u, // 箭头补充
22
+ /\u{1F900}-\u{1F9FF}/u, // 表情符号补充
23
+ /\u{1FA00}-\u{1FA6F}/u, // 棋牌符号
24
+ /\u{1FA70}-\u{1FAFF}/u, // 装饰符号
25
+ /\u{2600}-\u{26FF}/u, // 杂项符号
26
+ /\u{2700}-\u{27BF}/u, // 装饰符号
27
+ /[\u{1F000}-\u{1F02F}]/u, // 麻将牌
28
+ ]
29
+
30
+ for (const range of emojiRanges) {
31
+ if (range.test(text)) {
32
+ return true
33
+ }
34
+ }
35
+
36
+ // 简单检测:包含常见 emoji 字符
37
+ const simpleEmoji = /[\u{1F300}-\u{1F9FF}]/u
38
+ return simpleEmoji.test(text)
39
+ }
40
+
41
+ /**
42
+ * 获取适合的字体(考虑 emoji)
43
+ */
44
+ function getFontForText(requestedFont, text) {
45
+ const baseFont = validateFont(requestedFont) || getDefaultFont()
46
+
47
+ // 如果文本包含 emoji,尝试使用支持 emoji 的字体
48
+ if (containsEmoji(text)) {
49
+ const registeredFonts = getRegisteredFonts()
50
+
51
+ // 优先查找专门的 emoji 字体(多种命名方式)
52
+ const emojiFont = registeredFonts.find(f => {
53
+ if (!f) return false
54
+ const lower = f.toLowerCase()
55
+ return (
56
+ lower.includes('color emoji') || // Noto Color Emoji, Apple Color Emoji
57
+ lower.includes('noto emoji') || // Noto Emoji
58
+ lower.includes('segoe ui emoji') || // Windows emoji
59
+ lower.includes('symbola') || // Symbola
60
+ lower.includes('emoji') // 任何包含 emoji 的字体
61
+ )
62
+ })
63
+
64
+ if (emojiFont) {
65
+ console.log(`[poster] 检测到 emoji,使用字体: ${emojiFont}`)
66
+ return emojiFont
67
+ } else {
68
+ console.log(`[poster] 检测到 emoji,但未找到专用 emoji 字体,已注册字体: ${registeredFonts.join(', ')}`)
69
+ }
70
+ }
71
+
72
+ return baseFont
73
+ }
74
+
75
+ /**
76
+ * 添加文字
77
+ */
78
+ function addText(project, args) {
79
+ const {
80
+ text,
81
+ x, y,
82
+ fontSize, fontFamily, color,
83
+ align,
84
+ shadow,
85
+ } = args
86
+
87
+ const font = getFontForText(fontFamily, text)
88
+
89
+ const textItem = new paper.PointText({
90
+ point: [x, y],
91
+ content: text,
92
+ fontSize: fontSize || 48,
93
+ fontFamily: font,
94
+ fillColor: new paper.Color(color || '#ffffff'),
95
+ justification: align || 'left',
96
+ })
97
+
98
+ if (shadow) {
99
+ textItem.shadowColor = new paper.Color(shadow.color)
100
+ textItem.shadowBlur = shadow.blur || 5
101
+ textItem.shadowOffset = new paper.Point(shadow.offsetX || 2, shadow.offsetY || 2)
102
+ }
103
+
104
+ return { success: true, id: textItem.id, type: 'text' }
105
+ }
106
+
107
+ module.exports = addText