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

@@ -642,6 +642,7 @@ function mapPublicWorkDetailToMatch3DWork(
backgroundImageSrc: entry.backgroundImageSrc ?? null,
backgroundImageObjectKey: entry.backgroundImageObjectKey ?? null,
generatedBackgroundAsset:
entry.generatedBackgroundAsset ??
entry.generatedItemAssets
?.map((asset) => asset.backgroundAsset ?? null)
.find(Boolean) ?? null,
@@ -744,6 +745,32 @@ function resolveMatch3DRuntimeGeneratedItemAssets(
: normalizeMatch3DGeneratedItemAssetsForRuntime(profileAssets);
}
function resolveMatch3DRuntimeGeneratedBackgroundAsset(
run: Match3DRunSnapshot | null,
profile: Match3DWorkProfile | null,
publicWorkDetail: PlatformPublicGalleryCard | null,
) {
const runProfileId = run?.profileId?.trim() ?? '';
const profileBackground = profile?.generatedBackgroundAsset ?? null;
const publicBackground =
publicWorkDetail && isMatch3DGalleryEntry(publicWorkDetail)
? (publicWorkDetail.generatedBackgroundAsset ?? null)
: null;
if (runProfileId && profile?.profileId === runProfileId) {
return profileBackground ?? publicBackground;
}
if (
runProfileId &&
publicWorkDetail &&
isMatch3DGalleryEntry(publicWorkDetail) &&
publicWorkDetail.profileId === runProfileId
) {
return publicBackground ?? profileBackground;
}
return profileBackground ?? publicBackground;
}
function resolveActiveMatch3DRuntimeProfile(
run: Match3DRunSnapshot | null,
runtimeProfile: Match3DWorkProfile | null,
@@ -8911,6 +8938,11 @@ export function PlatformEntryFlowShellImpl({
activeMatch3DRuntimeProfile,
activeEntry,
)}
generatedBackgroundAsset={resolveMatch3DRuntimeGeneratedBackgroundAsset(
match3dRun,
activeMatch3DRuntimeProfile,
activeEntry,
)}
backgroundImageSrc={resolveMatch3DRuntimeBackgroundImageSrc(
match3dRun,
activeMatch3DRuntimeProfile,
@@ -10985,6 +11017,11 @@ export function PlatformEntryFlowShellImpl({
activeMatch3DRuntimeProfile,
selectedPublicWorkDetail,
)}
generatedBackgroundAsset={resolveMatch3DRuntimeGeneratedBackgroundAsset(
match3dRun,
activeMatch3DRuntimeProfile,
selectedPublicWorkDetail,
)}
backgroundImageSrc={resolveMatch3DRuntimeBackgroundImageSrc(
match3dRun,
activeMatch3DRuntimeProfile,