Update Match3D/image-generation docs & code
Adds/updates documentation, assets and implementation for Match3D and puzzle image generation workflows. Key changes: decision logs and pitfalls updated to prefer VectorEngine Gemini for Match3D material sheets and to require edits (multipart) for 1:1 container reference images; guidance added for when to use APIMart vs VectorEngine. .env.example clarified APIMart/Responses config. Many new public assets and PPT visuals added. Code changes across frontend and backend: updated shared contracts, server-rs match3d/puzzle/image-generation handlers, VectorEngine/OpenAI image generation clients, and multiple React components/tests to handle UI/background/container image signing, edits workflow, and puzzle UI background resolution. Added src/services/puzzle-runtime/puzzleUiBackgroundSource.ts and related test updates. Includes notes about multipart HTTP/1.1 requirement and test/verification commands in docs.
This commit is contained in:
@@ -43,7 +43,6 @@ export type MiniGameDraftGenerationPhase =
|
||||
| 'match3d-slice-images'
|
||||
| 'match3d-upload-images'
|
||||
| 'match3d-generate-views'
|
||||
| 'match3d-background-music'
|
||||
| 'match3d-background-image'
|
||||
| 'match3d-write-draft'
|
||||
| 'match3d-ready'
|
||||
@@ -51,7 +50,6 @@ export type MiniGameDraftGenerationPhase =
|
||||
| 'baby-object-images'
|
||||
| 'baby-object-ready'
|
||||
| 'puzzle-images'
|
||||
| 'puzzle-background-music'
|
||||
| 'puzzle-ui-background'
|
||||
| 'puzzle-select-image'
|
||||
| 'ready'
|
||||
@@ -98,27 +96,21 @@ const PUZZLE_STEPS = [
|
||||
detail: '调用图片模型生成适合切块的正方形首图。',
|
||||
weight: 42,
|
||||
},
|
||||
{
|
||||
id: 'puzzle-background-music',
|
||||
label: '生成背景音乐',
|
||||
detail: '用作品题目生成纯音乐并转存音频资产。',
|
||||
weight: 18,
|
||||
},
|
||||
{
|
||||
id: 'puzzle-ui-background',
|
||||
label: '生成UI背景',
|
||||
detail: '生成不含槽位和控件的 9:16 纯背景。',
|
||||
weight: 14,
|
||||
weight: 32,
|
||||
},
|
||||
{
|
||||
id: 'puzzle-select-image',
|
||||
label: '写入正式草稿',
|
||||
detail: '写入首图、音乐、UI背景和首关数据。',
|
||||
detail: '写入首图、UI背景和首关数据。',
|
||||
weight: 8,
|
||||
},
|
||||
] as const satisfies ReadonlyArray<MiniGameStepDefinition>;
|
||||
|
||||
const PUZZLE_ESTIMATED_WAIT_MS = 180_000;
|
||||
const PUZZLE_ESTIMATED_WAIT_MS = 132_000;
|
||||
const PUZZLE_NON_READY_MAX_PROGRESS = 98;
|
||||
const PUZZLE_PHASE_TIMELINE: Array<{
|
||||
phase: Extract<
|
||||
@@ -126,7 +118,6 @@ const PUZZLE_PHASE_TIMELINE: Array<{
|
||||
| 'compile'
|
||||
| 'puzzle-level-name'
|
||||
| 'puzzle-images'
|
||||
| 'puzzle-background-music'
|
||||
| 'puzzle-ui-background'
|
||||
| 'puzzle-select-image'
|
||||
>;
|
||||
@@ -135,7 +126,6 @@ const PUZZLE_PHASE_TIMELINE: Array<{
|
||||
{ phase: 'compile', durationMs: 12_000 },
|
||||
{ phase: 'puzzle-level-name', durationMs: 8_000 },
|
||||
{ phase: 'puzzle-images', durationMs: 70_000 },
|
||||
{ phase: 'puzzle-background-music', durationMs: 48_000 },
|
||||
{ phase: 'puzzle-ui-background', durationMs: 32_000 },
|
||||
{ phase: 'puzzle-select-image', durationMs: 10_000 },
|
||||
];
|
||||
@@ -192,7 +182,7 @@ const MATCH3D_STEPS = [
|
||||
{
|
||||
id: 'match3d-item-names',
|
||||
label: '生成作品计划',
|
||||
detail: '生成游戏名称、物品名称、音乐名称与标签。',
|
||||
detail: '生成游戏名称、物品名称与标签。',
|
||||
weight: 10,
|
||||
},
|
||||
{
|
||||
@@ -205,31 +195,25 @@ const MATCH3D_STEPS = [
|
||||
id: 'match3d-material-sheet',
|
||||
label: '分批生成素材图',
|
||||
detail: '按 1K 参数分批生成 5x5 多视角素材图。',
|
||||
weight: 22,
|
||||
weight: 24,
|
||||
},
|
||||
{
|
||||
id: 'match3d-slice-images',
|
||||
label: '切割独立图片',
|
||||
detail: '把素材图切成每个物品的五个视角。',
|
||||
weight: 10,
|
||||
weight: 12,
|
||||
},
|
||||
{
|
||||
id: 'match3d-upload-images',
|
||||
label: '上传图片资产',
|
||||
detail: '上传每个物品的 2D 五视角素材。',
|
||||
weight: 12,
|
||||
weight: 14,
|
||||
},
|
||||
{
|
||||
id: 'match3d-generate-views',
|
||||
label: '校验素材结构',
|
||||
detail: '确认物品顺序、五视角图片和音效提示词。',
|
||||
weight: 6,
|
||||
},
|
||||
{
|
||||
id: 'match3d-background-music',
|
||||
label: '生成背景音乐',
|
||||
detail: '用音乐名称生成纯音乐并转存音频资产。',
|
||||
weight: 14,
|
||||
detail: '确认物品顺序和五视角图片。',
|
||||
weight: 8,
|
||||
},
|
||||
{
|
||||
id: 'match3d-background-image',
|
||||
@@ -240,11 +224,13 @@ const MATCH3D_STEPS = [
|
||||
{
|
||||
id: 'match3d-write-draft',
|
||||
label: '写入草稿页',
|
||||
detail: '保存素材、音乐、背景、容器和作品草稿。',
|
||||
detail: '保存素材、背景、容器和作品草稿。',
|
||||
weight: 2,
|
||||
},
|
||||
] as const satisfies ReadonlyArray<MiniGameStepDefinition>;
|
||||
|
||||
const MATCH3D_ESTIMATED_WAIT_MS = 510_000;
|
||||
|
||||
const MATCH3D_PHASE_ORDER: Partial<
|
||||
Record<MiniGameDraftGenerationPhase, number>
|
||||
> = {
|
||||
@@ -255,9 +241,8 @@ const MATCH3D_PHASE_ORDER: Partial<
|
||||
'match3d-slice-images': 4,
|
||||
'match3d-upload-images': 5,
|
||||
'match3d-generate-views': 6,
|
||||
'match3d-background-music': 7,
|
||||
'match3d-background-image': 8,
|
||||
'match3d-write-draft': 9,
|
||||
'match3d-background-image': 7,
|
||||
'match3d-write-draft': 8,
|
||||
};
|
||||
|
||||
const BABY_OBJECT_MATCH_STEPS = [
|
||||
@@ -392,25 +377,23 @@ function resolveMatch3DPhaseByElapsedMs(
|
||||
currentPhase: MiniGameDraftGenerationPhase,
|
||||
): MiniGameDraftGenerationPhase {
|
||||
const elapsedPhase =
|
||||
elapsedMs >= 540_000
|
||||
elapsedMs >= 492_000
|
||||
? 'match3d-write-draft'
|
||||
: elapsedMs >= 460_000
|
||||
: elapsedMs >= 370_000
|
||||
? 'match3d-background-image'
|
||||
: elapsedMs >= 370_000
|
||||
? 'match3d-background-music'
|
||||
: elapsedMs >= 340_000
|
||||
? 'match3d-generate-views'
|
||||
: elapsedMs >= 260_000
|
||||
? 'match3d-upload-images'
|
||||
: elapsedMs >= 210_000
|
||||
? 'match3d-slice-images'
|
||||
: elapsedMs >= 28_000
|
||||
? 'match3d-material-sheet'
|
||||
: elapsedMs >= 12_000
|
||||
? 'match3d-background-prompt'
|
||||
: elapsedMs >= 4_000
|
||||
? 'match3d-item-names'
|
||||
: 'match3d-work-title';
|
||||
: elapsedMs >= 340_000
|
||||
? 'match3d-generate-views'
|
||||
: elapsedMs >= 260_000
|
||||
? 'match3d-upload-images'
|
||||
: elapsedMs >= 210_000
|
||||
? 'match3d-slice-images'
|
||||
: elapsedMs >= 28_000
|
||||
? 'match3d-material-sheet'
|
||||
: elapsedMs >= 12_000
|
||||
? 'match3d-background-prompt'
|
||||
: elapsedMs >= 4_000
|
||||
? 'match3d-item-names'
|
||||
: 'match3d-work-title';
|
||||
const elapsedOrder = MATCH3D_PHASE_ORDER[elapsedPhase] ?? 0;
|
||||
const currentOrder = MATCH3D_PHASE_ORDER[currentPhase] ?? -1;
|
||||
return currentOrder > elapsedOrder ? currentPhase : elapsedPhase;
|
||||
@@ -579,7 +562,7 @@ export function buildMiniGameDraftGenerationProgress(
|
||||
: normalizedState.kind === 'square-hole'
|
||||
? Math.max(0, 12_000 - elapsedMs)
|
||||
: normalizedState.kind === 'match3d'
|
||||
? Math.max(0, 10 * 60_000 - elapsedMs)
|
||||
? Math.max(0, MATCH3D_ESTIMATED_WAIT_MS - elapsedMs)
|
||||
: normalizedState.kind === 'baby-object-match'
|
||||
? Math.max(0, 60_000 - elapsedMs)
|
||||
: null,
|
||||
|
||||
Reference in New Issue
Block a user