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

@@ -56,10 +56,10 @@ const testEntryConfig = {
id: 'visual-novel',
title: '视觉小说',
subtitle: '分支叙事体验',
badge: '可创建',
badge: '敬请期待',
imageSrc: '/creation-type-references/visual-novel.webp',
visible: true,
open: true,
visible: false,
open: false,
sortOrder: 60,
updatedAtMicros: 1,
},
@@ -217,9 +217,11 @@ test('creation hub marks generating and newly completed drafts', () => {
expect(html).toContain('生成中');
expect(html).toContain('aria-label="新生成完成"');
expect(html).toContain('生成中...');
expect(html).toContain('creation-work-card__spinner');
});
test('creation hub published work spans full mobile row', () => {
test('creation hub published work uses unified list card layout', () => {
const html = renderToStaticMarkup(
<CustomWorldCreationHub
items={[]}
@@ -253,9 +255,10 @@ test('creation hub published work spans full mobile row', () => {
/>,
);
expect(html).toContain('grid-cols-2');
expect(html).toContain('col-span-2 sm:col-span-1');
expect(html).not.toContain('grid-cols-1 gap-3 md:grid-cols-2');
expect(html).toContain('creation-work-list');
expect(html).toContain('platform-category-game-item');
expect(html).toContain('creation-work-card__side-cover');
expect(html).not.toContain('col-span-2 sm:col-span-1');
});
test('creation hub draft cards use cover background and hide updated time', () => {
@@ -318,9 +321,109 @@ test('creation hub draft cards use cover background and hide updated time', () =
expect(html).toContain(
'class="absolute inset-0 h-full w-full object-cover" src="/covers/new-draft.webp"',
);
expect(html).toContain('creation-work-card__side-cover');
expect(html).toContain('src="/covers/new-draft.webp"');
expect(html).toContain(
'--creation-work-card-cover-fallback:url(/creation-type-references/puzzle.webp)',
);
expect(html).not.toContain('1778457601.234567Z');
expect(html).not.toContain('2026-05-07');
expect(html).not.toContain('更新于');
expect(html).not.toContain('最后修改');
});
test('creation hub draft cards fall back to creation type cover when cover is missing', () => {
const html = renderToStaticMarkup(
<CustomWorldCreationHub
mode="works-only"
items={[]}
puzzleItems={[
{
workId: 'puzzle:no-cover-draft',
profileId: 'puzzle-profile-no-cover',
ownerUserId: 'user-1',
authorDisplayName: '测试作者',
workTitle: '缺少封面的拼图草稿',
workDescription: '没有生成封面时也需要保留图像背景。',
levelName: '缺少封面的拼图草稿',
summary: '没有生成封面时也需要保留图像背景。',
themeTags: [],
coverImageSrc: null,
publicationStatus: 'draft',
updatedAt: '2026-05-07T00:00:00.000Z',
publishedAt: null,
publishReady: false,
},
]}
loading={false}
error={null}
onRetry={() => {}}
onCreateType={noopCreateType}
onOpenDraft={() => {}}
onEnterPublished={() => {}}
entryConfig={testEntryConfig}
creationTypes={testCreationTypes}
onOpenPuzzleDetail={() => {}}
/>,
);
expect(html).toContain('缺少封面的拼图草稿');
expect(html).toContain(
'class="absolute inset-0 h-full w-full object-cover" src="/creation-type-references/puzzle.webp"',
);
expect(html).toContain(
'--creation-work-card-cover-fallback:url(/creation-type-references/puzzle.webp)',
);
expect(html).not.toContain('>封面</div>');
});
test('creation hub published card keeps publish info without fixed action text', () => {
const html = renderToStaticMarkup(
<CustomWorldCreationHub
mode="works-only"
items={[]}
puzzleItems={[
{
workId: 'puzzle:published-card',
profileId: 'puzzle-profile-published',
ownerUserId: 'user-1',
authorDisplayName: '测试作者',
workTitle: '统一卡片作品',
workDescription: '作品卡仍要保留原有的积分与统计信息。',
levelName: '统一卡片作品',
summary: '作品卡仍要保留原有的积分与统计信息。',
themeTags: ['潮雾'],
coverImageSrc: '/covers/unified-card.webp',
publicationStatus: 'published',
updatedAt: '2026-05-07T00:00:00.000Z',
publishedAt: '2026-05-07T00:00:00.000Z',
playCount: 88,
remixCount: 9,
likeCount: 6,
publishReady: true,
pointIncentiveTotalPoints: 4,
pointIncentiveClaimablePoints: 1,
},
]}
loading={false}
error={null}
onRetry={() => {}}
onCreateType={noopCreateType}
onOpenDraft={() => {}}
onEnterPublished={() => {}}
entryConfig={testEntryConfig}
creationTypes={testCreationTypes}
onOpenPuzzleDetail={() => {}}
onClaimPuzzlePointIncentive={() => {}}
/>,
);
expect(html).toContain('积分激励');
expect(html).toContain('待领取');
expect(html).toContain('游玩');
expect(html).toContain('改造');
expect(html).toContain('点赞');
expect(html).toContain('creation-work-card__side-cover');
expect(html).not.toContain('creation-work-card__action');
expect(html).not.toContain('>查看详情<');
});