@playcraft/cli 0.0.40 → 0.0.42
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/README.md +66 -3
- package/dist/atom-plan/validate-atom-plan.js +298 -0
- package/dist/cli-root-help.js +1 -1
- package/dist/commands/3d.js +363 -0
- package/dist/commands/create.js +337 -0
- package/dist/commands/image.js +1337 -43
- package/dist/commands/recommend.js +1 -1
- package/dist/commands/remix.js +213 -0
- package/dist/commands/skills.js +1379 -0
- package/dist/commands/tools-3d.js +473 -0
- package/dist/commands/tools-generation.js +452 -0
- package/dist/commands/tools-project.js +400 -0
- package/dist/commands/tools-research.js +37 -0
- package/dist/commands/tools-research.test.js +216 -0
- package/dist/commands/tools-utils.js +183 -0
- package/dist/commands/tools.js +7 -616
- package/dist/config.js +2 -0
- package/dist/index.js +19 -1
- package/dist/utils/version-checker.js +8 -11
- package/package.json +9 -3
- package/project-template/.claude/agents/designer.md +120 -0
- package/project-template/.claude/agents/developer.md +124 -0
- package/project-template/.claude/agents/pm.md +164 -0
- package/project-template/.claude/agents/refs/README.md +73 -0
- package/project-template/.claude/agents/refs/designer-art-style-catalog.md +533 -0
- package/project-template/.claude/agents/refs/designer-color-audio-recipes.md +153 -0
- package/project-template/.claude/agents/refs/designer-deliverable-spec.md +191 -0
- package/project-template/.claude/agents/refs/designer-dimension-axis.md +27 -0
- package/project-template/.claude/agents/refs/designer-handoff-v2-checklist.md +68 -0
- package/project-template/.claude/agents/refs/designer-master-composite-recipes.md +208 -0
- package/project-template/.claude/agents/refs/designer-style-exploration-flow.md +37 -0
- package/project-template/.claude/agents/refs/developer-dev-handoff.md +109 -0
- package/project-template/.claude/agents/refs/developer-impl-cookbook.md +134 -0
- package/project-template/.claude/agents/refs/developer-phase1-flow.md +136 -0
- package/project-template/.claude/agents/refs/pm-workflow-detail.md +551 -0
- package/project-template/.claude/agents/refs/reviewer-convergence-eval.md +130 -0
- package/project-template/.claude/agents/refs/reviewer-six-dimension-eval.md +6 -0
- package/project-template/.claude/agents/refs/ta-3d-flip-recipe.md +85 -0
- package/project-template/.claude/agents/refs/ta-atlas-deliverable-standard.md +67 -0
- package/project-template/.claude/agents/refs/ta-batch-pipeline-recipes.md +120 -0
- package/project-template/.claude/agents/refs/ta-image-generation-detail.md +356 -0
- package/project-template/.claude/agents/refs/ta-image-ops-reference.md +495 -0
- package/project-template/.claude/agents/refs/ta-pipeline-cookbook.md +1108 -0
- package/project-template/.claude/agents/refs/ta-tools-reference.md +111 -0
- package/project-template/.claude/agents/refs/ta-vfx-preset-catalog.md +365 -0
- package/project-template/.claude/agents/reviewer.md +127 -0
- package/project-template/.claude/agents/technical-artist.md +122 -0
- package/project-template/.claude/hooks/README.md +44 -0
- package/project-template/.claude/hooks/validate-atom-plan.mjs +224 -0
- package/project-template/.claude/hooks/validate-workflow-stop.mjs +343 -0
- package/project-template/.claude/settings.json +36 -0
- package/project-template/.claude/settings.local.json +4 -0
- package/project-template/.claude/skills/playcraft-ad-psychology/SKILL.md +182 -0
- package/project-template/.claude/skills/playcraft-art-style-guide/SKILL.md +123 -0
- package/project-template/.claude/skills/playcraft-asset-state-sheet/SKILL.md +141 -0
- package/project-template/.claude/skills/playcraft-audio-generation/SKILL.md +280 -0
- package/project-template/.claude/skills/playcraft-batch-pipeline/SKILL.md +184 -0
- package/project-template/.claude/skills/playcraft-build-optimizer/SKILL.md +306 -0
- package/project-template/.claude/skills/playcraft-image-generation/SKILL.md +279 -0
- package/project-template/.claude/skills/playcraft-image-generation/reference/build-sprite-sheet.template.mjs +123 -0
- package/project-template/.claude/skills/playcraft-image-generation/reference/compare-style.template.mjs +254 -0
- package/project-template/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +235 -0
- package/project-template/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +97 -0
- package/project-template/.claude/skills/playcraft-image-generation/reference/gen-edit-variants.template.mjs +118 -0
- package/project-template/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +137 -0
- package/project-template/.claude/skills/playcraft-image-generation/reference/prompt-cookbook.md +397 -0
- package/project-template/.claude/skills/playcraft-image-generation/reference/validate-sprite-sheet.template.mjs +296 -0
- package/project-template/.claude/skills/playcraft-image-ops/SKILL.md +122 -0
- package/project-template/.claude/skills/playcraft-masking/SKILL.md +373 -0
- package/project-template/.claude/skills/playcraft-research/SKILL.md +212 -0
- package/project-template/.claude/skills/playcraft-sprite-generation/SKILL.md +423 -0
- package/project-template/.claude/skills/playcraft-storyboard/SKILL.md +167 -0
- package/project-template/.claude/skills/playcraft-style-qa/SKILL.md +270 -0
- package/project-template/.claude/skills/playcraft-text-rendering/SKILL.md +236 -0
- package/project-template/.claude/skills/playcraft-vfx-animation/SKILL.md +130 -0
- package/project-template/.claude/skills/playcraft-workflow/SKILL.md +485 -0
- package/project-template/.claude/skills/playwright-cli/SKILL.md +390 -0
- package/project-template/.claude/skills/playwright-cli/references/element-attributes.md +23 -0
- package/project-template/.claude/skills/playwright-cli/references/playwright-tests.md +39 -0
- package/project-template/.claude/skills/playwright-cli/references/request-mocking.md +87 -0
- package/project-template/.claude/skills/playwright-cli/references/running-code.md +240 -0
- package/project-template/.claude/skills/playwright-cli/references/session-management.md +226 -0
- package/project-template/.claude/skills/playwright-cli/references/spec-driven-testing.md +312 -0
- package/project-template/.claude/skills/playwright-cli/references/storage-state.md +275 -0
- package/project-template/.claude/skills/playwright-cli/references/test-generation.md +138 -0
- package/project-template/.claude/skills/playwright-cli/references/tracing.md +142 -0
- package/project-template/.claude/skills/playwright-cli/references/video-recording.md +157 -0
- package/project-template/.cursor/hooks.json +17 -0
- package/project-template/.cursor/rules/playcraft-orchestrator.mdc +137 -0
- package/project-template/.cursor/rules/playcraft-subagent-boundary.mdc +18 -0
- package/project-template/CLAUDE.md +280 -0
- package/project-template/assets/audio/bgm/.gitkeep +0 -0
- package/project-template/assets/audio/sfx/.gitkeep +0 -0
- package/project-template/assets/bundles/.gitkeep +0 -0
- package/project-template/assets/images/bg/.gitkeep +0 -0
- package/project-template/assets/images/reference/.gitkeep +0 -0
- package/project-template/assets/images/storyboard/.gitkeep +0 -0
- package/project-template/assets/images/tiles/.gitkeep +0 -0
- package/project-template/assets/images/ui/.gitkeep +0 -0
- package/project-template/assets/images/vfx/.gitkeep +0 -0
- package/project-template/assets/models/.gitkeep +0 -0
- package/project-template/docs/team/agent-conduct.md +121 -0
- package/project-template/docs/team/agent-runtime-matrix.md +62 -0
- package/project-template/docs/team/atom-plan-format.md +105 -0
- package/project-template/docs/team/collaboration.md +297 -0
- package/project-template/docs/team/core-model.md +50 -0
- package/project-template/docs/team/platform-capabilities.md +15 -0
- package/project-template/docs/team/workflow-changelog.md +65 -0
- package/project-template/docs/team/workflow-consistency-checklist.md +140 -0
- package/project-template/game/config/.gitkeep +0 -0
- package/project-template/game/gameplay/.gitkeep +0 -0
- package/project-template/game/scenes/.gitkeep +0 -0
- package/project-template/logs/.gitkeep +0 -0
- package/project-template/ta-workspace/logs/.gitkeep +0 -0
- package/project-template/ta-workspace/scripts/.gitkeep +0 -0
- package/project-template/ta-workspace/tmp/.gitkeep +0 -0
- package/project-template/templates/atom-plan.template.json +26 -0
- package/project-template/templates/atom-plan.template.md +108 -0
- package/project-template/templates/design-brief.template.md +195 -0
- package/project-template/templates/design-lens-checklist.reference.md +117 -0
- package/project-template/templates/design-methodology.md +99 -0
- package/project-template/templates/designer-log.template.md +114 -0
- package/project-template/templates/developer-log.template.md +134 -0
- package/project-template/templates/five-axis-framework.md +186 -0
- package/project-template/templates/intent-clarifications.template.md +58 -0
- package/project-template/templates/layout-spec.template.md +146 -0
- package/project-template/templates/project-state.template.md +237 -0
- package/project-template/templates/review-report.template.md +91 -0
- package/project-template/templates/style-exploration.template.md +93 -0
- package/project-template/templates/ta-log.template.md +343 -0
package/project-template/.claude/skills/playcraft-image-generation/reference/prompt-cookbook.md
ADDED
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
# Image Generation Prompt Cookbook
|
|
2
|
+
|
|
3
|
+
> 适用于 PlayCraft CLI `playcraft tools generate-image`。
|
|
4
|
+
> 所有模型均适用;gpt-image-2 类模型对英文 prompt 理解最准确,优先写英文。
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 一、Prompt 万能公式
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
[主体描述] + [风格/介质] + [构图/视角] + [背景] + [质量修饰词]
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
**示例**:
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
A golden sword icon, flat 2D vector style, centered composition,
|
|
18
|
+
white background, clean crisp edges, game UI asset, high quality
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 二、各素材类型模板
|
|
24
|
+
|
|
25
|
+
### 🎮 游戏图标(UI Icons)
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
A [物品名] icon, flat 2D vector illustration, bold outlines,
|
|
29
|
+
vibrant colors, centered composition, white background,
|
|
30
|
+
no shadow, no gradient, game UI style, sharp crisp edges
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
- 关键词:`flat 2D` / `bold outlines` / `centered` / `no shadow` / `game UI style`
|
|
34
|
+
- 避免:`3D` / `realistic` / `photographic` / `drop shadow`
|
|
35
|
+
|
|
36
|
+
### 🃏 卡牌 / 棋子 / 方块(Rectangular Tiles)
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
A playing card: [花色] [数字], flat 2D, clean white card face,
|
|
40
|
+
[花色符号] symbol clearly visible, bold [颜色] ink,
|
|
41
|
+
no drop shadow, no 3D effect, no perspective distortion,
|
|
42
|
+
sharp clean edges, centered on white background
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
- 关键词:`flat 2D` / `no drop shadow` / `no 3D effect` / `clean edges`
|
|
46
|
+
- 注意:**不需要绿幕**,直接 resize,不要 remove-background
|
|
47
|
+
|
|
48
|
+
### 👾 游戏角色 / 精灵(Characters & Sprites)
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
A [角色描述] character, full body visible, game sprite style,
|
|
52
|
+
[艺术风格: pixel art / cartoon / chibi / realistic],
|
|
53
|
+
isolated on solid bright green #00FF00 background,
|
|
54
|
+
centered, facing forward / side view, clean silhouette
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
- 需要透明背景 → **绿幕策略**,prompt 加 `"on solid bright green #00FF00 background, isolated"`
|
|
58
|
+
- 后处理:`remove-background --tolerance 25`
|
|
59
|
+
|
|
60
|
+
### 🌄 场景背景(Backgrounds)
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
[场景描述], [风格: hand-drawn / watercolor / pixel art / 3D render],
|
|
64
|
+
full scene composition, edge to edge, no UI elements,
|
|
65
|
+
[时间: day / night / sunset], [氛围: peaceful / intense / magical],
|
|
66
|
+
[画面比例暗示: wide panoramic / portrait]
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
- 不需要背景处理,直接 resize
|
|
70
|
+
- 比例建议:横版游戏 `--aspect-ratio 16:9`,竖版 `9:16`
|
|
71
|
+
|
|
72
|
+
### 🔤 含文字 / 数字的素材
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
[描述], with [内容] clearly written in bold [颜色] [字体风格] font,
|
|
76
|
+
legible, centered, high contrast text
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
- gpt-image-2 对文字处理最好,优先使用
|
|
80
|
+
- Google Gemini 对中文支持较好
|
|
81
|
+
|
|
82
|
+
### 🌿 纹理 / 材质(Textures)
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
[材质名: ice / wood / metal / stone] texture, seamless tileable,
|
|
86
|
+
top-down view, diffuse map, [颜色倾向],
|
|
87
|
+
no shadows, flat lighting, high detail
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### 🔲 精灵图网格(Sprite Sheet Grid,gpt-image-2 直出)
|
|
91
|
+
|
|
92
|
+
**一次 API 调用生成完整精灵图,后续 sprite-split 切分**。比逐个生成效率高 N 倍。
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
Sprite sheet grid layout, [N] columns × [M] rows.
|
|
96
|
+
Each cell contains one [元素类型]. Cell contents:
|
|
97
|
+
[Row1,Col1]: [内容描述]; [Row1,Col2]: [内容描述]; ...
|
|
98
|
+
Grid layout, uniform cell size, equal spacing,
|
|
99
|
+
elements perfectly centered in each cell.
|
|
100
|
+
No borders between cells, no labels, no numbers on cells.
|
|
101
|
+
[风格描述]
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**卡牌套(扑克)示例**:
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
Sprite sheet grid layout, 4 columns × 4 rows.
|
|
108
|
+
Each cell contains one playing card face, flat 2D illustration, white card face.
|
|
109
|
+
Cell contents:
|
|
110
|
+
[Row1,Col1]: Ace of Spades, A symbol top-left, large spade symbol center;
|
|
111
|
+
[Row1,Col2]: 2 of Spades, number 2, two spade symbols;
|
|
112
|
+
[Row1,Col3]: 3 of Spades, number 3, three spade symbols;
|
|
113
|
+
[Row1,Col4]: 4 of Spades, number 4, four spade symbols;
|
|
114
|
+
[Row2,Col1]: 5 of Spades; [Row2,Col2]: 6 of Spades; [Row2,Col3]: 7 of Spades; [Row2,Col4]: 8 of Spades;
|
|
115
|
+
[Row3,Col1]: 9 of Spades; [Row3,Col2]: 10 of Spades; [Row3,Col3]: Jack of Spades with J; [Row3,Col4]: Queen of Spades with Q;
|
|
116
|
+
[Row4,Col1]: King of Spades with K; [Row4,Col2]: Ace of Hearts; [Row4,Col3]: 2 of Hearts; [Row4,Col4]: 3 of Hearts.
|
|
117
|
+
Grid layout, equal cell size, no borders between cells. Bold black ink for spades, bold red ink for hearts.
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**图标集示例**(一批 9 个图标):
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
Sprite sheet grid, 3 columns × 3 rows. Flat 2D game icon style, white background.
|
|
124
|
+
[Row1,Col1]: sword icon; [Row1,Col2]: shield icon; [Row1,Col3]: bow and arrow icon;
|
|
125
|
+
[Row2,Col1]: magic staff icon; [Row2,Col2]: potion bottle icon; [Row2,Col3]: scroll icon;
|
|
126
|
+
[Row3,Col1]: coin gold icon; [Row3,Col2]: gem diamond icon; [Row3,Col3]: key icon.
|
|
127
|
+
Each icon centered in its cell, bold outlines, vibrant colors, no shadow.
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**背景选择(重要!)**:
|
|
131
|
+
|
|
132
|
+
| 素材类型 | prompt 背景写法 | 切分后处理 |
|
|
133
|
+
| ----------------------------------- | --------------------------------------------------- | ---------------------------------- |
|
|
134
|
+
| 独立元素(角色/车/道具/图标)需透明 | `isolated on solid bright green #00FF00 background` | `remove-background --tolerance 25` |
|
|
135
|
+
| 卡牌/棋子/UI 面板(矩形本体) | `white background, no shadow` | 直接 resize,不去背景 |
|
|
136
|
+
|
|
137
|
+
**注意事项**:
|
|
138
|
+
|
|
139
|
+
- 每批最多 **4×4 = 16 个元素**,超过会出现混乱
|
|
140
|
+
- 每个格的描述要精确,包含特征性视觉元素
|
|
141
|
+
- 切分后用 `sprite-split --rows N --columns M` 按网格切分
|
|
142
|
+
- 模板:[gen-batch-sprite.template.mjs](gen-batch-sprite.template.mjs)
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## 三、风格关键词速查
|
|
147
|
+
|
|
148
|
+
### 艺术风格
|
|
149
|
+
|
|
150
|
+
| 风格 | 关键词 |
|
|
151
|
+
| --------- | ---------------------------------------------------------------- |
|
|
152
|
+
| 像素艺术 | `pixel art, 8-bit style, limited color palette, sharp pixels` |
|
|
153
|
+
| 扁平插画 | `flat 2D illustration, vector style, bold outlines, minimal` |
|
|
154
|
+
| 卡通 | `cartoon style, bright colors, cel-shaded, clean lines` |
|
|
155
|
+
| Q版/Chibi | `chibi style, cute, big head proportion, round shapes` |
|
|
156
|
+
| 写实 | `realistic, photorealistic, detailed, high resolution` |
|
|
157
|
+
| 水彩 | `watercolor painting, soft edges, transparent washes, artistic` |
|
|
158
|
+
| 赛博朋克 | `cyberpunk, neon lights, dark background, glowing effects` |
|
|
159
|
+
| 奇幻 | `fantasy art, magical, ethereal glow, detailed illustration` |
|
|
160
|
+
| 中国风 | `Chinese traditional ink painting style, brush strokes, minimal` |
|
|
161
|
+
|
|
162
|
+
### 质量修饰词(末尾通用)
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
high quality, clean, sharp details, professional game asset, centered composition
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### 负面描述(告诉模型不要什么)
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
no text, no watermark, no blur, no noise, no artifacts, no extra limbs,
|
|
172
|
+
no distortion, no compression artifacts, isolated subject
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## 四、gpt-image-2 专项技巧
|
|
178
|
+
|
|
179
|
+
gpt-image-2 是目前质量最高的文生图模型,prompt 套路略有不同:
|
|
180
|
+
|
|
181
|
+
### 特点
|
|
182
|
+
|
|
183
|
+
- **英文 prompt 效果最佳**,中文理解也不错但英文更稳定
|
|
184
|
+
- 对**复杂场景**、**细节描述**处理能力远超其他模型
|
|
185
|
+
- 支持**图生图 edit 模式**(传 `--reference-image`),局部编辑能力强
|
|
186
|
+
- 不支持透明 PNG 输出(ALPHA = no),需绿幕策略
|
|
187
|
+
|
|
188
|
+
### prompt 格式建议
|
|
189
|
+
|
|
190
|
+
```
|
|
191
|
+
[简洁主体,1句话] + [风格描述,2-3个关键词] + [技术要求,1-2个]
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
避免过度堆砌修饰词(10+ 个关键词反而会降低质量)。
|
|
195
|
+
|
|
196
|
+
### Edit 模式(图生图)的 prompt 格式
|
|
197
|
+
|
|
198
|
+
```
|
|
199
|
+
[修改指令,动词开头] + [保持不变的元素] + [想要改变的元素]
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
示例:
|
|
203
|
+
|
|
204
|
+
```
|
|
205
|
+
# 好的 edit prompt:
|
|
206
|
+
"Change the rank to 2, keep the same card layout and spade suit symbol"
|
|
207
|
+
|
|
208
|
+
# 差的 edit prompt(会让模型重新生成):
|
|
209
|
+
"A playing card with 2 of spades, white background, flat 2D..."
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### 精灵图直出(最高效用法!)
|
|
213
|
+
|
|
214
|
+
**gpt-image-2 理解布局描述能力最强**,可以一次生成完整网格图:
|
|
215
|
+
|
|
216
|
+
```
|
|
217
|
+
# 精灵图直出 prompt 结构
|
|
218
|
+
Sprite sheet grid layout, [N] columns × [M] rows.
|
|
219
|
+
Each cell: [描述元素类型和内容].
|
|
220
|
+
Grid layout, uniform cell size, equal cell spacing,
|
|
221
|
+
elements centered in each cell, no borders between cells.
|
|
222
|
+
[风格描述]
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**每批推荐 ≤ 16 个元素(4×4)**。超过时分批,每批生成一张网格图。
|
|
226
|
+
|
|
227
|
+
### 批量出图(--count N)
|
|
228
|
+
|
|
229
|
+
同一 prompt 一次出多张候选:
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
playcraft tools generate-image \
|
|
233
|
+
--prompt "A sword icon, flat 2D..." \
|
|
234
|
+
--output assets/gen/sword \
|
|
235
|
+
--count 4 \
|
|
236
|
+
--image-model iegg-litellm/gpt-image-2
|
|
237
|
+
# → sword_1.png sword_2.png sword_3.png sword_4.png
|
|
238
|
+
# 从 4 张中挑最好的,比重试 4 次高效
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## 五、多轮迭代策略
|
|
244
|
+
|
|
245
|
+
### Phase 1:概念确认(1-4 张)
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
# 一次 API 调用生成 4 个候选,选最好的(比 4 次独立调用更高效)
|
|
249
|
+
playcraft tools generate-image \
|
|
250
|
+
--prompt "..." \
|
|
251
|
+
--output "test/concept" \
|
|
252
|
+
--count 4 \
|
|
253
|
+
--image-model iegg-litellm/gpt-image-2
|
|
254
|
+
# → concept_1.png concept_2.png concept_3.png concept_4.png
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Phase 2:锁定风格,加 reference 批量
|
|
258
|
+
|
|
259
|
+
确认概念图后,**所有后续生图必须加 `--reference-image`**,用确认的概念图作为参考。
|
|
260
|
+
|
|
261
|
+
### Phase 3:批量 edit 微调
|
|
262
|
+
|
|
263
|
+
对已生成的图片用 edit 模型做微调(调颜色、调细节),比重新生成更高效。
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## 八、UI / HUD 元素模板
|
|
268
|
+
|
|
269
|
+
> 可玩广告中高频出现的界面元素。这些素材需要**透明背景**(独立叠加在游戏画面上),且必须配合 60-30-10 色彩法则——CTA 按钮颜色必须是画面中唯一出现该颜色的地方。
|
|
270
|
+
>
|
|
271
|
+
> 注意:`figer_icon.aiimage`、`win_result_panel.aiimage` 等 atom Skills 提供了带参考图的生成配方,PM `playcraft skills match` 能匹配到时优先使用。本节模板用于无对应 atom Skill 的场景。
|
|
272
|
+
|
|
273
|
+
### 🟠 CTA 按钮(Call-to-Action Button)
|
|
274
|
+
|
|
275
|
+
```
|
|
276
|
+
Subject: Mobile game CTA button, rounded rectangle shape
|
|
277
|
+
Style: [flat 2D vector / semi-glossy / cartoon 3D beveled — match game style]
|
|
278
|
+
Important details: [bright orange / gold / green] gradient fill,
|
|
279
|
+
white bold sans-serif text reading "PLAY NOW",
|
|
280
|
+
subtle drop shadow below button, glossy highlight on top edge,
|
|
281
|
+
3px white inner border, corners rounded radius 24px
|
|
282
|
+
Use case: Game ad install button, isolated asset, HTML5 playable ad
|
|
283
|
+
Constraints: Transparent background, no extra elements, centered, clean crisp edges,
|
|
284
|
+
no watermark
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
- CTA 颜色必须是游戏画面中**最少使用**的颜色(对比稀缺性原则)
|
|
288
|
+
- 触控目标区域 ≥ 48×48px,生成建议尺寸 360×120px(9:3 比例)
|
|
289
|
+
- 后处理:不需要去背景(直接生成透明背景或用绿幕)
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
### ⬜ 进度条 / 血条(Progress Bar)
|
|
294
|
+
|
|
295
|
+
```
|
|
296
|
+
Subject: Horizontal game progress bar, [80%] filled
|
|
297
|
+
Style: [flat 2D / cartoon / metallic frame]
|
|
298
|
+
Important details: [color] filled portion [80% of total width], unfilled portion [gray / dark],
|
|
299
|
+
rounded end caps, thin outer frame in [darker shade],
|
|
300
|
+
optional inner glow on filled section
|
|
301
|
+
Use case: Game HUD progress indicator, isolated UI element
|
|
302
|
+
Constraints: Transparent background, horizontal orientation, no text labels,
|
|
303
|
+
clean edges, no watermark
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
- 固定填充比例(75–90%)激活进度错觉心理钩子
|
|
307
|
+
- 建议尺寸:480×48px(10:1 宽高比)
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
### 👆 教程引导箭头 / 手势(Tutorial Guidance)
|
|
312
|
+
|
|
313
|
+
```
|
|
314
|
+
Subject: Cartoon pointing hand with index finger extended downward
|
|
315
|
+
Style: cartoon, slightly stylized proportions, large rounded fingertip
|
|
316
|
+
Important details: warm skin tone, white sleeve cuff visible at wrist,
|
|
317
|
+
soft drop shadow beneath finger tip, friendly approachable style,
|
|
318
|
+
[optional: subtle animated glow ring around fingertip]
|
|
319
|
+
Use case: Tutorial overlay tap gesture for playable ad, points toward target element
|
|
320
|
+
Constraints: Transparent background, PNG with alpha channel,
|
|
321
|
+
no extra limbs or elements, finger pointing at bottom-center
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
**箭头变体**(更简洁):
|
|
325
|
+
|
|
326
|
+
```
|
|
327
|
+
Subject: Bold cartoon arrow pointing [down / right], game tutorial UI
|
|
328
|
+
Style: flat 2D, thick outline 4px, rounded arrowhead
|
|
329
|
+
Important details: [bright yellow / white] fill, [dark outline],
|
|
330
|
+
slight perspective tilt for depth, attention-grabbing
|
|
331
|
+
Constraints: Transparent background, single clean arrow shape, no text
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
### 💬 对话气泡 / 提示框(Tooltip / Speech Bubble)
|
|
337
|
+
|
|
338
|
+
```
|
|
339
|
+
Subject: Game UI speech bubble / tooltip, [rectangular with tail / rounded cloud shape]
|
|
340
|
+
Style: flat cartoon, clean vector
|
|
341
|
+
Important details: white or [light color] fill, [2–3px] dark outline,
|
|
342
|
+
tail pointing [down-left / down-center], interior empty for text overlay,
|
|
343
|
+
subtle inner shadow or gradient
|
|
344
|
+
Use case: Game tutorial hint tooltip, isolated UI asset
|
|
345
|
+
Constraints: Transparent background, no text inside, clean edges,
|
|
346
|
+
no watermark, no extra decorations
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
- 生成空白气泡,文字通过代码 Canvas 叠加(避免 AI 文字渲染错误)
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
### 🏆 EndCard 合成画面元素(Reward Icons)
|
|
354
|
+
|
|
355
|
+
EndCard 需要展示"可见但未到手"的奖励,驱动 FOMO 安装冲动:
|
|
356
|
+
|
|
357
|
+
```
|
|
358
|
+
Subject: [treasure chest half-open / pile of gold coins / rare gem crystal]
|
|
359
|
+
Style: [match game art style from concept mockup]
|
|
360
|
+
Important details: [treasure chest]: lid slightly ajar, golden glow escaping from inside,
|
|
361
|
+
jewels visible inside, exciting but incomplete;
|
|
362
|
+
[gold coins]: scattered pile, gleaming highlights, not neatly stacked (implies uncollected);
|
|
363
|
+
[gem crystal]: large, brilliant facets, floating above ground, clearly valuable
|
|
364
|
+
Use case: EndCard reward visual, creates FOMO and drives install
|
|
365
|
+
Constraints: Transparent background, centered, isolated subject,
|
|
366
|
+
no CTA text (added separately), warm celebratory lighting
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
- EndCard **不能**展示"已获得"状态——宝箱要半开、金币要散落、关卡要未完成
|
|
370
|
+
- 这些元素和 CTA 按钮分开生成,由 Developer 在代码中合成布局
|
|
371
|
+
|
|
372
|
+
---
|
|
373
|
+
|
|
374
|
+
### 📊 UI 元素背景处理规则速查
|
|
375
|
+
|
|
376
|
+
| UI 元素类型 | prompt 背景写法 | 后处理 |
|
|
377
|
+
| ---------------- | ----------------------------------------------- | ------------------------------ |
|
|
378
|
+
| CTA 按钮 | `transparent background` 或绿幕 | floodfill 去背 |
|
|
379
|
+
| 进度条 | `transparent background` 或绿幕 | floodfill 去背 |
|
|
380
|
+
| 引导手势 | `transparent background, PNG with alpha` | floodfill 去背(tolerance 25) |
|
|
381
|
+
| 对话气泡 | `transparent background` 或绿幕 | floodfill 去背 |
|
|
382
|
+
| EndCard 奖励图标 | 绿幕(`solid bright green #00FF00 background`) | floodfill 去背(tolerance 25) |
|
|
383
|
+
|
|
384
|
+
---
|
|
385
|
+
|
|
386
|
+
## 六、常见问题 & 修正方案
|
|
387
|
+
|
|
388
|
+
| 问题 | 原因 | 修正 |
|
|
389
|
+
| ------------------ | -------------------- | ------------------------------------------------ |
|
|
390
|
+
| 图标边缘有阴影 | 模型默认加立体效果 | 加 `no shadow, no drop shadow, flat 2D` |
|
|
391
|
+
| 构图不居中 | 没有明确指定 | 加 `centered composition, subject centered` |
|
|
392
|
+
| 背景不干净 | 背景描述不够明确 | 加 `solid white background, isolated` 或绿幕策略 |
|
|
393
|
+
| 多个物体出现 | 主体不够明确 | 加 `a single [物体]`, `only one [物体]` |
|
|
394
|
+
| 文字拼写错误 | 所有模型通病 | 尝试 gpt-image-2(最好),或多生成几张 |
|
|
395
|
+
| 风格不一致(批量) | 没用 reference image | Phase 2 必须加 `--reference-image` |
|
|
396
|
+
| 细节过于复杂 | 素材尺寸小但细节太多 | 加 `simple design, minimal details, bold shapes` |
|
|
397
|
+
| 生成极慢/超时 | 模型负载高 | 换另一个 provider 或换模型 |
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* validate-sprite-sheet.template.mjs
|
|
3
|
+
*
|
|
4
|
+
* 精灵图技术正确性验证脚本。
|
|
5
|
+
* TA 在 Compliance Gate 前运行,确认精灵图尺寸、帧数、通道数均符合要求。
|
|
6
|
+
*
|
|
7
|
+
* 使用方法:
|
|
8
|
+
* cp .claude/skills/playcraft-image-generation/reference/validate-sprite-sheet.template.mjs \
|
|
9
|
+
* ta-workspace/scripts/validate-sprite-sheet.mjs
|
|
10
|
+
* # 修改下方 SHEETS 数组后运行:
|
|
11
|
+
* node ta-workspace/scripts/validate-sprite-sheet.mjs
|
|
12
|
+
*
|
|
13
|
+
* 输出示例:
|
|
14
|
+
* [VALIDATE] tile_bounce_anim.png
|
|
15
|
+
* 尺寸验算: 512×256 = 4cols × 128px × 2rows × 128px ✅
|
|
16
|
+
* 通道数: 4 (RGBA) ✅
|
|
17
|
+
* 帧数: 8 帧(JSON 验证: N/A — animate 命令无 JSON)
|
|
18
|
+
* 帧内容抽查 (帧 0, 4, 7): 全部非空 ✅
|
|
19
|
+
* [VALIDATE] explosion_small.png
|
|
20
|
+
* 尺寸验算: 预设 4cols × 8frames → 期望 W=cols×frameW ✅
|
|
21
|
+
* 通道数: 4 (RGBA) ✅
|
|
22
|
+
*
|
|
23
|
+
* 注意:脚本使用 `playcraft image info --json` 获取图片信息。
|
|
24
|
+
* JSON 验证仅适用于 `sprite-sheet` 命令输出(有配套 .json 文件)。
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { execSync } from 'child_process';
|
|
28
|
+
import { existsSync, readFileSync, appendFileSync, mkdirSync } from 'fs';
|
|
29
|
+
import path from 'path';
|
|
30
|
+
|
|
31
|
+
// ─── CONFIG ───────────────────────────────────────────────────────────────────
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 每个条目描述一张精灵图的期望参数。
|
|
35
|
+
* source: 'sprite-sheet' | 'animate' | 'use-vfx'
|
|
36
|
+
* - sprite-sheet: 有配套 JSON,可做完整验证
|
|
37
|
+
* - animate: 无 JSON,从 stdout 记录的参数验证
|
|
38
|
+
* - use-vfx: 无 JSON,从 list-vfx --json 记录的参数验证
|
|
39
|
+
*/
|
|
40
|
+
const SHEETS = [
|
|
41
|
+
{
|
|
42
|
+
file: 'assets/images/tiles/tile_bounce_anim.png',
|
|
43
|
+
source: 'animate', // 'sprite-sheet' | 'animate' | 'use-vfx'
|
|
44
|
+
columns: 4,
|
|
45
|
+
frameWidth: 128,
|
|
46
|
+
frameHeight: 128,
|
|
47
|
+
frameCount: 8,
|
|
48
|
+
padding: 0,
|
|
49
|
+
jsonFile: null, // animate 无 JSON,填 null
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
file: 'assets/images/vfx/explosion.png',
|
|
53
|
+
source: 'use-vfx',
|
|
54
|
+
columns: 4,
|
|
55
|
+
frameWidth: 128, // use-vfx 预设宽高需用 playcraft image info 确认
|
|
56
|
+
frameHeight: 128,
|
|
57
|
+
frameCount: 8,
|
|
58
|
+
padding: 0,
|
|
59
|
+
jsonFile: null,
|
|
60
|
+
},
|
|
61
|
+
// sprite-sheet 示例(有 JSON):
|
|
62
|
+
// {
|
|
63
|
+
// file: 'assets/images/tiles/tile_atlas.png',
|
|
64
|
+
// source: 'sprite-sheet',
|
|
65
|
+
// columns: 6,
|
|
66
|
+
// frameWidth: 128,
|
|
67
|
+
// frameHeight: 128,
|
|
68
|
+
// frameCount: 34,
|
|
69
|
+
// padding: 2,
|
|
70
|
+
// jsonFile: 'assets/images/tiles/tile_atlas.json',
|
|
71
|
+
// },
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
const LOG_FILE = 'ta-workspace/logs/sprite-validate.log';
|
|
75
|
+
|
|
76
|
+
// ─── HELPERS ──────────────────────────────────────────────────────────────────
|
|
77
|
+
|
|
78
|
+
function imageInfo(filePath) {
|
|
79
|
+
try {
|
|
80
|
+
const raw = execSync(
|
|
81
|
+
`playcraft image info --input "${filePath}" --json`,
|
|
82
|
+
{ encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] },
|
|
83
|
+
);
|
|
84
|
+
return JSON.parse(raw);
|
|
85
|
+
} catch {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function pass(msg) { return `✅ ${msg}`; }
|
|
91
|
+
function fail(msg) { return `❌ ${msg}`; }
|
|
92
|
+
|
|
93
|
+
// ─── VALIDATION ───────────────────────────────────────────────────────────────
|
|
94
|
+
|
|
95
|
+
async function validateSheet(sheet) {
|
|
96
|
+
const lines = [`\n[VALIDATE] ${sheet.file} (source: ${sheet.source})`];
|
|
97
|
+
let allPassed = true;
|
|
98
|
+
|
|
99
|
+
if (!existsSync(sheet.file)) {
|
|
100
|
+
lines.push(` ${fail('文件不存在 — 请先完成资产生产')}`);
|
|
101
|
+
return { passed: false, lines };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ── 1. 获取实际图片信息 ────────────────────────────────────────────────
|
|
105
|
+
const info = imageInfo(sheet.file);
|
|
106
|
+
if (!info) {
|
|
107
|
+
lines.push(` ${fail('无法读取图片信息(playcraft image info 失败)')}`);
|
|
108
|
+
return { passed: false, lines };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const actualW = info.width;
|
|
112
|
+
const actualH = info.height;
|
|
113
|
+
const actualChannels = info.channels ?? 4;
|
|
114
|
+
|
|
115
|
+
// ── 2. 尺寸数学验算 ────────────────────────────────────────────────────
|
|
116
|
+
const rows = Math.ceil(sheet.frameCount / sheet.columns);
|
|
117
|
+
const expectedW = sheet.columns * sheet.frameWidth + (sheet.columns - 1) * sheet.padding;
|
|
118
|
+
const expectedH = rows * sheet.frameHeight + (rows - 1) * sheet.padding;
|
|
119
|
+
|
|
120
|
+
const dimOk = actualW === expectedW && actualH === expectedH;
|
|
121
|
+
if (dimOk) {
|
|
122
|
+
lines.push(
|
|
123
|
+
` ${pass(`尺寸验算: ${actualW}×${actualH} = ${sheet.columns}cols×${sheet.frameWidth}px + ${rows}rows×${sheet.frameHeight}px (padding=${sheet.padding}px)`)}`
|
|
124
|
+
);
|
|
125
|
+
} else {
|
|
126
|
+
allPassed = false;
|
|
127
|
+
lines.push(
|
|
128
|
+
` ${fail(`尺寸不匹配: 实际 ${actualW}×${actualH},期望 ${expectedW}×${expectedH}`)}`
|
|
129
|
+
);
|
|
130
|
+
lines.push(` → 检查 columns/frameWidth/frameHeight/padding 参数是否与生成命令一致`);
|
|
131
|
+
lines.push(` → animate 命令 padding 固定为 0;sprite-sheet 命令默认 padding 为 0`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// ── 3. 通道数验证 ──────────────────────────────────────────────────────
|
|
135
|
+
if (actualChannels === 4) {
|
|
136
|
+
lines.push(` ${pass(`通道数: 4 (RGBA,支持透明背景)`)}`);
|
|
137
|
+
} else {
|
|
138
|
+
allPassed = false;
|
|
139
|
+
lines.push(
|
|
140
|
+
` ${fail(`通道数: ${actualChannels}(不是 4/RGBA)— 透明区域将渲染为黑色`)}`
|
|
141
|
+
);
|
|
142
|
+
lines.push(` → 如果原图有透明背景,确认去背景步骤正确(remove-background 或生成时使用绿幕策略)`);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ── 4. JSON 验证(仅 sprite-sheet 命令)────────────────────────────────
|
|
146
|
+
if (sheet.source === 'sprite-sheet') {
|
|
147
|
+
const jsonPath = sheet.jsonFile || sheet.file.replace(/\.png$/i, '.json');
|
|
148
|
+
if (!existsSync(jsonPath)) {
|
|
149
|
+
allPassed = false;
|
|
150
|
+
lines.push(` ${fail(`JSON 文件不存在: ${jsonPath}`)}`);
|
|
151
|
+
lines.push(` → sprite-sheet 命令应自动生成 .json,确认命令执行成功`);
|
|
152
|
+
} else {
|
|
153
|
+
try {
|
|
154
|
+
const json = JSON.parse(readFileSync(jsonPath, 'utf-8'));
|
|
155
|
+
const frameKeys = Object.keys(json.frames ?? {});
|
|
156
|
+
const jsonFrameCount = frameKeys.length;
|
|
157
|
+
|
|
158
|
+
if (jsonFrameCount === sheet.frameCount) {
|
|
159
|
+
lines.push(` ${pass(`JSON 帧数: ${jsonFrameCount} 帧`)}`);
|
|
160
|
+
} else {
|
|
161
|
+
allPassed = false;
|
|
162
|
+
lines.push(
|
|
163
|
+
` ${fail(`JSON 帧数不匹配: JSON 中 ${jsonFrameCount} 帧,期望 ${sheet.frameCount} 帧`)}`
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// 验证 meta.size
|
|
168
|
+
const metaW = json.meta?.size?.w;
|
|
169
|
+
const metaH = json.meta?.size?.h;
|
|
170
|
+
if (metaW === actualW && metaH === actualH) {
|
|
171
|
+
lines.push(` ${pass(`JSON meta.size: ${metaW}×${metaH} 与实际图片一致`)}`);
|
|
172
|
+
} else {
|
|
173
|
+
allPassed = false;
|
|
174
|
+
lines.push(
|
|
175
|
+
` ${fail(`JSON meta.size 不匹配: JSON 中 ${metaW}×${metaH},实际 ${actualW}×${actualH}`)}`
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// 帧名字典序警告(数字后缀需补零)
|
|
180
|
+
const hasUnpaddedNumbers = frameKeys.some(k => /[^0]_\d\.png$/.test(k));
|
|
181
|
+
if (hasUnpaddedNumbers) {
|
|
182
|
+
lines.push(
|
|
183
|
+
` ⚠️ 帧名警告: 检测到未补零的数字后缀(如 _1.png vs _10.png)`
|
|
184
|
+
);
|
|
185
|
+
lines.push(
|
|
186
|
+
` → 字典序下 f_10.png 排在 f_2.png 之前,导致动画帧乱序`
|
|
187
|
+
);
|
|
188
|
+
lines.push(` → 输入帧文件名应补零对齐(f_01.png, f_02.png...)`);
|
|
189
|
+
}
|
|
190
|
+
} catch {
|
|
191
|
+
allPassed = false;
|
|
192
|
+
lines.push(` ${fail(`JSON 文件解析失败: ${jsonPath}`)}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
} else {
|
|
196
|
+
lines.push(
|
|
197
|
+
` ℹ️ JSON 验证: 跳过(${sheet.source} 命令不输出 JSON)— 网格参数已记录在 ta-log.md`
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// ── 5. 帧内容抽查(随机 3 帧,验证非透明像素 > 1%)─────────────────────
|
|
202
|
+
if (dimOk && sheet.frameWidth > 0 && sheet.frameHeight > 0) {
|
|
203
|
+
const sampleFrameIndices = [
|
|
204
|
+
0,
|
|
205
|
+
Math.floor(sheet.frameCount / 2),
|
|
206
|
+
sheet.frameCount - 1,
|
|
207
|
+
].filter((v, i, a) => a.indexOf(v) === i);
|
|
208
|
+
|
|
209
|
+
const emptyFrames = [];
|
|
210
|
+
for (const frameIdx of sampleFrameIndices) {
|
|
211
|
+
const col = frameIdx % sheet.columns;
|
|
212
|
+
const row = Math.floor(frameIdx / sheet.columns);
|
|
213
|
+
const x = col * (sheet.frameWidth + sheet.padding);
|
|
214
|
+
const y = row * (sheet.frameHeight + sheet.padding);
|
|
215
|
+
|
|
216
|
+
try {
|
|
217
|
+
// 裁剪单帧并检查非透明像素比例
|
|
218
|
+
const cropResult = execSync(
|
|
219
|
+
`playcraft image crop \
|
|
220
|
+
--input "${sheet.file}" \
|
|
221
|
+
--output ta-workspace/tmp/_frame_check_${frameIdx}.png \
|
|
222
|
+
--x ${x} --y ${y} \
|
|
223
|
+
--width ${sheet.frameWidth} --height ${sheet.frameHeight}`,
|
|
224
|
+
{ encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] },
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
const frameInfo = imageInfo(`ta-workspace/tmp/_frame_check_${frameIdx}.png`);
|
|
228
|
+
// playcraft image info 返回的 dominantColors 可以间接判断非空
|
|
229
|
+
// 简单启发式:如果 dominant colors 存在且有非透明颜色,认为帧非空
|
|
230
|
+
const nonEmpty = frameInfo && (frameInfo.dominantColors?.length > 0 || frameInfo.hasAlpha === false);
|
|
231
|
+
if (!nonEmpty) emptyFrames.push(frameIdx);
|
|
232
|
+
} catch {
|
|
233
|
+
// 裁剪失败跳过
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (emptyFrames.length === 0) {
|
|
238
|
+
lines.push(
|
|
239
|
+
` ${pass(`帧内容抽查 (帧 ${sampleFrameIndices.join(', ')}): 全部非空`)}`
|
|
240
|
+
);
|
|
241
|
+
} else {
|
|
242
|
+
allPassed = false;
|
|
243
|
+
lines.push(
|
|
244
|
+
` ${fail(`帧内容抽查: 帧 ${emptyFrames.join(', ')} 疑似全透明/空帧`)}`
|
|
245
|
+
);
|
|
246
|
+
lines.push(` → 检查对应帧位置坐标是否正确,或去背景是否过激(tolerance 过高)`);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// 清理临时文件
|
|
250
|
+
try {
|
|
251
|
+
execSync(`rm -f ta-workspace/tmp/_frame_check_*.png`, { stdio: 'ignore' });
|
|
252
|
+
} catch { /* ignore */ }
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return { passed: allPassed, lines };
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// ─── MAIN ─────────────────────────────────────────────────────────────────────
|
|
259
|
+
|
|
260
|
+
async function main() {
|
|
261
|
+
mkdirSync('ta-workspace/logs', { recursive: true });
|
|
262
|
+
mkdirSync('ta-workspace/tmp', { recursive: true });
|
|
263
|
+
|
|
264
|
+
console.log('\n🔍 精灵图技术验证');
|
|
265
|
+
console.log(` 检查 ${SHEETS.length} 张精灵图\n`);
|
|
266
|
+
|
|
267
|
+
let passCount = 0;
|
|
268
|
+
let failCount = 0;
|
|
269
|
+
const allLines = [];
|
|
270
|
+
|
|
271
|
+
for (const sheet of SHEETS) {
|
|
272
|
+
const { passed, lines } = await validateSheet(sheet);
|
|
273
|
+
lines.forEach(l => console.log(l));
|
|
274
|
+
allLines.push(...lines);
|
|
275
|
+
if (passed) passCount++;
|
|
276
|
+
else failCount++;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const summary = [
|
|
280
|
+
`\n=== 验证汇总 ===`,
|
|
281
|
+
` 总计: ${SHEETS.length} 张 通过: ${passCount} 失败: ${failCount}`,
|
|
282
|
+
failCount > 0
|
|
283
|
+
? ` ❌ 存在问题的精灵图需在 Compliance Gate 前修复`
|
|
284
|
+
: ` ✅ 全部通过,可继续 Compliance Gate`,
|
|
285
|
+
'',
|
|
286
|
+
].join('\n');
|
|
287
|
+
|
|
288
|
+
console.log(summary);
|
|
289
|
+
|
|
290
|
+
const timestamp = new Date().toISOString();
|
|
291
|
+
appendFileSync(LOG_FILE, `\n[${timestamp}]\n${allLines.join('\n')}\n${summary}`);
|
|
292
|
+
|
|
293
|
+
if (failCount > 0) process.exit(1);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
main().catch(e => { console.error(e); process.exit(1); });
|