import type { ImageDocument } from "@core/document"; import type { Angle, Rect, Size, Transform, Vec2D } from "@core/geometry"; import type { ArtboardId, AssetId, GenerationCandidateId, GenerationJobId, LayerId } from "@core/id"; import type { GenerateArchitecture, GenerateMode, GenerateSettings, ToolState } from "./tools"; import type { TransformSession } from "./transform"; export type ViewportState = { center: Vec2D; zoom: number; rotation: Angle; size: Size; }; export type SelectionState = { artboardId?: ArtboardId; layerIds: LayerId[]; }; export type MaskViewMode = "composite" | "blackWhite" | "alpha" | "overlay"; export type MaskEditState = { targetLayerId: LayerId; maskLayerId: LayerId; viewMode?: MaskViewMode; }; export type BrushPreviewState = { position: Vec2D; }; export type BrushStrokePreviewState = { layerId: LayerId; assetId: AssetId; source: string; }; export type GenerationCandidate = { id: GenerationCandidateId; source: string; mimeType: string; intrinsicSize: Size; mode: GenerateSettings["mode"]; settings: GenerateSettings; seed: number; width: number; height: number; inputImage?: string; maskImage?: string; placement: { artboardId: ArtboardId; layerName: string; transform: Transform; }; inpaint?: { targetLayerId: LayerId; maskLayerId: LayerId; sourceAssetId: AssetId; maskAssetId: AssetId; inputImage: string; maskImage: string; crop: { assetBounds: Rect; documentBounds: Rect; padding: number; maskedAreaOnly: boolean; }; mask: { polarity: GenerateSettings["inpaint"]["maskPolarity"]; activeBounds: Rect; }; backend: { growMaskBy: number; maskedContent: GenerateSettings["inpaint"]["maskedContent"]; maskBlur: number; maskFeather: number; maskExpand: number; cropPadding: number; }; }; }; export type GenerationCompareMode = "result" | "before" | "split"; export type GenerationJobKind = "generate" | "regenerate" | "refine" | "replace"; export type GenerationJobStatus = "running" | "succeeded" | "failed" | "cancelled"; export type GenerationJob = { id: GenerationJobId; kind: GenerationJobKind; label: string; status: GenerationJobStatus; startedAt: number; finishedAt?: number; error?: string; }; export type GenerationState = { candidates: GenerationCandidate[]; selectedCandidateId?: string; compareMode: GenerationCompareMode; jobs: GenerationJob[]; resources: GenerationResourcesState; }; export type GenerationArchitectureOption = { value: GenerateArchitecture; label: string; defaultModel: string; models: string[]; supportedModes: GenerateMode[]; }; export type GenerationOptions = { architectures?: GenerationArchitectureOption[]; models?: string[]; textEncoders?: string[]; vaes?: string[]; samplers?: string[]; schedulers?: string[]; }; export type GenerationResourcesState = { status: "idle" | "loading" | "ready" | "failed"; options?: GenerationOptions; error?: string }; export type CommandPaletteState = { open: boolean; query: string; selectedIndex: number; }; export type WorkspacePanel = "none" | "generate" | "chromaKey" | "layers"; export function isOperationWorkspacePanel(panel: WorkspacePanel): boolean { return panel === "generate" || panel === "chromaKey"; } export type WorkspaceState = { panel: WorkspacePanel; }; export type EditorState = { viewport: ViewportState; selection: SelectionState; tools: ToolState; generation: GenerationState; commandPalette: CommandPaletteState; workspace: WorkspaceState; transformSession?: TransformSession; maskEdit?: MaskEditState; brushPreview?: BrushPreviewState; brushStrokePreview?: BrushStrokePreviewState; pointerSession?: { type: "pan" }; }; export type HistorySnapshot = { document: ImageDocument; editor: EditorState; }; export type HistoryState = { past: HistorySnapshot[]; future: HistorySnapshot[]; }; export type AppState = { document: ImageDocument; editor: EditorState; history: HistoryState; };