Increase VectorEngine timeouts and add image UI

Add VectorEngine image generation config and raise request timeouts (env + scripts) from 180000 to 1000000ms. Introduce a reusable CreativeImageInputPanel component with tests and wire up mobile keyboard-focus helpers; update generation views and related tests (CustomWorldGenerationView, BarkBattle editor, Match3D, Puzzle flows). Improve API error handling / VectorEngine request guidance (packages/shared http.ts and docs), and apply multiple backend/frontend fixes for puzzle/match3d/prompt handling. Also include extensive docs and decision-log updates describing UI/UX decisions and verification steps.
This commit is contained in:
2026-05-15 02:40:59 +08:00
parent 4642855fd0
commit 74fd9a33ac
87 changed files with 5508 additions and 1261 deletions

View File

@@ -393,7 +393,7 @@ test('buildCreationWorkShelfItems uses generated object keys as cover sources',
'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',
'generated-match3d-assets/session/profile/background/container.png',
);
});
@@ -444,6 +444,182 @@ test('buildCreationWorkShelfItems falls back to match3d item object key without
);
});
test('buildCreationWorkShelfItems ignores puzzle theme reference cover and uses first level image', () => {
const items = buildCreationWorkShelfItems({
rpgItems: [],
bigFishItems: [],
puzzleItems: [
{
workId: 'puzzle:theme-reference-cover',
profileId: 'puzzle-profile-theme-reference-cover',
ownerUserId: 'user-1',
authorDisplayName: '测试作者',
levelName: '主题兜底拼图',
summary: '摘要里的封面是玩法参考图时,用第一关画面兜底。',
themeTags: [],
coverImageSrc: '/creation-type-references/puzzle.webp',
publicationStatus: 'draft',
updatedAt: '2026-05-08T00:00:00.000Z',
publishedAt: null,
publishReady: false,
levels: [
{
levelId: 'level-1',
levelName: '第一关',
pictureDescription: '第一关画面。',
candidates: [
{
candidateId: 'candidate-1',
imageSrc: '/puzzle-first-level-candidate.png',
assetId: 'asset-1',
prompt: '第一关画面',
sourceType: 'generated',
selected: true,
},
],
selectedCandidateId: 'candidate-1',
coverImageSrc: '/puzzle-first-level-cover.png',
coverAssetId: 'asset-1',
generationStatus: 'ready',
},
],
},
],
});
expect(items.find((item) => item.kind === 'puzzle')?.coverImageSrc).toBe(
'/puzzle-first-level-cover.png',
);
});
test('buildCreationWorkShelfItems ignores match3d theme reference cover and uses container image', () => {
const items = buildCreationWorkShelfItems({
rpgItems: [],
bigFishItems: [],
puzzleItems: [],
match3dItems: [
{
workId: 'match3d:theme-reference-cover',
profileId: 'match3d-profile-theme-reference-cover',
ownerUserId: 'user-1',
gameName: '主题兜底抓鹅',
themeText: '糖果厨房',
summary: '摘要里的封面是玩法参考图时用UI背景图兜底。',
tags: [],
coverImageSrc: '/creation-type-references/match3d.webp',
clearCount: 18,
difficulty: 1,
publicationStatus: 'draft',
playCount: 0,
updatedAt: '2026-05-07T00:00:00.000Z',
publishReady: false,
generatedBackgroundAsset: {
prompt: '糖果厨房竖屏UI背景',
imageSrc: '/match3d-ui-background.png',
containerImageSrc: '/match3d-container.png',
status: 'image_ready',
},
generatedItemAssets: [
{
itemId: 'item-1',
itemName: '糖果',
imageSrc: '/match3d-item.png',
status: 'image_ready',
},
],
},
],
});
expect(items.find((item) => item.kind === 'match3d')?.coverImageSrc).toBe(
'/match3d-container.png',
);
});
test('buildCreationWorkShelfItems uses match3d container asset before background and item image', () => {
const items = buildCreationWorkShelfItems({
rpgItems: [],
bigFishItems: [],
puzzleItems: [],
match3dItems: [
{
workId: 'match3d:item-background-asset-cover',
profileId: 'match3d-profile-item-background-asset-cover',
ownerUserId: 'user-1',
gameName: '背景资产抓鹅',
themeText: '糖果厨房',
summary: '顶层背景缺失时从素材携带的UI背景兜底。',
tags: [],
coverImageSrc: '/creation-type-references/match3d.webp',
clearCount: 18,
difficulty: 1,
publicationStatus: 'draft',
playCount: 0,
updatedAt: '2026-05-07T00:00:00.000Z',
publishReady: false,
generatedItemAssets: [
{
itemId: 'item-1',
itemName: '糖果',
imageSrc: '/match3d-item.png',
backgroundAsset: {
prompt: '糖果厨房竖屏UI背景',
imageObjectKey:
'generated-match3d-assets/session/profile/background/image.png',
containerImageObjectKey:
'generated-match3d-assets/session/profile/ui-container/container.png',
status: 'image_ready',
},
status: 'image_ready',
},
],
},
],
});
expect(items.find((item) => item.kind === 'match3d')?.coverImageSrc).toBe(
'generated-match3d-assets/session/profile/ui-container/container.png',
);
});
test('buildCreationWorkShelfItems uses match3d transparent container reference as last fallback', () => {
const items = buildCreationWorkShelfItems({
rpgItems: [],
bigFishItems: [],
puzzleItems: [],
match3dItems: [
{
workId: 'match3d:container-reference-fallback',
profileId: 'match3d-profile-container-reference-fallback',
ownerUserId: 'user-1',
sourceSessionId: 'session-1',
gameName: '水果抓大鹅',
themeText: '水果',
summary: '',
tags: [],
coverImageSrc: null,
referenceImageSrc: null,
backgroundPrompt: '',
backgroundImageSrc: null,
backgroundImageObjectKey: null,
generatedBackgroundAsset: null,
generatedItemAssets: [],
clearCount: 3,
difficulty: 2,
publicationStatus: 'draft',
publishReady: false,
playCount: 0,
updatedAt: '2026-05-01T00:00:00.000Z',
publishedAt: null,
},
],
});
expect(items.find((item) => item.kind === 'match3d')?.coverImageSrc).toBe(
'/match3d-background-references/pot-fused-reference.png',
);
});
test('getCreationWorkShelfItemTime parses backend seconds.microsZ values', () => {
expect(getCreationWorkShelfItemTime('1778457601.234567Z')).toBe(
1778457601234.567,