feat(sampler): second pass gets an Enable switch; shorter hints
The pass was derived from whether the schedule field had content, so turning it off meant deleting a schedule you wanted to keep. It has its own checkbox now and the schedule is just configuration; enabling without one is reported rather than silently ignored. Trims the second-pass and ALG hints from four paragraphs to a sentence each. The long-form detail stays behind the Details link, which is what it is for.
This commit is contained in:
@@ -242,7 +242,7 @@
|
||||
{ name: "v2a_grad_scale", label: "Video→audio coupling", kind: "float", default: 1.0, min: 0.0, max: 4.0, step: 0.25, dependsOn: "joyai_audio_memory",
|
||||
hint: "How much the carried audio follows the new shot's picture. 1.0 is the model's own behaviour and costs nothing; JoyAI uses 2.0; 0 makes audio ignore the video." },
|
||||
{ name: "alg_anchor", label: "Blur the i2v anchor (ALG)", kind: "bool", default: false,
|
||||
hint: "Hides the anchor image's fine detail during the first, noisiest steps so the shot can't shortcut to a near-still that just matches it — the usual fix for an anchored scene that barely moves. Works with whatever sampler you have wired, including a plain KSampler, and does nothing on a scene with no anchor image." },
|
||||
hint: "Blurs the anchor's fine detail during the first, noisiest steps — the usual fix for an anchored scene that barely moves. No effect without an anchor image." },
|
||||
{ name: "alg_anchor_strength", label: "Anchor blur strength", kind: "float", default: 2.0, min: 1.0, max: 4.0, step: 0.1, dependsOn: "alg_anchor",
|
||||
hint: "How blurry the anchor gets while it's blurred. The paper says 2.5; 2.0 held character likeness noticeably better here." },
|
||||
{ name: "alg_anchor_sigma_threshold", label: "Anchor blur sigma threshold", kind: "float", default: 0.975, min: 0.5, max: 0.999, step: 0.005, dependsOn: "alg_anchor",
|
||||
@@ -634,22 +634,6 @@
|
||||
const next = JSON.stringify({ ...cur, samplers: updatedSamplers });
|
||||
if (quiet) S.setStudioInput("studio_settings", next);
|
||||
else S.setStudioInputNow("studio_settings", next);
|
||||
syncSecondPassFromSchedule(updatedSamplers, quiet);
|
||||
}
|
||||
// The second pass is driven by ONE thing: the schedule. Giving it one turns it on;
|
||||
// taking it away turns it off. There is no cut and no re-entry point to configure —
|
||||
// pass 1 always runs the main schedule in full and pass 2 always runs this one in full.
|
||||
// A schedule is either typed into the low pass's Sigmas field or COMPUTED by picking a
|
||||
// scheduler for it; both must count here, or picking one would be an inert control.
|
||||
function syncSecondPassFromSchedule(samplers, quiet) {
|
||||
const raw = String(samplers?.low?.sigmas || "").replace(/;/g, ",");
|
||||
const vals = raw.split(",").map((v) => parseFloat(v.trim())).filter((v) => !isNaN(v));
|
||||
const sched = String(samplers?.low?.scheduler || "use_user_sigmas");
|
||||
const computed = sched !== "use_user_sigmas" && Number(samplers?.low?.steps || 0) > 0;
|
||||
const set = quiet ? S.setSamplerInput : S.setSamplerInputNow;
|
||||
// one number is not a schedule
|
||||
if (computed || vals.length >= 2) set("second_pass", true);
|
||||
else S.unsetSamplerInput("second_pass");
|
||||
}
|
||||
|
||||
// ALG used to have two switches: the Distilled Flow panel's own alg_enabled, and the
|
||||
@@ -705,15 +689,10 @@
|
||||
moved.style.color = "var(--accent)";
|
||||
algG.append(moved);
|
||||
}
|
||||
algG.append(hintEl("This is the only ALG anchor control — on Distilled Flow it runs inside "
|
||||
+ "the sampler loop, on every other sampler through a denoiser proxy. The same blur for "
|
||||
+ "guide and JoyAI-memory frames is under Experimental (“Blur i2v guides and JoyAI "
|
||||
+ "memory”) — it has its own strength and window."));
|
||||
// Second pass lives here rather than under Experimental: at its defaults the split is
|
||||
// behaviour-neutral (pass 2 resumes from exactly the state pass 1 handed over), so it
|
||||
// is a sampler setting, not a gamble. The only control is the schedule field in the
|
||||
// panel above — enable and cut are derived from it (see syncSecondPassFromSchedule);
|
||||
// all that is left here is the optional between-pass operation.
|
||||
algG.append(hintEl("The same blur for guide and JoyAI-memory frames is under Experimental, "
|
||||
+ "with its own strength and window."));
|
||||
// Enable and schedule are in the panel above, with the sampler they belong to; this is
|
||||
// the optional operation applied to the latent between the two passes.
|
||||
const g = group(pane, "Second pass");
|
||||
renderKnobList(g, st, ["second_pass_op"]);
|
||||
const si = st.project.sampler_inputs || {};
|
||||
|
||||
@@ -406,23 +406,19 @@
|
||||
// reuses the sampler configured above, and rendering its algorithm settings here would
|
||||
// offer knobs that quietly do nothing.
|
||||
sectionTag(container, "Second pass");
|
||||
const spOn = !!(window.Store?.get()?.project?.sampler_inputs || {}).second_pass;
|
||||
row(container, "Enable", checkCtrl(spOn, "sp-second-on", (v) => {
|
||||
window.Store?.setSamplerInputNow?.("second_pass", v);
|
||||
}));
|
||||
hint(container, "Samples each scene twice. Pass 1 runs the main schedule in full, then "
|
||||
+ "pass 2 runs the one below in full — total steps are the two added up.");
|
||||
|
||||
const spSig = textCtrl(s.low.sigmas, "e.g. 0.812, 0.6, 0.35, 0.15, 0.0", "sp-second-sig",
|
||||
(v) => { s.low.sigmas = v; mkSave(true)(); });
|
||||
row(container, "Second pass schedule", spSig);
|
||||
hint(container, "Fill this in and each scene is sampled in two passes; leave it empty and "
|
||||
+ "it isn't. Comma-separated floats, high to low, ending at 0. Pass 1 "
|
||||
+ "runs the main Sigmas schedule above in full, then pass 2 runs THIS "
|
||||
+ "one in full, so the total is simply the two added up (a 9-step main "
|
||||
+ "plus a 4-step second pass is 13). Pass 2 starts from the finished "
|
||||
+ "clip: it is handed in as the latent and the sampler noises it to your "
|
||||
+ "first sigma itself, exactly as any img2img does — no extra step in "
|
||||
+ "between. That first sigma is therefore the strength dial, and it is "
|
||||
+ "literal: at 0.8 pass 2 starts from 80% fresh noise over 20% of the "
|
||||
+ "pass-1 picture and will rework the shot (and look soft if it has few "
|
||||
+ "steps to resolve it); at 0.4 it is 40/60 and polishes; at 0.2 it is "
|
||||
+ "nearly pure detail work. The rest of the list sets how many steps it "
|
||||
+ "gets. To make pass 1 "
|
||||
+ "shorter, shorten the schedule above; nothing here cuts it short.");
|
||||
row(container, "Schedule", spSig);
|
||||
hint(container, "Comma-separated, high to low, ending at 0. The FIRST sigma is the strength "
|
||||
+ "dial: 0.8 reworks the shot, 0.4 polishes, 0.2 is detail work. The rest sets "
|
||||
+ "how many steps pass 2 gets.");
|
||||
|
||||
// Pass 2 can be computed instead of typed, same switch as pass 1 — its SIGMAS is the
|
||||
// only thing of the low pass that is wired, so a schedule chosen here IS pass 2.
|
||||
@@ -430,19 +426,18 @@ hint(container, "Fill this in and each scene is sampled in two passes; leave it
|
||||
if (s.low.steps === undefined) s.low.steps = s.low.ksampler_steps === undefined ? 4 : s.low.ksampler_steps;
|
||||
const spScheds = ksamplerSchedulers(mkSave(false));
|
||||
const spSchedCur = s.low.scheduler || KSAMPLER_USER_SIGMAS;
|
||||
row(container, "Second pass schedule (computed)",
|
||||
row(container, "Schedule (computed)",
|
||||
selCtrl(spScheds.includes(spSchedCur) ? spScheds : spScheds.concat([spSchedCur]), spSchedCur,
|
||||
"sp-second-sch", (v) => { s.low.scheduler = v; mkSave(false)(); }));
|
||||
hint(container, "Leave on '" + KSAMPLER_USER_SIGMAS + "' to use the typed field above. Pick a "
|
||||
+ "scheduler and pass 2 runs a computed schedule of the step count below instead "
|
||||
+ "— which also TURNS THE SECOND PASS ON, whatever the field above says. A full "
|
||||
+ "computed schedule starts at the model's top sigma, so pass 2 reworks the shot "
|
||||
+ "rather than polishing it; for a polish, type the short low-sigma list above "
|
||||
+ "and leave this alone.");
|
||||
hint(container, "Leave on '" + KSAMPLER_USER_SIGMAS + "' to use the field above. A computed "
|
||||
+ "schedule starts at the model's top sigma, so pass 2 reworks rather than polishes.");
|
||||
if (spSchedCur !== KSAMPLER_USER_SIGMAS) {
|
||||
row(container, "Second pass steps",
|
||||
row(container, "Steps",
|
||||
intCtrl(s.low.steps, 1, 200, "sp-second-steps", (v) => { s.low.steps = v; mkSave(true)(); }));
|
||||
}
|
||||
if (spOn && spSchedCur === KSAMPLER_USER_SIGMAS && !String(s.low.sigmas || "").trim()) {
|
||||
hint(container, "Pass 2 is on but has no schedule — give it one above, or pick a computed one.");
|
||||
}
|
||||
}
|
||||
|
||||
window.SamplerPanel = { render, defaultSamplers, defaultPass };
|
||||
|
||||
Reference in New Issue
Block a user