feat: enhance generate settings to support multiple architectures and their defaults
This commit is contained in:
@@ -5,7 +5,7 @@ import { toolEnterMaskEditCommand, toolEnterTemporaryPanCommand, toolExitMaskEdi
|
||||
const defaultBrush = { color: "#111827", size: 8, hardness: 100 };
|
||||
const defaultChromaKey = { color: "#00ff00", tolerance: 32, softness: 24, feather: 0, choke: 0, despeckle: 0, spill: 50 };
|
||||
const defaultMagicWand = { tolerance: 32, feather: 0, choke: 0, despeckle: 0, contiguous: true, mode: "replace" as const };
|
||||
const defaultGenerate = { mode: "text-to-image" as const, model: "auto" as const, prompt: "", negativePrompt: "", strength: 75, steps: 30, cfg: 7, seed: -1, sampler: "euler", scheduler: "normal", width: 1024, height: 1024, outpaint: { left: 128, top: 128, right: 128, bottom: 128, feathering: 32 }, inpaint: { maskedAreaOnly: true, cropPadding: 96, maskPolarity: "hidden" as const, maskedContent: "neutral" as const, growMaskBy: 6, maskExpand: 0, maskFeather: 0, maskBlur: 0, maskDespeckle: 0 } };
|
||||
const defaultGenerate = { architecture: "sdxl" as const, mode: "text-to-image" as const, model: "auto" as const, textEncoder: "auto", vae: "auto", prompt: "", negativePrompt: "", strength: 75, steps: 30, cfg: 7, seed: -1, sampler: "euler", scheduler: "normal", width: 1024, height: 1024, outpaint: { left: 128, top: 128, right: 128, bottom: 128, feathering: 32 }, inpaint: { maskedAreaOnly: true, cropPadding: 96, maskPolarity: "hidden" as const, maskedContent: "neutral" as const, growMaskBy: 6, maskExpand: 0, maskFeather: 0, maskBlur: 0, maskDespeckle: 0 } };
|
||||
|
||||
describe("tool commands", () => {
|
||||
test("sets active tool", () => {
|
||||
@@ -35,6 +35,23 @@ describe("tool commands", () => {
|
||||
expect(next.editor.tools.generate.inpaint).toEqual({ ...defaultGenerate.inpaint, cropPadding: 2048, growMaskBy: 0, maskExpand: -256, maskBlur: 256, maskPolarity: "revealed", maskedContent: "original" });
|
||||
});
|
||||
|
||||
test("applies architecture defaults and filters unsupported modes", () => {
|
||||
const initial = toolSetGenerateSettingsCommand.execute({ state: createInitialAppState("Test") }, { mode: "inpaint" });
|
||||
const next = toolSetGenerateSettingsCommand.execute({ state: initial }, { architecture: "z-image-turbo" });
|
||||
|
||||
expect(next.editor.tools.generate).toMatchObject({
|
||||
architecture: "z-image-turbo",
|
||||
mode: "text-to-image",
|
||||
model: "auto",
|
||||
textEncoder: "qwen_3_4b.safetensors",
|
||||
vae: "ae.safetensors",
|
||||
steps: 8,
|
||||
cfg: 1,
|
||||
sampler: "res_multistep",
|
||||
scheduler: "simple",
|
||||
});
|
||||
});
|
||||
|
||||
test("sets and clears brush preview", () => {
|
||||
const showing = toolSetBrushPreviewCommand.execute({ state: createInitialAppState("Test") }, { position: { x: 10, y: 20 } });
|
||||
const cleared = toolSetBrushPreviewCommand.execute({ state: showing }, undefined);
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { Vec2D } from "@core/geometry";
|
||||
import type { LayerId, ArtboardId, AssetId } from "@core/id";
|
||||
import type { Layer } from "@core/layer";
|
||||
import type { MaskViewMode } from "@editor/state";
|
||||
import { generateArchitectureDefaults } from "@editor/tools";
|
||||
import type { BrushSettings, ChromaKeySettings, GenerateSettings, MagicWandSettings, ToolId } from "@editor/tools";
|
||||
import type { Command } from "./command";
|
||||
import { commandIds } from "./ids";
|
||||
@@ -62,7 +63,12 @@ export const toolSetGenerateSettingsCommand: Command<ToolSetGenerateSettingsPayl
|
||||
id: commandIds.toolSetGenerateSettings,
|
||||
name: "Set generate settings",
|
||||
execute({ state }, payload) {
|
||||
const mode = payload.mode ?? state.editor.tools.generate.mode;
|
||||
const current = state.editor.tools.generate;
|
||||
const architecture = payload.architecture ?? current.architecture;
|
||||
const architectureChanged = architecture !== current.architecture;
|
||||
const defaults = generateArchitectureDefaults[architecture];
|
||||
const requestedMode = payload.mode ?? current.mode;
|
||||
const mode = defaults.supportedModes.includes(requestedMode) ? requestedMode : defaults.supportedModes[0] ?? "text-to-image";
|
||||
return {
|
||||
...state,
|
||||
editor: {
|
||||
@@ -70,35 +76,38 @@ export const toolSetGenerateSettingsCommand: Command<ToolSetGenerateSettingsPayl
|
||||
tools: {
|
||||
...state.editor.tools,
|
||||
generate: {
|
||||
architecture,
|
||||
mode,
|
||||
model: payload.model ?? state.editor.tools.generate.model,
|
||||
prompt: payload.prompt ?? state.editor.tools.generate.prompt,
|
||||
negativePrompt: payload.negativePrompt ?? state.editor.tools.generate.negativePrompt,
|
||||
strength: clampNumber(payload.strength ?? state.editor.tools.generate.strength, 0, 100),
|
||||
steps: Math.round(clampNumber(payload.steps ?? state.editor.tools.generate.steps, 1, 150)),
|
||||
cfg: clampNumber(payload.cfg ?? state.editor.tools.generate.cfg, 0, 30),
|
||||
seed: Math.round(clampNumber(payload.seed ?? state.editor.tools.generate.seed, -1, Number.MAX_SAFE_INTEGER)),
|
||||
sampler: payload.sampler ?? state.editor.tools.generate.sampler,
|
||||
scheduler: payload.scheduler ?? state.editor.tools.generate.scheduler,
|
||||
width: Math.round(clampNumber(payload.width ?? state.editor.tools.generate.width, 64, 4096)),
|
||||
height: Math.round(clampNumber(payload.height ?? state.editor.tools.generate.height, 64, 4096)),
|
||||
model: payload.model ?? (architectureChanged ? defaults.model : current.model),
|
||||
textEncoder: payload.textEncoder ?? (architectureChanged ? defaults.textEncoder : current.textEncoder),
|
||||
vae: payload.vae ?? (architectureChanged ? defaults.vae : current.vae),
|
||||
prompt: payload.prompt ?? current.prompt,
|
||||
negativePrompt: payload.negativePrompt ?? current.negativePrompt,
|
||||
strength: clampNumber(payload.strength ?? current.strength, 0, 100),
|
||||
steps: Math.round(clampNumber(payload.steps ?? (architectureChanged ? defaults.steps : current.steps), 1, 150)),
|
||||
cfg: clampNumber(payload.cfg ?? (architectureChanged ? defaults.cfg : current.cfg), 0, 30),
|
||||
seed: Math.round(clampNumber(payload.seed ?? current.seed, -1, Number.MAX_SAFE_INTEGER)),
|
||||
sampler: payload.sampler ?? (architectureChanged ? defaults.sampler : current.sampler),
|
||||
scheduler: payload.scheduler ?? (architectureChanged ? defaults.scheduler : current.scheduler),
|
||||
width: Math.round(clampNumber(payload.width ?? current.width, 64, 4096)),
|
||||
height: Math.round(clampNumber(payload.height ?? current.height, 64, 4096)),
|
||||
outpaint: {
|
||||
left: Math.round(clampNumber(payload.outpaint?.left ?? state.editor.tools.generate.outpaint.left, 0, 2048)),
|
||||
top: Math.round(clampNumber(payload.outpaint?.top ?? state.editor.tools.generate.outpaint.top, 0, 2048)),
|
||||
right: Math.round(clampNumber(payload.outpaint?.right ?? state.editor.tools.generate.outpaint.right, 0, 2048)),
|
||||
bottom: Math.round(clampNumber(payload.outpaint?.bottom ?? state.editor.tools.generate.outpaint.bottom, 0, 2048)),
|
||||
feathering: Math.round(clampNumber(payload.outpaint?.feathering ?? state.editor.tools.generate.outpaint.feathering, 0, 512)),
|
||||
left: Math.round(clampNumber(payload.outpaint?.left ?? current.outpaint.left, 0, 2048)),
|
||||
top: Math.round(clampNumber(payload.outpaint?.top ?? current.outpaint.top, 0, 2048)),
|
||||
right: Math.round(clampNumber(payload.outpaint?.right ?? current.outpaint.right, 0, 2048)),
|
||||
bottom: Math.round(clampNumber(payload.outpaint?.bottom ?? current.outpaint.bottom, 0, 2048)),
|
||||
feathering: Math.round(clampNumber(payload.outpaint?.feathering ?? current.outpaint.feathering, 0, 512)),
|
||||
},
|
||||
inpaint: {
|
||||
maskedAreaOnly: payload.inpaint?.maskedAreaOnly ?? state.editor.tools.generate.inpaint.maskedAreaOnly,
|
||||
cropPadding: Math.round(clampNumber(payload.inpaint?.cropPadding ?? state.editor.tools.generate.inpaint.cropPadding, 0, 2048)),
|
||||
maskPolarity: payload.inpaint?.maskPolarity ?? state.editor.tools.generate.inpaint.maskPolarity,
|
||||
maskedContent: payload.inpaint?.maskedContent ?? state.editor.tools.generate.inpaint.maskedContent,
|
||||
growMaskBy: Math.round(clampNumber(payload.inpaint?.growMaskBy ?? state.editor.tools.generate.inpaint.growMaskBy, 0, 256)),
|
||||
maskExpand: Math.round(clampNumber(payload.inpaint?.maskExpand ?? state.editor.tools.generate.inpaint.maskExpand, -256, 256)),
|
||||
maskFeather: Math.round(clampNumber(payload.inpaint?.maskFeather ?? state.editor.tools.generate.inpaint.maskFeather, 0, 256)),
|
||||
maskBlur: Math.round(clampNumber(payload.inpaint?.maskBlur ?? state.editor.tools.generate.inpaint.maskBlur, 0, 256)),
|
||||
maskDespeckle: Math.round(clampNumber(payload.inpaint?.maskDespeckle ?? state.editor.tools.generate.inpaint.maskDespeckle, 0, 64)),
|
||||
maskedAreaOnly: payload.inpaint?.maskedAreaOnly ?? current.inpaint.maskedAreaOnly,
|
||||
cropPadding: Math.round(clampNumber(payload.inpaint?.cropPadding ?? current.inpaint.cropPadding, 0, 2048)),
|
||||
maskPolarity: payload.inpaint?.maskPolarity ?? current.inpaint.maskPolarity,
|
||||
maskedContent: payload.inpaint?.maskedContent ?? current.inpaint.maskedContent,
|
||||
growMaskBy: Math.round(clampNumber(payload.inpaint?.growMaskBy ?? current.inpaint.growMaskBy, 0, 256)),
|
||||
maskExpand: Math.round(clampNumber(payload.inpaint?.maskExpand ?? current.inpaint.maskExpand, -256, 256)),
|
||||
maskFeather: Math.round(clampNumber(payload.inpaint?.maskFeather ?? current.inpaint.maskFeather, 0, 256)),
|
||||
maskBlur: Math.round(clampNumber(payload.inpaint?.maskBlur ?? current.inpaint.maskBlur, 0, 256)),
|
||||
maskDespeckle: Math.round(clampNumber(payload.inpaint?.maskDespeckle ?? current.inpaint.maskDespeckle, 0, 64)),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user