fix: the sampler-name list comes from ComfyUI, not a hardcoded eight

Studio's KSampler mode passes the chosen name straight to comfy.samplers.
sampler_object(), so any sampler this ComfyUI has always worked — but both
frontends offered a hardcoded list of eight written before the rest existed.
That silently hid 36 of them, including res_multistep, which is what ComfyUI's
own MiniMax H3 templates use.

Both now read sampler_name from the live KSampler node spec and fall back to the
old list if that fetch fails. A saved name missing from the live list stays
selectable instead of being swapped for the first option.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
digital-garbage
2026-08-03 21:52:14 +03:00
co-authored by Claude Opus 5
parent 3506471906
commit 981798d6d9
2 changed files with 44 additions and 4 deletions
+27 -2
View File
@@ -13,7 +13,29 @@
const SAMPLER_TYPES = ["Hybrid Euler 2S", "Distilled Flow", "KSampler"];
const VELOCITY_BIAS_MODES = ["off", "capture", "apply", "capture_and_apply"];
const MOTION_PULSE_MODES = ["off", "balanced", "aggressive", "custom"];
const KSAMPLER_NAMES = ["euler", "euler_ancestral", "dpm_2", "dpm_2_ancestral", "dpmpp_2m", "dpmpp_sde", "ddim", "uni_pc"];
// Fallback only. The real list is whatever THIS ComfyUI has — read from the live
// KSampler node spec, because a hardcoded set silently hides samplers the backend can
// already run (it passes the name straight to comfy.samplers.sampler_object). That is
// how res_multistep — the one ComfyUI's own MiniMax H3 templates use — went missing.
const KSAMPLER_NAMES_FALLBACK = ["euler", "euler_ancestral", "dpm_2", "dpm_2_ancestral", "dpmpp_2m", "dpmpp_sde", "ddim", "uni_pc"];
let _ksamplerNames = null;
let _ksamplerPending = null;
function ksamplerNames(onLoaded) {
if (_ksamplerNames) return _ksamplerNames;
if (!_ksamplerPending && window.MovieEditorAPI?.nodeSpec) {
_ksamplerPending = window.MovieEditorAPI.nodeSpec("KSampler")
.then((spec) => {
const w = (spec?.inputs || []).find((i) => i.name === "sampler_name");
if (w && (w.choices || []).length) {
_ksamplerNames = w.choices;
if (onLoaded) onLoaded();
}
})
.catch(() => {});
}
return KSAMPLER_NAMES_FALLBACK;
}
function defaultHybrid() {
return {
@@ -300,8 +322,11 @@
} else if (cfg.type === "KSampler") {
sectionTag(container, "KSampler");
// saveNow re-renders, which is how the list refreshes once the live names land.
const names = ksamplerNames(saveNow);
const cur = cfg.ksampler_name || "euler";
row(container, "sampler name",
selCtrl(KSAMPLER_NAMES, cfg.ksampler_name || "euler", dk + "-ks",
selCtrl(names.includes(cur) ? names : names.concat([cur]), cur, dk + "-ks",
(v) => { cfg.ksampler_name = v; save(); }));
}
}
+17 -2
View File
@@ -14,7 +14,18 @@ const TABS = ["Session", "Shortcuts", "Split markers", "Refiner", "Advisor", "Lo
const SAMPLER_TYPES = ["Hybrid Euler 2S", "Distilled Flow", "KSampler"];
const MOTION_PULSE_MODES = ["off", "balanced", "aggressive", "custom"];
const VELOCITY_BIAS_MODES = ["off", "capture", "apply", "capture_and_apply"];
const KSAMPLER_NAMES = ["euler", "euler_ancestral", "dpm_2", "dpm_2_ancestral", "dpmpp_2m", "dpmpp_sde", "ddim", "uni_pc"];
// Fallback only — the real list is whatever THIS ComfyUI has. The backend passes the name
// straight to comfy.samplers.sampler_object(), so a hardcoded set hides samplers it can
// already run (res_multistep, which ComfyUI's own MiniMax H3 templates use, was missing).
const KSAMPLER_NAMES_FALLBACK = ["euler", "euler_ancestral", "dpm_2", "dpm_2_ancestral", "dpmpp_2m", "dpmpp_sde", "ddim", "uni_pc"];
let KSAMPLER_NAMES = KSAMPLER_NAMES_FALLBACK;
api.fetchApi("/object_info/KSampler")
.then((r) => r.json())
.then((defs) => {
const names = defs?.KSampler?.input?.required?.sampler_name?.[0];
if (Array.isArray(names) && names.length) KSAMPLER_NAMES = names;
})
.catch(() => {});
let activePanel = null;
let studioShortcutData = null;
@@ -1435,7 +1446,11 @@ function openPanel(node) {
}
} else if (cfg.type === "KSampler") {
body.append(sectionTitle("KSampler settings"));
const ksSelect = selectEl(KSAMPLER_NAMES, cfg.ksampler_name || "euler");
// Keep a saved name that isn't in the live list (older/newer ComfyUI) selectable
// rather than silently swapping it for the first option.
const _ksCur = cfg.ksampler_name || "euler";
const ksSelect = selectEl(
KSAMPLER_NAMES.includes(_ksCur) ? KSAMPLER_NAMES : KSAMPLER_NAMES.concat([_ksCur]), _ksCur);
ksSelect.addEventListener("change", () => { cfg.ksampler_name = ksSelect.value; });
body.append(row("sampler name", ksSelect));
}