新增图片画布编辑器

新增 /editor 图片画布入口与 Lovart 风格画布交互

新增图片画布工程和资源持久化的 SpacetimeDB 表、绑定与 api-server BFF

接入图片生成和修改的 VectorEngine gpt-image-2 后端通道

完善素材库文件夹、重命名、上传删除、图层和元数据交互

补充图片画布技术方案、领域词、执行跟踪和浏览器 smoke 截图
This commit is contained in:
2026-06-13 16:22:18 +08:00
parent f8a80cd795
commit 747473024d
53 changed files with 6694 additions and 29 deletions

View File

@@ -1,4 +1,4 @@
import { Loader2 } from 'lucide-react';
import { Image as ImageIcon, Loader2 } from 'lucide-react';
import { AnimatePresence, motion } from 'motion/react';
import {
type Dispatch,
@@ -1077,6 +1077,13 @@ const CustomWorldGenerationView = lazy(async () => {
};
});
const ImageCanvasEditorView = lazy(async () => {
const module = await import('../image-editor/ImageCanvasEditorView');
return {
default: module.ImageCanvasEditorView,
};
});
const UnifiedCreationWorkspace = lazy(async () => {
const module = await import('../unified-creation/UnifiedCreationWorkspace');
return {
@@ -4791,16 +4798,22 @@ export function PlatformEntryFlowShellImpl({
() => pendingPlatformTaskCompletionDialog,
[pendingPlatformTaskCompletionDialog],
);
const activePlatformTaskCompletionDialog = resolveActivePlatformDialog(
currentPlatformTaskCompletionDialog,
dismissedPlatformTaskCompletionDialogKey,
buildPlatformTaskCompletionDialogDismissKey,
);
const activePlatformErrorDialog = resolveActivePlatformDialog(
currentPlatformErrorDialog,
dismissedPlatformErrorDialogKey,
buildPlatformErrorDialogDismissKey,
);
const activePlatformTaskCompletionDialog =
selectionStage === 'image-editor'
? null
: resolveActivePlatformDialog(
currentPlatformTaskCompletionDialog,
dismissedPlatformTaskCompletionDialogKey,
buildPlatformTaskCompletionDialogDismissKey,
);
const activePlatformErrorDialog =
selectionStage === 'image-editor'
? null
: resolveActivePlatformDialog(
currentPlatformErrorDialog,
dismissedPlatformErrorDialogKey,
buildPlatformErrorDialogDismissKey,
);
const closePlatformErrorDialog = useCallback(() => {
if (!currentPlatformErrorDialog) {
return;
@@ -14558,9 +14571,24 @@ export function PlatformEntryFlowShellImpl({
) : null}
</Suspense>
);
const creationStartContent = renderCreationHubContent(
'start-only',
'正在加载创作大厅...',
const creationStartContent = (
<div className="image-editor-creation-entry-stack">
<button
type="button"
className="image-editor-creation-entry"
onClick={() => setSelectionStage('image-editor')}
aria-label="打开图片编辑器"
>
<span className="image-editor-creation-entry__icon">
<ImageIcon className="h-5 w-5" />
</span>
<span className="image-editor-creation-entry__body">
<span></span>
<span></span>
</span>
</button>
{renderCreationHubContent('start-only', '正在加载创作大厅...')}
</div>
);
const draftHubContent = renderCreationHubContent(
'works-only',
@@ -14570,6 +14598,21 @@ export function PlatformEntryFlowShellImpl({
return (
<>
<AnimatePresence mode="wait">
{selectionStage === 'image-editor' && (
<motion.div
key="image-editor"
initial={{ opacity: 0, y: 12 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -12 }}
className="image-editor-stage-shell flex h-full min-h-0 min-w-0 flex-col overflow-hidden"
>
<Suspense
fallback={<LazyPanelFallback label="正在加载编辑器..." />}
>
<ImageCanvasEditorView />
</Suspense>
</motion.div>
)}
{selectionStage === 'platform' && (
<motion.div
key="platform-home"

View File

@@ -1,6 +1,4 @@
import type {
CustomWorldAgentSessionSnapshot,
} from '../../../packages/shared/src/contracts/customWorldAgent';
import type { CustomWorldAgentSessionSnapshot } from '../../../packages/shared/src/contracts/customWorldAgent';
import type { RpgCreationResultView } from '../../../packages/shared/src/contracts/rpgCreationResultView';
import type { HydratedSavedGameSnapshot } from '../../persistence/runtimeSnapshotTypes';
import type { CustomWorldProfile } from '../../types';
@@ -15,6 +13,7 @@ export type CustomWorldRuntimeLaunchOptions = {
export type SelectionStage =
| 'platform'
| 'image-editor'
| 'profile-feedback'
| 'work-detail'
| 'detail'
@@ -70,7 +69,10 @@ export type SelectionStage =
export type CustomWorldGenerationViewSource = 'agent-draft-foundation' | null;
export type CustomWorldResultViewSource = 'saved-profile' | 'agent-draft' | null;
export type CustomWorldResultViewSource =
| 'saved-profile'
| 'agent-draft'
| null;
export type CustomWorldAutoSaveState = 'idle' | 'saving' | 'saved' | 'error';

View File

@@ -2,6 +2,7 @@ import type { SelectionStage } from './platformEntryTypes';
const PROTECTED_DATA_LOSS_STABLE_STAGE_BY_STAGE = {
platform: true,
'image-editor': true,
'profile-feedback': false,
'work-detail': true,
detail: true,