Fix timeline scene count: treat segments[0] as anchor, not a scene
Mirrors _v2_transition_scene_texts: the text before the first transition is a character anchor prepended to every scene, not a scene itself. Show it separately above the rail. scenes[] now matches what the Scene Chain sampler actually generates. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
6f540791fe
commit
f797c535d9
+14
-7
@@ -573,20 +573,27 @@ def split_prompt_by_transitions(prompt, placement="start"):
|
||||
|
||||
|
||||
def parse_timeline_segments(prompt):
|
||||
"""Return {"scenes": [...], "transitions": [...]} for timeline preview.
|
||||
"""Return {"anchor": str, "scenes": [...], "transitions": [...]} for timeline preview.
|
||||
|
||||
Uses split_prompt_by_transitions — the same code path as Studio generation.
|
||||
scenes: list of {"index": int, "text": str}
|
||||
transitions: list of {"after_scene": int, "visual_effect": str|None}
|
||||
Mirrors _v2_transition_scene_texts: segments[0] is the character anchor prepended
|
||||
to every scene, segments[1:] are the actual generated scenes.
|
||||
If no transitions found, the single segment is treated as scene 1 with no anchor.
|
||||
"""
|
||||
segments = split_prompt_by_transitions(prompt, placement="silent")
|
||||
scenes = [{"index": i, "text": text} for i, (text, _) in enumerate(segments)]
|
||||
if len(segments) == 1:
|
||||
return {
|
||||
"anchor": "",
|
||||
"scenes": [{"index": 0, "text": segments[0][0]}],
|
||||
"transitions": [],
|
||||
}
|
||||
anchor = segments[0][0].strip()
|
||||
scenes = [{"index": i, "text": text.strip()} for i, (text, _) in enumerate(segments[1:])]
|
||||
transitions = [
|
||||
{"after_scene": i - 1, "visual_effect": effect}
|
||||
for i, (_, effect) in enumerate(segments)
|
||||
for i, (_, effect) in enumerate(segments[1:])
|
||||
if i > 0
|
||||
]
|
||||
return {"scenes": scenes, "transitions": transitions}
|
||||
return {"anchor": anchor, "scenes": scenes, "transitions": transitions}
|
||||
|
||||
|
||||
class FunPackVideoRefiner:
|
||||
|
||||
+12
-1
@@ -1283,13 +1283,20 @@ function openPanel(node) {
|
||||
refreshBtn.addEventListener("click", () => { body.replaceChildren(); renderTimeline(); });
|
||||
body.append(refreshBtn);
|
||||
|
||||
const { scenes, transitions } = data;
|
||||
const { anchor, scenes, transitions } = data;
|
||||
const trByScene = {};
|
||||
for (const t of transitions) trByScene[t.after_scene] = t;
|
||||
|
||||
body.append(el("div", "funpack-studio-hint",
|
||||
scenes.length === 1 ? "1 scene — no transitions found." : `${scenes.length} scenes detected.`));
|
||||
|
||||
if (anchor) {
|
||||
const anchorBox = el("div", "funpack-timeline-anchor");
|
||||
anchorBox.append(el("div", "funpack-timeline-badge", "Anchor (all scenes)"));
|
||||
anchorBox.append(el("div", "funpack-timeline-text", anchor));
|
||||
body.append(anchorBox);
|
||||
}
|
||||
|
||||
const rail = el("div", "funpack-timeline-rail");
|
||||
for (const scene of scenes) {
|
||||
const box = el("div", "funpack-timeline-box");
|
||||
@@ -1553,6 +1560,10 @@ function injectStyles() {
|
||||
}
|
||||
.funpack-studio-tab-link { color: #58a6d6; text-decoration: underline; cursor: pointer; }
|
||||
.funpack-studio-tab-link:hover { color: #8dcff5; }
|
||||
.funpack-timeline-anchor {
|
||||
border: 1px solid rgba(88,166,214,0.35); border-radius: 6px;
|
||||
background: rgba(22,45,62,0.5); padding: 8px; margin-bottom: 6px;
|
||||
}
|
||||
.funpack-timeline-rail {
|
||||
display: flex; flex-direction: row; align-items: flex-start;
|
||||
gap: 0; overflow-x: auto; padding-bottom: 6px;
|
||||
|
||||
Reference in New Issue
Block a user