Only show i2v stale warning on clip after anchor actually changes.

Require sourceSnapshotted on render metadata so refresh does not false-positive. Remove duplicate anchor hints from toolbar, player, and inspector; keep a single on-clip notice without a (none) label.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
digital-garbage
2026-06-11 13:37:38 +03:00
co-authored by Cursor
parent 1fa74696a0
commit 379ae77f87
5 changed files with 14 additions and 51 deletions
-8
View File
@@ -171,14 +171,6 @@
warn.append(el("div", "render-prompt-text", promptMismatch.rendered || "(empty)"));
body.append(warn);
}
const anchorMismatch = S.renderAnchorMismatch ? S.renderAnchorMismatch(scene.id) : null;
if (anchorMismatch) {
const warn = el("div", "render-prompt-warn render-anchor-warn");
warn.append(el("div", "render-prompt-warn-title", "i2v image changed · showing previous generation"));
warn.append(el("div", "render-prompt-text", anchorMismatch.renderedLabel || "(none)"));
body.append(warn);
}
const src = el("select");
SRC.forEach(([v, label]) => { const o = el("option", null, label); o.value = v; if ((root.source?.type) === v) o.selected = true; src.append(o); });
src.onchange = () => {
+4 -18
View File
@@ -119,29 +119,15 @@
}
function _showRenderPrompt(sceneId) {
if (!_promptEl) return;
const promptMismatch = sceneId && S.renderPromptMismatch ? S.renderPromptMismatch(sceneId) : null;
const anchorMismatch = sceneId && S.renderAnchorMismatch ? S.renderAnchorMismatch(sceneId) : null;
if (!promptMismatch && !anchorMismatch) {
const mismatch = sceneId && S.renderPromptMismatch ? S.renderPromptMismatch(sceneId) : null;
if (!mismatch) {
_promptEl.style.display = "none";
_promptEl.textContent = "";
_promptEl.classList.remove("anchor-stale");
return;
}
_promptEl.style.display = "";
if (anchorMismatch && !promptMismatch) {
_promptEl.classList.add("anchor-stale");
_promptEl.title = `Generated with i2v image: ${anchorMismatch.renderedLabel}`;
_promptEl.textContent = "i2v image changed · showing previous generation";
} else {
_promptEl.classList.remove("anchor-stale");
if (anchorMismatch && promptMismatch) {
_promptEl.title = `i2v: ${anchorMismatch.renderedLabel} · prompt: ${promptMismatch.rendered}`;
_promptEl.textContent = `i2v image changed · generated with: ${promptMismatch.rendered}`;
} else {
_promptEl.title = "Timeline prompt was edited after generation - rate against this text";
_promptEl.textContent = `Generated with: ${promptMismatch.rendered}`;
}
}
_promptEl.title = "Timeline prompt was edited after generation - rate against this text";
_promptEl.textContent = `Generated with: ${mismatch.rendered}`;
}
// ── video pool management ─────────────────────────────────────────────────────
+5 -3
View File
@@ -355,6 +355,7 @@
anchor: rp.anchor ?? anchor,
sourceType: rp.sourceType ?? sourceType,
mediaRef: rp.mediaRef !== undefined ? rp.mediaRef : mediaRef,
sourceSnapshotted: true,
};
});
}
@@ -1089,6 +1090,7 @@
anchor: (state.project?.anchor || "").trim(),
sourceType: src.type || "carry",
mediaRef: src.media_ref || null,
sourceSnapshotted: true,
};
}
@@ -1121,7 +1123,7 @@
function renderAnchorMismatch(sceneId) {
const snap = renderPromptForScene(sceneId);
if (!snap) return null;
if (!snap?.sourceSnapshotted) return null;
const current = _snapshotRenderSource(sceneId);
if (!current) return null;
const renderedType = snap.sourceType || "carry";
@@ -1130,10 +1132,10 @@
return {
renderedType,
renderedRef,
renderedLabel: renderMediaLabel(renderedRef),
renderedLabel: renderedRef ? renderMediaLabel(renderedRef) : null,
currentType: current.sourceType,
currentRef: current.mediaRef,
currentLabel: renderMediaLabel(current.mediaRef),
currentLabel: current.mediaRef ? renderMediaLabel(current.mediaRef) : null,
};
}
-4
View File
@@ -674,11 +674,7 @@ body.tl-reordering { cursor: grabbing; user-select: none; }
.clip.prompt-mismatch { border-color: color-mix(in srgb, var(--amber) 45%, var(--line)); }
.clip.anchor-mismatch { border-color: color-mix(in srgb, var(--teal-soft) 42%, var(--line)); }
.clip.stale-render.rendered::after { color: var(--amber-2); text-shadow: 0 0 5px rgba(224, 162, 58, .7); }
.clip-gen-anchor .clip-gen-prompt-label { color: var(--teal-soft); }
.clip-gen-anchor .clip-gen-prompt-text { color: #c8fff4; }
.tl-render-anchor { color: #c8fff4; border-color: color-mix(in srgb, var(--teal-soft) 40%, var(--line)); }
.render-anchor-warn { border-color: color-mix(in srgb, var(--teal-soft) 35%, var(--line)); }
.render-anchor-warn .render-prompt-warn-title { color: var(--teal-soft); }
.clip-actions { position: absolute; top: 5px; right: 8px; display: flex; gap: 2px; opacity: 0; transition: opacity .12s; }
.clip:hover .clip-actions { opacity: 1; }
.ic-btn { width: 18px; height: 18px; padding: 0; font-size: 11px; line-height: 1; border: 1px solid var(--line);
+5 -18
View File
@@ -445,9 +445,11 @@
if (anchorMismatch) {
clip.classList.add("anchor-mismatch");
const gen = el("div", "clip-gen-prompt clip-gen-anchor");
gen.title = "i2v anchor changed after generation - preview shows the previous render";
gen.title = anchorMismatch.renderedLabel
? `Generated with i2v image: ${anchorMismatch.renderedLabel}`
: "i2v anchor changed after generation - preview shows the previous render";
gen.append(el("span", "clip-gen-prompt-label", "i2v image changed"));
gen.append(el("span", "clip-gen-prompt-text", `Showing previous generation (${anchorMismatch.renderedLabel})`));
gen.append(el("span", "clip-gen-prompt-text", "Showing previous generation"));
clip.append(gen);
}
if (S.renderPromptMismatch) {
@@ -836,15 +838,9 @@
const sc = S.scene(st.selectedSceneId);
if (!sc) return wrap;
const sceneNo = p.scenes.indexOf(sc) + 1;
const promptMismatch = S.renderPromptMismatch ? S.renderPromptMismatch(sc.id) : null;
const anchorMismatch = S.renderAnchorMismatch ? S.renderAnchorMismatch(sc.id) : null;
const rlabel = el("span", "tl-keys", `★ Scene ${sceneNo}`);
const rsel = el("select", "tl-rating");
rsel.title = anchorMismatch
? "i2v image changed - rate the previous generation shown in preview"
: promptMismatch
? "Rate against the generated prompt - timeline text was edited after this render"
: "Rate this scene's render - FunPack Studio refines from it on next generation";
rsel.title = "Rate this scene's render - FunPack Studio refines from it on next generation";
rsel.append(new Option("- rate -", ""));
(st.ratingLabels || []).forEach((l) => {
const o = new Option(l, l);
@@ -854,15 +850,6 @@
rsel.onchange = () => S.setSceneRating(sc.id, rsel.value);
wrap.append(rlabel);
wrap.append(rsel);
if (anchorMismatch) {
const hint = el("span", "tl-render-prompt tl-render-anchor", "i2v image changed · showing previous generation");
hint.title = `Generated with ${anchorMismatch.renderedLabel}`;
wrap.append(hint);
} else if (promptMismatch) {
const hint = el("span", "tl-render-prompt", promptMismatch.rendered);
hint.title = "Generated with this prompt - use it when rating (timeline text differs)";
wrap.append(hint);
}
return wrap;
}