feat: warn on the main window when Best-FaceID cannot do anything
Best-FaceID reads identity from an identity_pin-tagged guide, and only the AUTO
continuity builder ever applies that tag (timeline._identity_pin_guide). Every
way of losing it is silent: the run succeeds and simply carries no identity.
Three such states, all verified against _run_sampler_inputs (tagged guides in
the emitted funpack_scene_guides payload: 2 when healthy, 0 in each bad case):
- no identity pin set at all
- custom guide stack on -- manual guides REPLACE auto guides (`manual or auto`),
and manual GuideEntry has no identity_pin field, so the pin is dropped
- auto continuity off -- same outcome by the other route
Shown on the main window of both frontends, not inside the settings pane that
turns it on: you would only see it there if you already went looking.
- shared predicate: PipelineCaps.identityTransferIssue -> {short, detail}
- Editor: amber chip beside Generate in the timeline header, click opens
Engine settings; full text in the tooltip
- Easy Gen: full-width amber strip between the preview and the Generate row
fpActionbar had to grow the identity fields -- it hashed only pid/sel/gen, so
setting the pin would have left a stale warning sitting next to Generate.
Verified live in both UIs across all five transitions (no pin -> pin -> stack on
-> stack off -> auto off -> feature off); appears and clears correctly in each.
Silent when the Chain Sampler is not in the pipeline, where the knob is inert.
Tests: 22 failed / 465 passed, unchanged from baseline.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
ffe920474c
commit
858e7d9cb6
@@ -15,6 +15,7 @@
|
||||
const uploadInput = document.getElementById("easy-upload-input");
|
||||
const galleryBtn = document.getElementById("easy-gallery-btn");
|
||||
const generateBtn = document.getElementById("easy-generate-btn");
|
||||
const warnStrip = document.getElementById("easy-warn-strip");
|
||||
const advancedBtn = document.getElementById("easy-advanced-btn");
|
||||
const projectsBtn = document.getElementById("easy-projects-btn");
|
||||
const saveBtn = document.getElementById("easy-save-btn");
|
||||
@@ -72,6 +73,12 @@
|
||||
uploadBtn.textContent = attached ? "⬆ Uploaded ✕" : "⬆ Upload";
|
||||
preview.setUpload(attached ? API.mediaUrl(source.media_ref) : null, source?.type === "v2v" ? "video" : "image");
|
||||
|
||||
// A setting that is switched on but cannot do anything belongs on the main screen,
|
||||
// above Generate — not only inside the pane that switched it on.
|
||||
const issue = window.PipelineCaps?.identityTransferIssue(st);
|
||||
warnStrip.textContent = issue ? issue.detail : "";
|
||||
warnStrip.hidden = !issue;
|
||||
|
||||
const pid = p ? p.id : null;
|
||||
if (pid !== lastProjectId) {
|
||||
lastProjectId = pid;
|
||||
|
||||
@@ -63,6 +63,15 @@ a.brand:hover .brand-sub { color: var(--amber-2); }
|
||||
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.easy-progress-stop:disabled { opacity: .6; cursor: default; }
|
||||
|
||||
/* Full-width notice between the preview and the Generate row: a setting that is on
|
||||
but cannot do anything should be readable without opening any panel. */
|
||||
.easy-warn-strip {
|
||||
flex: none; padding: 9px 16px; font-size: 12.5px; line-height: 1.45;
|
||||
color: var(--amber); border-top: 1px solid color-mix(in srgb, var(--amber) 45%, var(--line));
|
||||
background: color-mix(in srgb, var(--amber) 9%, transparent);
|
||||
}
|
||||
.easy-warn-strip[hidden] { display: none; }
|
||||
|
||||
.easy-bar {
|
||||
flex: none; display: flex; align-items: flex-end; gap: 12px;
|
||||
padding: 14px 16px; border-top: 1px solid var(--line); background: var(--ink-1);
|
||||
|
||||
@@ -64,6 +64,8 @@
|
||||
|
||||
<main class="easy-preview" id="easy-preview"></main>
|
||||
|
||||
<div class="easy-warn-strip" id="easy-warn-strip" hidden></div>
|
||||
|
||||
<footer class="easy-bar">
|
||||
<button class="btn ghost easy-upload-btn" id="easy-upload-btn" type="button"
|
||||
title="Upload an image or video to guide generation">⬆ Upload</button>
|
||||
|
||||
@@ -40,6 +40,17 @@
|
||||
montageBtn.disabled = !hasProject() || busy(st);
|
||||
montageBtn.onclick = () => window.MontageDialog?.open();
|
||||
mount.append(montageBtn);
|
||||
|
||||
// Settings that are switched on but cannot do anything belong next to Generate,
|
||||
// not buried in the pane that switched them on — you would only see it there if
|
||||
// you already went looking.
|
||||
const issue = window.PipelineCaps?.identityTransferIssue(st);
|
||||
if (issue) {
|
||||
const chip = el("button", "btn ghost compact action-warn", "⚠ " + issue.short);
|
||||
chip.title = issue.detail + "\n\nClick to open Engine settings.";
|
||||
chip.onclick = () => window.SettingsWindow?.open("engine");
|
||||
mount.append(chip);
|
||||
}
|
||||
}
|
||||
|
||||
if (window.ViewBus) window.ViewBus.subscribeActionbar(render);
|
||||
|
||||
@@ -60,6 +60,43 @@
|
||||
return sourceNeedsAnchorMedia(scene, st);
|
||||
}
|
||||
|
||||
// Best-FaceID reads identity from an identity_pin-tagged guide, and ONLY the auto
|
||||
// continuity builder ever applies that tag (backend timeline._identity_pin_guide).
|
||||
// Every way of losing it is silent — the run succeeds carrying no identity at all —
|
||||
// so the main window says so before you spend a generation finding out.
|
||||
// Returns {short, detail} for a compact chip and a full-width strip respectively,
|
||||
// or null when the setting will actually do something.
|
||||
function identityTransferIssue(st) {
|
||||
const p = st && st.project;
|
||||
if (!p || !(p.sampler_inputs || {}).identity_transfer_enabled) return null;
|
||||
if (!usesChainSampler(st)) return null; // knob is inert without the Chain Sampler
|
||||
const cs = p.continuity_settings || {};
|
||||
const gs = p.guide_settings || {};
|
||||
if (!cs.identity_pin_ref) {
|
||||
return {
|
||||
short: "Best-FaceID: no identity pin",
|
||||
detail: "You have Best-FaceID enabled but no identity pin is set — it has no face to transfer. "
|
||||
+ "Set the identity pin in Settings → Engine → Continuity, or press 📌 on an image in the Media bin.",
|
||||
};
|
||||
}
|
||||
if (gs.stack_enabled) {
|
||||
return {
|
||||
short: "Best-FaceID: pin not reaching sampler",
|
||||
detail: "You have Best-FaceID enabled and an identity pin set, but the custom guide stack replaces "
|
||||
+ "the auto-continuity guides that carry the pin — so the pin never reaches the sampler. "
|
||||
+ "Turn the custom guide stack off in Settings → Engine → Continuity.",
|
||||
};
|
||||
}
|
||||
if (cs.auto_enabled === false) {
|
||||
return {
|
||||
short: "Best-FaceID: pin not reaching sampler",
|
||||
detail: "You have Best-FaceID enabled and an identity pin set, but auto continuity is off — the pin "
|
||||
+ "only travels with auto-continuity guides. Turn auto continuity on in Settings → Engine → Continuity.",
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function sourceLabel(type) {
|
||||
const map = {
|
||||
empty: "Empty · text-to-video",
|
||||
@@ -82,6 +119,7 @@
|
||||
defaultSceneSourceType,
|
||||
sourceNeedsAnchorMedia,
|
||||
isMissingAnchorMedia,
|
||||
identityTransferIssue,
|
||||
sourceLabel,
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -197,6 +197,9 @@ button, input, select, textarea { font-family: inherit; color: var(--text); }
|
||||
.btn.ghost { background: transparent; border-color: transparent; color: var(--muted); padding: 4px 8px; font-size: 12px; }
|
||||
.btn.ghost:hover { color: var(--amber-2); background: var(--ink-3); }
|
||||
.btn.ghost.on { color: var(--amber); border-color: color-mix(in srgb, var(--amber) 55%, var(--line)); }
|
||||
/* "This is switched on but cannot do anything" chip, shown beside Generate. */
|
||||
.btn.action-warn { color: var(--amber); border-color: color-mix(in srgb, var(--amber) 45%, var(--line)); background: color-mix(in srgb, var(--amber) 10%, transparent); }
|
||||
.btn.action-warn:hover { color: var(--amber-2); border-color: var(--amber); }
|
||||
.btn.danger:hover { border-color: var(--danger); color: var(--danger); }
|
||||
.btn.tiny { padding: 2px 7px; font-size: 12px; }
|
||||
|
||||
|
||||
@@ -120,6 +120,14 @@
|
||||
pid: st.project?.id,
|
||||
sel: st.selectedSceneIds?.length,
|
||||
gen: st.gen?.state,
|
||||
// The Best-FaceID warning chip lives in this zone, so everything its message
|
||||
// depends on has to be part of the fingerprint — otherwise setting the pin
|
||||
// leaves a stale warning sitting next to Generate.
|
||||
idOn: st.project?.sampler_inputs?.identity_transfer_enabled,
|
||||
idPin: st.project?.continuity_settings?.identity_pin_ref,
|
||||
idAuto: st.project?.continuity_settings?.auto_enabled,
|
||||
idStack: st.project?.guide_settings?.stack_enabled,
|
||||
sampler: st.project?.sampler_slot,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user