evomeme-dev 0.1.7
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 +247 -0
- package/bin/evomeme +28 -0
- package/dist/canvas-public/app.js +5857 -0
- package/dist/canvas-public/cycle-detect.js +166 -0
- package/dist/canvas-public/index.html +395 -0
- package/dist/canvas-public/sequence-sheet.js +59 -0
- package/dist/canvas-public/smart-split.js +185 -0
- package/dist/canvas-public/styles.css +2276 -0
- package/dist/canvas-public/vendor/painterro.min.js +3 -0
- package/dist/index.js +25586 -0
- package/package.json +69 -0
- package/skills/evomeme-cloud-fs/SKILL.md +176 -0
- package/skills/evomeme-cloud-fs/agents/openai.yaml +7 -0
- package/skills/evomeme-cover/SKILL.md +132 -0
- package/skills/evomeme-cover/agents/openai.yaml +7 -0
- package/skills/evomeme-game-maker/SKILL.md +214 -0
- package/skills/evomeme-game-maker/agents/openai.yaml +4 -0
- package/skills/evomeme-login/SKILL.md +92 -0
- package/skills/evomeme-login/agents/openai.yaml +7 -0
- package/skills/evomeme-native-bridge-sdk/SKILL.md +286 -0
- package/skills/evomeme-native-bridge-sdk/agents/openai.yaml +7 -0
- package/skills/evomeme-tos-upload/SKILL.md +46 -0
- package/skills/evomeme-tos-upload/agents/openai.yaml +4 -0
- package/skills/game-art/SKILL.md +121 -0
- package/skills/game-art/agents/openai.yaml +7 -0
- package/skills/game-asset-image-generator/SKILL.md +104 -0
- package/skills/game-asset-image-generator/agents/openai.yaml +7 -0
- package/skills/game-asset-image-generator/references/background.md +32 -0
- package/skills/game-asset-image-generator/references/static-game-assets.md +38 -0
- package/skills/game-audio/SKILL.md +82 -0
- package/skills/game-audio/agents/openai.yaml +4 -0
- package/skills/game-audio/references/bgm-cdn.md +127 -0
- package/skills/game-audio/references/sfx-cdn.md +77 -0
- package/skills/game-demo/SKILL.md +103 -0
- package/skills/game-demo/agents/openai.yaml +7 -0
- package/skills/game-maker/SKILL.md +111 -0
- package/skills/game-maker/agents/openai.yaml +4 -0
- package/skills/game-test/SKILL.md +58 -0
- package/skills/game-test/agents/openai.yaml +7 -0
- package/skills/game-test/references/checklists/playtest-qa.md +12 -0
- package/skills/game-ui/SKILL.md +169 -0
- package/skills/game-ui/agents/openai.yaml +4 -0
- package/skills/game-ui/references/checklists/game-ui-quality.md +14 -0
- package/skills/game-ui/references/checklists/hud-readability.md +12 -0
- package/skills/game-ui/references/checklists/mobile-input.md +12 -0
- package/skills/game-ui/references/checklists/responsive-ui-fit.md +12 -0
- package/skills/game-ui/references/ui-patterns.md +140 -0
- package/skills/game-ui/references/ui-prompt-templates.md +63 -0
- package/skills/phaser-2d-game/SKILL.md +127 -0
- package/skills/phaser-2d-game/agents/openai.yaml +7 -0
- package/skills/phaser-2d-game/references/engine-performance.md +64 -0
- package/skills/phaser-2d-game/references/engine-physics.md +139 -0
- package/skills/phaser-2d-game/references/engine-runtime.md +129 -0
- package/skills/phaser-2d-game/references/engine-spritesheets.md +99 -0
- package/skills/phaser-2d-game/references/engine-tilemaps.md +80 -0
- package/skills/phaser-2d-game/references/file-structure.md +94 -0
- package/skills/phaser-2d-graphics-builder/SKILL.md +68 -0
- package/skills/phaser-2d-graphics-builder/agents/openai.yaml +7 -0
- package/skills/phaser-2d-graphics-builder/assets/scorecard-anchors/scene-1.jpeg +0 -0
- package/skills/phaser-2d-graphics-builder/assets/scorecard-anchors/scene-2.jpeg +0 -0
- package/skills/phaser-2d-graphics-builder/assets/scorecard-anchors/scene-3.jpg +0 -0
- package/skills/phaser-2d-graphics-builder/references/checklists/compose-quality.md +10 -0
- package/skills/phaser-2d-graphics-builder/references/checklists/performance-safe-visual-detail.md +9 -0
- package/skills/phaser-2d-graphics-builder/references/checklists/premium-game-quality-gate.md +15 -0
- package/skills/phaser-2d-graphics-builder/references/checklists/sprite-quality.md +10 -0
- package/skills/phaser-2d-graphics-builder/references/checklists/technical-art-quality.md +9 -0
- package/skills/phaser-2d-graphics-builder/references/checklists/visual-scorecard.md +9 -0
- package/skills/phaser-2d-graphics-builder/references/compose-recipes.md +71 -0
- package/skills/phaser-2d-graphics-builder/references/graphics-prompt-templates.md +33 -0
- package/skills/phaser-2d-graphics-builder/references/implementation-blueprint.md +82 -0
- package/skills/phaser-2d-graphics-builder/references/sprite-recipes.md +90 -0
- package/skills/phaser-2d-graphics-builder/references/technical-art.md +67 -0
- package/skills/phaser-2d-graphics-builder/references/vfx-recipes.md +67 -0
- package/skills/phaser-2d-graphics-builder/references/visual-scorecard.md +129 -0
- package/skills/threejs-3d-game/SKILL.md +113 -0
- package/skills/threejs-3d-game/agents/openai.yaml +7 -0
- package/skills/threejs-3d-game/references/engine-asset-pipeline.md +116 -0
- package/skills/threejs-3d-game/references/engine-audio.md +70 -0
- package/skills/threejs-3d-game/references/engine-input-camera.md +84 -0
- package/skills/threejs-3d-game/references/engine-performance.md +96 -0
- package/skills/threejs-3d-game/references/engine-physics.md +142 -0
- package/skills/threejs-3d-game/references/engine-runtime.md +199 -0
- package/skills/threejs-3d-game/references/file-structure.md +353 -0
- package/skills/threejs-aaa-graphics-builder/SKILL.md +62 -0
- package/skills/threejs-aaa-graphics-builder/agents/openai.yaml +7 -0
- package/skills/threejs-aaa-graphics-builder/assets/scorecard-anchors/scene-1.jpg +0 -0
- package/skills/threejs-aaa-graphics-builder/assets/scorecard-anchors/scene-2.jpg +0 -0
- package/skills/threejs-aaa-graphics-builder/assets/scorecard-anchors/scene-3.jpg +0 -0
- package/skills/threejs-aaa-graphics-builder/references/checklists/aaa-game-quality-gate.md +23 -0
- package/skills/threejs-aaa-graphics-builder/references/checklists/aaa-visual-scorecard.md +19 -0
- package/skills/threejs-aaa-graphics-builder/references/checklists/material-lighting-quality.md +14 -0
- package/skills/threejs-aaa-graphics-builder/references/checklists/performance-safe-visual-detail.md +14 -0
- package/skills/threejs-aaa-graphics-builder/references/checklists/procedural-model-quality.md +15 -0
- package/skills/threejs-aaa-graphics-builder/references/checklists/technical-art-quality.md +17 -0
- package/skills/threejs-aaa-graphics-builder/references/graphics-prompt-templates.md +236 -0
- package/skills/threejs-aaa-graphics-builder/references/implementation-blueprint.md +161 -0
- package/skills/threejs-aaa-graphics-builder/references/model-recipes.md +146 -0
- package/skills/threejs-aaa-graphics-builder/references/render-recipes.md +90 -0
- package/skills/threejs-aaa-graphics-builder/references/shader-cookbook.md +292 -0
- package/skills/threejs-aaa-graphics-builder/references/technical-art.md +167 -0
- package/skills/threejs-aaa-graphics-builder/references/visual-scorecard.md +147 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 智能切分:从一张含多主体的图中提取连通区域,按阅读顺序返回裁切 dataURL。
|
|
3
|
+
* 纯浏览器 Canvas,无外部依赖。
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
function isForeground(r, g, b, a, bg) {
|
|
7
|
+
if (a < 24) return false
|
|
8
|
+
// 相对背景色差够大才算前景(兼容白底 / 棋盘格近似色)
|
|
9
|
+
const dr = r - bg.r
|
|
10
|
+
const dg = g - bg.g
|
|
11
|
+
const db = b - bg.b
|
|
12
|
+
const dist = Math.sqrt(dr * dr + dg * dg + db * db)
|
|
13
|
+
return dist > 28 || a < 250 && a > 24
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function sampleBackground(data, w, h) {
|
|
17
|
+
// 取四角均值作为背景估计
|
|
18
|
+
const pts = [
|
|
19
|
+
[0, 0],
|
|
20
|
+
[w - 1, 0],
|
|
21
|
+
[0, h - 1],
|
|
22
|
+
[w - 1, h - 1],
|
|
23
|
+
[Math.floor(w / 2), 0],
|
|
24
|
+
[0, Math.floor(h / 2)],
|
|
25
|
+
]
|
|
26
|
+
let r = 0
|
|
27
|
+
let g = 0
|
|
28
|
+
let b = 0
|
|
29
|
+
let n = 0
|
|
30
|
+
for (const [x, y] of pts) {
|
|
31
|
+
const i = (y * w + x) * 4
|
|
32
|
+
r += data[i]
|
|
33
|
+
g += data[i + 1]
|
|
34
|
+
b += data[i + 2]
|
|
35
|
+
n += 1
|
|
36
|
+
}
|
|
37
|
+
return { r: r / n, g: g / n, b: b / n }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function loadImageElement(url) {
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
42
|
+
const img = new Image()
|
|
43
|
+
img.crossOrigin = 'anonymous'
|
|
44
|
+
img.onload = () => resolve(img)
|
|
45
|
+
img.onerror = () => reject(new Error('图片加载失败'))
|
|
46
|
+
img.src = url
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @param {string} imageUrl
|
|
52
|
+
* @returns {Promise<string[]>} PNG dataURL 列表(至少 2 张才有意义;找不到则空数组)
|
|
53
|
+
*/
|
|
54
|
+
export async function smartSplitImage(imageUrl) {
|
|
55
|
+
const img = await loadImageElement(imageUrl)
|
|
56
|
+
const maxSide = 1600
|
|
57
|
+
const scale = Math.min(1, maxSide / Math.max(img.naturalWidth, img.naturalHeight))
|
|
58
|
+
const w = Math.max(1, Math.round(img.naturalWidth * scale))
|
|
59
|
+
const h = Math.max(1, Math.round(img.naturalHeight * scale))
|
|
60
|
+
|
|
61
|
+
const canvas = document.createElement('canvas')
|
|
62
|
+
canvas.width = w
|
|
63
|
+
canvas.height = h
|
|
64
|
+
const ctx = canvas.getContext('2d', { willReadFrequently: true })
|
|
65
|
+
ctx.drawImage(img, 0, 0, w, h)
|
|
66
|
+
const { data } = ctx.getImageData(0, 0, w, h)
|
|
67
|
+
const bg = sampleBackground(data, w, h)
|
|
68
|
+
|
|
69
|
+
const visited = new Uint8Array(w * h)
|
|
70
|
+
const boxes = []
|
|
71
|
+
const minArea = Math.max(64, Math.floor((w * h) / 800))
|
|
72
|
+
const queue = new Int32Array(w * h)
|
|
73
|
+
|
|
74
|
+
for (let y = 0; y < h; y += 1) {
|
|
75
|
+
for (let x = 0; x < w; x += 1) {
|
|
76
|
+
const start = y * w + x
|
|
77
|
+
if (visited[start]) continue
|
|
78
|
+
const i0 = start * 4
|
|
79
|
+
if (!isForeground(data[i0], data[i0 + 1], data[i0 + 2], data[i0 + 3], bg)) {
|
|
80
|
+
visited[start] = 1
|
|
81
|
+
continue
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
let qh = 0
|
|
85
|
+
let qt = 0
|
|
86
|
+
queue[qt++] = start
|
|
87
|
+
visited[start] = 1
|
|
88
|
+
let minX = x
|
|
89
|
+
let maxX = x
|
|
90
|
+
let minY = y
|
|
91
|
+
let maxY = y
|
|
92
|
+
let area = 0
|
|
93
|
+
|
|
94
|
+
while (qh < qt) {
|
|
95
|
+
const p = queue[qh++]
|
|
96
|
+
const px = p % w
|
|
97
|
+
const py = (p / w) | 0
|
|
98
|
+
area += 1
|
|
99
|
+
if (px < minX) minX = px
|
|
100
|
+
if (px > maxX) maxX = px
|
|
101
|
+
if (py < minY) minY = py
|
|
102
|
+
if (py > maxY) maxY = py
|
|
103
|
+
|
|
104
|
+
const neighbors = [p - 1, p + 1, p - w, p + w]
|
|
105
|
+
for (const n of neighbors) {
|
|
106
|
+
if (n < 0 || n >= w * h) continue
|
|
107
|
+
if (visited[n]) continue
|
|
108
|
+
const nx = n % w
|
|
109
|
+
const ny = (n / w) | 0
|
|
110
|
+
// 防跨行左右邻居
|
|
111
|
+
if (Math.abs(nx - px) + Math.abs(ny - py) !== 1) continue
|
|
112
|
+
const ni = n * 4
|
|
113
|
+
if (!isForeground(data[ni], data[ni + 1], data[ni + 2], data[ni + 3], bg)) {
|
|
114
|
+
visited[n] = 1
|
|
115
|
+
continue
|
|
116
|
+
}
|
|
117
|
+
visited[n] = 1
|
|
118
|
+
queue[qt++] = n
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const bw = maxX - minX + 1
|
|
123
|
+
const bh = maxY - minY + 1
|
|
124
|
+
if (area >= minArea && bw >= 8 && bh >= 8) {
|
|
125
|
+
// 过滤几乎铺满整图的单一大块(切不出多图)
|
|
126
|
+
if (bw * bh < w * h * 0.92) {
|
|
127
|
+
boxes.push({ minX, minY, maxX, maxY, area })
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (boxes.length < 2) return []
|
|
134
|
+
|
|
135
|
+
// 阅读顺序:先上后下,同行按左到右
|
|
136
|
+
const rowTol = Math.max(12, Math.floor(h * 0.03))
|
|
137
|
+
boxes.sort((a, b) => {
|
|
138
|
+
if (Math.abs(a.minY - b.minY) > rowTol) return a.minY - b.minY
|
|
139
|
+
return a.minX - b.minX
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
// 原图尺寸裁切(更高清),并统一到完全相同的画布尺寸,保证序列播放不抖动
|
|
143
|
+
const inv = 1 / scale
|
|
144
|
+
const crops = []
|
|
145
|
+
for (const box of boxes) {
|
|
146
|
+
const sx = Math.max(0, Math.floor(box.minX * inv))
|
|
147
|
+
const sy = Math.max(0, Math.floor(box.minY * inv))
|
|
148
|
+
const sw = Math.min(img.naturalWidth - sx, Math.ceil((box.maxX - box.minX + 1) * inv))
|
|
149
|
+
const sh = Math.min(img.naturalHeight - sy, Math.ceil((box.maxY - box.minY + 1) * inv))
|
|
150
|
+
if (sw < 4 || sh < 4) continue
|
|
151
|
+
crops.push({ sx, sy, sw, sh })
|
|
152
|
+
}
|
|
153
|
+
if (crops.length < 2) return []
|
|
154
|
+
|
|
155
|
+
// 统一尺寸:先按最高补上方白边,再按最宽左右均匀补白边
|
|
156
|
+
const frameW = Math.max(...crops.map((c) => c.sw))
|
|
157
|
+
const frameH = Math.max(...crops.map((c) => c.sh))
|
|
158
|
+
const full = document.createElement('canvas')
|
|
159
|
+
full.width = frameW
|
|
160
|
+
full.height = frameH
|
|
161
|
+
const fctx = full.getContext('2d')
|
|
162
|
+
|
|
163
|
+
const out = []
|
|
164
|
+
for (const crop of crops) {
|
|
165
|
+
fctx.fillStyle = '#ffffff'
|
|
166
|
+
fctx.fillRect(0, 0, frameW, frameH)
|
|
167
|
+
const padTop = frameH - crop.sh
|
|
168
|
+
const padX = frameW - crop.sw
|
|
169
|
+
const dx = Math.floor(padX / 2)
|
|
170
|
+
const dy = padTop
|
|
171
|
+
fctx.drawImage(
|
|
172
|
+
img,
|
|
173
|
+
crop.sx,
|
|
174
|
+
crop.sy,
|
|
175
|
+
crop.sw,
|
|
176
|
+
crop.sh,
|
|
177
|
+
dx,
|
|
178
|
+
dy,
|
|
179
|
+
crop.sw,
|
|
180
|
+
crop.sh,
|
|
181
|
+
)
|
|
182
|
+
out.push(full.toDataURL('image/png'))
|
|
183
|
+
}
|
|
184
|
+
return out
|
|
185
|
+
}
|