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:
@@ -290,6 +290,148 @@ test('buildCreationWorkShelfItems falls back to available gameplay images as cov
|
||||
);
|
||||
});
|
||||
|
||||
test('buildCreationWorkShelfItems uses generated object keys as cover sources', () => {
|
||||
const items = buildCreationWorkShelfItems({
|
||||
rpgItems: [],
|
||||
bigFishItems: [],
|
||||
puzzleItems: [
|
||||
{
|
||||
workId: 'puzzle:level-object-key',
|
||||
profileId: 'puzzle-profile-level-object-key',
|
||||
ownerUserId: 'user-1',
|
||||
authorDisplayName: '测试作者',
|
||||
levelName: '关卡对象拼图',
|
||||
summary: '作品摘要带关卡图对象路径时用关卡图做卡片背景。',
|
||||
themeTags: [],
|
||||
coverImageSrc: null,
|
||||
publicationStatus: 'draft',
|
||||
updatedAt: '2026-05-08T00:00:00.000Z',
|
||||
publishedAt: null,
|
||||
publishReady: false,
|
||||
levels: [
|
||||
{
|
||||
levelId: 'level-1',
|
||||
levelName: '第一关',
|
||||
pictureDescription: '港口雨夜。',
|
||||
candidates: [
|
||||
{
|
||||
candidateId: 'candidate-1',
|
||||
imageSrc: '',
|
||||
assetId: 'asset-1',
|
||||
prompt: '港口雨夜',
|
||||
sourceType: 'generated',
|
||||
selected: true,
|
||||
},
|
||||
],
|
||||
selectedCandidateId: 'candidate-1',
|
||||
coverImageSrc:
|
||||
'generated-puzzle-assets/session/profile/level-cover.png',
|
||||
coverAssetId: null,
|
||||
generationStatus: 'ready',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
match3dItems: [
|
||||
{
|
||||
workId: 'match3d:object-key-cover',
|
||||
profileId: 'match3d-profile-object-key-cover',
|
||||
ownerUserId: 'user-1',
|
||||
gameName: '对象路径抓鹅',
|
||||
themeText: '糖果厨房',
|
||||
summary: '背景图或物品图只有 object key 时也应展示。',
|
||||
tags: [],
|
||||
coverImageSrc: null,
|
||||
clearCount: 18,
|
||||
difficulty: 1,
|
||||
publicationStatus: 'draft',
|
||||
playCount: 0,
|
||||
updatedAt: '2026-05-07T00:00:00.000Z',
|
||||
publishReady: false,
|
||||
generatedBackgroundAsset: {
|
||||
prompt: '糖果厨房背景',
|
||||
imageObjectKey:
|
||||
'generated-match3d-assets/session/profile/background/image.png',
|
||||
containerImageObjectKey:
|
||||
'generated-match3d-assets/session/profile/background/container.png',
|
||||
status: 'ready',
|
||||
},
|
||||
generatedItemAssets: [
|
||||
{
|
||||
itemId: 'item-1',
|
||||
itemName: '糖果',
|
||||
imageObjectKey:
|
||||
'generated-match3d-assets/session/profile/items/item-1/image.png',
|
||||
imageViews: [
|
||||
{
|
||||
viewId: 'view-1',
|
||||
viewIndex: 1,
|
||||
imageObjectKey:
|
||||
'generated-match3d-assets/session/profile/items/item-1/views/view-1.png',
|
||||
},
|
||||
],
|
||||
status: 'image_ready',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(items.find((item) => item.kind === 'puzzle')?.coverImageSrc).toBe(
|
||||
'generated-puzzle-assets/session/profile/level-cover.png',
|
||||
);
|
||||
expect(items.find((item) => item.kind === 'match3d')?.coverImageSrc).toBe(
|
||||
'generated-match3d-assets/session/profile/background/image.png',
|
||||
);
|
||||
});
|
||||
|
||||
test('buildCreationWorkShelfItems falls back to match3d item object key without background', () => {
|
||||
const items = buildCreationWorkShelfItems({
|
||||
rpgItems: [],
|
||||
bigFishItems: [],
|
||||
puzzleItems: [],
|
||||
match3dItems: [
|
||||
{
|
||||
workId: 'match3d:item-object-key-cover',
|
||||
profileId: 'match3d-profile-item-object-key-cover',
|
||||
ownerUserId: 'user-1',
|
||||
gameName: '物品对象路径抓鹅',
|
||||
themeText: '糖果厨房',
|
||||
summary: '背景图缺失时用物品视角图对象路径。',
|
||||
tags: [],
|
||||
coverImageSrc: null,
|
||||
clearCount: 18,
|
||||
difficulty: 1,
|
||||
publicationStatus: 'draft',
|
||||
playCount: 0,
|
||||
updatedAt: '2026-05-07T00:00:00.000Z',
|
||||
publishReady: false,
|
||||
generatedItemAssets: [
|
||||
{
|
||||
itemId: 'item-1',
|
||||
itemName: '糖果',
|
||||
imageObjectKey:
|
||||
'generated-match3d-assets/session/profile/items/item-1/image.png',
|
||||
imageViews: [
|
||||
{
|
||||
viewId: 'view-1',
|
||||
viewIndex: 1,
|
||||
imageObjectKey:
|
||||
'generated-match3d-assets/session/profile/items/item-1/views/view-1.png',
|
||||
},
|
||||
],
|
||||
status: 'image_ready',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(items.find((item) => item.kind === 'match3d')?.coverImageSrc).toBe(
|
||||
'generated-match3d-assets/session/profile/items/item-1/views/view-1.png',
|
||||
);
|
||||
});
|
||||
|
||||
test('getCreationWorkShelfItemTime parses backend seconds.microsZ values', () => {
|
||||
expect(getCreationWorkShelfItemTime('1778457601.234567Z')).toBe(
|
||||
1778457601234.567,
|
||||
|
||||
Reference in New Issue
Block a user