export const availableToolIds = ["select", "brush", "eraser", "feather", "magicWand", "semanticSelect", "maskLasso", "maskRectangle", "pan"] as const; export const availableOperationIds = ["generate", "chromaKey"] as const; export type ToolId = (typeof availableToolIds)[number]; export type OperationId = (typeof availableOperationIds)[number]; export type InteractionMode = | { type: "tool"; tool: ToolId } | { type: "temporary-pan"; previousTool: ToolId }; export type BrushSettings = { color: string; size: number; hardness: number; opacity: number; flow: number; smoothing: number; pressureSize: boolean; }; export type FeatherSettings = { size: number; radius: number; strength: number; smoothing: number; pressureSize: boolean; }; export type ChromaKeySettings = { color: string; tolerance: number; softness: number; feather: number; choke: number; despeckle: number; spill: number; }; export type MagicWandMode = "replace" | "add" | "subtract"; export type GenerateMode = "text-to-image" | "image-to-image" | "inpaint" | "outpaint"; export type GenerateIntent = "create" | "replace" | "remove" | "extend" | "variations"; export const generateArchitectures = ["sdxl", "z-image", "z-image-turbo", "anima"] as const; export type GenerateArchitecture = (typeof generateArchitectures)[number]; export type GenerateModel = string; export type InpaintMaskedContent = "neutral" | "original" | "originalColor" | "edges"; export type InpaintProfile = "remove" | "replace" | "repair" | "material" | "reshape" | "custom"; export type InpaintStructureControl = "none" | "canny" | "depth" | "pose"; export type GenerateSettings = { architecture: GenerateArchitecture; mode: GenerateMode; model: GenerateModel; textEncoder: string; vae: string; prompt: string; negativePrompt: string; strength: number; steps: number; cfg: number; seed: number; sampler: string; scheduler: string; width: number; height: number; batchSize: number; refinePass: boolean; refineStrength: number; outpaint: { left: number; top: number; right: number; bottom: number; feathering: number; }; inpaint: { profile: InpaintProfile; maskedAreaOnly: boolean; cropPadding: number; maskPolarity: "hidden" | "revealed"; maskedContent: InpaintMaskedContent; growMaskBy: number; maskExpand: number; maskFeather: number; maskBlur: number; maskDespeckle: number; structureControl: InpaintStructureControl; controlStrength: number; controlModel: string; colorMatch: boolean; }; }; export const generateArchitectureDefaults: Record = { sdxl: { model: "auto", textEncoder: "auto", vae: "auto", steps: 30, cfg: 7, sampler: "euler", scheduler: "normal", supportedModes: ["text-to-image", "image-to-image", "inpaint", "outpaint"] }, "z-image": { model: "auto", textEncoder: "qwen_3_4b.safetensors", vae: "ae.safetensors", steps: 30, cfg: 4, sampler: "res_multistep", scheduler: "simple", supportedModes: ["text-to-image"] }, "z-image-turbo": { model: "auto", textEncoder: "qwen_3_4b.safetensors", vae: "ae.safetensors", steps: 8, cfg: 1, sampler: "res_multistep", scheduler: "simple", supportedModes: ["text-to-image"] }, anima: { model: "auto", textEncoder: "qwen_3_06b_base.safetensors", vae: "qwen_image_vae.safetensors", steps: 30, cfg: 4, sampler: "er_sde", scheduler: "simple", supportedModes: ["text-to-image"] }, }; export type MagicWandSettings = { tolerance: number; feather: number; choke: number; despeckle: number; contiguous: boolean; mode: MagicWandMode; }; export type ToolState = { activeTool: ToolId; interactionMode: InteractionMode; brush: BrushSettings; feather: FeatherSettings; chromaKey: ChromaKeySettings; magicWand: MagicWandSettings; generate: GenerateSettings; }; export const initialToolState: ToolState = { activeTool: "select", interactionMode: { type: "tool", tool: "select" }, brush: { color: "#111827", size: 8, hardness: 100, opacity: 100, flow: 100, smoothing: 20, pressureSize: true }, feather: { size: 96, radius: 16, strength: 65, smoothing: 25, pressureSize: true }, chromaKey: { color: "#00ff00", tolerance: 32, softness: 24, feather: 0, choke: 0, despeckle: 0, spill: 50 }, magicWand: { tolerance: 32, feather: 0, choke: 0, despeckle: 0, contiguous: true, mode: "replace" }, generate: { architecture: "sdxl", mode: "text-to-image", model: "auto", textEncoder: "auto", vae: "auto", prompt: "", negativePrompt: "", strength: 75, steps: 30, cfg: 7, seed: -1, sampler: "euler", scheduler: "normal", width: 1024, height: 1024, batchSize: 4, refinePass: true, refineStrength: 20, outpaint: { left: 128, top: 128, right: 128, bottom: 128, feathering: 32 }, inpaint: { profile: "replace", maskedAreaOnly: true, cropPadding: 128, maskPolarity: "revealed", maskedContent: "neutral", growMaskBy: 6, maskExpand: 8, maskFeather: 3, maskBlur: 0, maskDespeckle: 0, structureControl: "none", controlStrength: 0.55, controlModel: "auto", colorMatch: true }, }, }; export const inpaintProfileDefaults: Record, Omit, "inpaint"> & { inpaint: Partial }> = { remove: { strength: 100, inpaint: { maskedContent: "neutral", cropPadding: 160, maskExpand: 12, maskFeather: 4, structureControl: "none" } }, replace: { strength: 85, inpaint: { maskedContent: "neutral", cropPadding: 128, maskExpand: 8, maskFeather: 3, structureControl: "none" } }, repair: { strength: 45, refinePass: true, refineStrength: 15, inpaint: { maskedContent: "original", cropPadding: 96, maskExpand: 4, maskFeather: 2, structureControl: "none" } }, material: { strength: 65, refinePass: true, refineStrength: 20, inpaint: { maskedContent: "edges", cropPadding: 128, maskExpand: 6, maskFeather: 3, structureControl: "canny", controlStrength: 0.55, colorMatch: false } }, reshape: { strength: 90, inpaint: { maskedContent: "neutral", cropPadding: 160, maskExpand: 10, maskFeather: 4, structureControl: "depth", controlStrength: 0.4 } }, }; export function isPanInteractionMode(interactionMode: InteractionMode): boolean { return interactionMode.type === "temporary-pan" || (interactionMode.type === "tool" && interactionMode.tool === "pan"); }