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:
2026-05-14 20:34:45 +08:00
parent d33c937ebc
commit 548db78ca7
103 changed files with 6687 additions and 3270 deletions

View File

@@ -26,7 +26,6 @@ describe('miniGameDraftGenerationProgress', () => {
'编译首关草稿',
'生成关卡名称',
'生成首关画面',
'生成背景音乐',
'生成UI背景',
'写入正式草稿',
]);
@@ -34,7 +33,7 @@ describe('miniGameDraftGenerationProgress', () => {
expect(progress?.steps[0]?.detail).toBe(
'读取画面描述,建立可编辑草稿与首关结构。',
);
expect(progress?.estimatedRemainingMs).toBe(178_500);
expect(progress?.estimatedRemainingMs).toBe(130_500);
expect(progress?.overallProgress).toBeGreaterThan(0);
expect(progress?.steps[0]?.completed).toBeGreaterThan(0);
});
@@ -50,22 +49,19 @@ describe('miniGameDraftGenerationProgress', () => {
};
const imageProgress = buildMiniGameDraftGenerationProgress(state, 26_000);
const musicProgress = buildMiniGameDraftGenerationProgress(state, 96_000);
const uiProgress = buildMiniGameDraftGenerationProgress(state, 146_000);
const writeBackProgress = buildMiniGameDraftGenerationProgress(state, 176_000);
const uiProgress = buildMiniGameDraftGenerationProgress(state, 96_000);
const writeBackProgress = buildMiniGameDraftGenerationProgress(state, 126_000);
expect(imageProgress?.phaseId).toBe('puzzle-images');
expect(imageProgress?.estimatedRemainingMs).toBe(155_000);
expect(imageProgress?.estimatedRemainingMs).toBe(107_000);
expect(imageProgress?.steps[1]?.status).toBe('completed');
expect(imageProgress?.steps[2]?.status).toBe('active');
expect(imageProgress?.steps[2]?.completed).toBeGreaterThan(0);
expect(musicProgress?.phaseId).toBe('puzzle-background-music');
expect(musicProgress?.phaseLabel).toBe('生成背景音乐');
expect(uiProgress?.phaseId).toBe('puzzle-ui-background');
expect(writeBackProgress?.phaseId).toBe('puzzle-select-image');
expect(writeBackProgress?.estimatedRemainingMs).toBe(5_000);
expect(writeBackProgress?.steps[4]?.status).toBe('completed');
expect(writeBackProgress?.steps[5]?.status).toBe('active');
expect(writeBackProgress?.estimatedRemainingMs).toBe(7_000);
expect(writeBackProgress?.steps[3]?.status).toBe('completed');
expect(writeBackProgress?.steps[4]?.status).toBe('active');
});
test('puzzle draft generation keeps moving without claiming completion before response', () => {
@@ -83,7 +79,7 @@ describe('miniGameDraftGenerationProgress', () => {
expect(progress?.phaseId).toBe('puzzle-select-image');
expect(progress?.overallProgress).toBe(98);
expect(progress?.estimatedRemainingMs).toBe(0);
expect(progress?.steps[5]?.completed).toBe(1);
expect(progress?.steps[4]?.completed).toBe(1);
});
test('puzzle ready copy points to result page work info completion', () => {
@@ -177,13 +173,12 @@ describe('miniGameDraftGenerationProgress', () => {
'match3d-slice-images',
'match3d-upload-images',
'match3d-generate-views',
'match3d-background-music',
'match3d-background-image',
'match3d-write-draft',
]);
expect(progress?.phaseId).toBe('match3d-material-sheet');
expect(progress?.phaseLabel).toBe('分批生成素材图');
expect(progress?.estimatedRemainingMs).toBe(570_000);
expect(progress?.estimatedRemainingMs).toBe(480_000);
});
test('match3d draft generation starts from title generation', () => {
@@ -215,29 +210,23 @@ describe('miniGameDraftGenerationProgress', () => {
);
expect(progress?.phaseId).toBe('match3d-generate-views');
expect(progress?.steps[6]?.detail).toContain('音效提示词');
expect(progress?.steps[6]?.detail).toContain('五视角图片');
expect(progress?.steps[6]?.completed).toBe(1);
expect(progress?.steps[6]?.total).toBe(3);
});
test('match3d draft generation reaches music, background image and writeback phases', () => {
test('match3d draft generation reaches background image and writeback phases', () => {
const state = createMiniGameDraftGenerationState('match3d');
const musicProgress = buildMiniGameDraftGenerationProgress(
const backgroundProgress = buildMiniGameDraftGenerationProgress(
state,
state.startedAtMs + 400_000,
);
const backgroundProgress = buildMiniGameDraftGenerationProgress(
const writeProgress = buildMiniGameDraftGenerationProgress(
state,
state.startedAtMs + 500_000,
);
const writeProgress = buildMiniGameDraftGenerationProgress(
state,
state.startedAtMs + 550_000,
);
expect(musicProgress?.phaseId).toBe('match3d-background-music');
expect(musicProgress?.phaseLabel).toBe('生成背景音乐');
expect(backgroundProgress?.phaseId).toBe('match3d-background-image');
expect(backgroundProgress?.phaseLabel).toBe('生成UI背景');
expect(writeProgress?.phaseId).toBe('match3d-write-draft');