Brings the OpenCut Cutting Room rebuild, Anchor-as-guide, Mixed self-image
guide, autocomplete, and the Scene Builder / character / NormalizingSampler
removals onto main. Tree matches dev exactly (discards the obsolete
cutting_edge README doc link).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The cutting_edge branch is gone; generalize the section to cover short-lived
non-main branches without the 'cutting edge' branding, same warning.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Mixed scenes never rendered an inspector image picker — renderSourceField only
called renderImageSource for eff === "image", even though renderImageSource has a
dedicated mixed branch ("Anchor image (mixed i2v)"). So a Mixed anchor could only
be set by dragging onto the timeline clip, unlike image/anchor_guide. Render the
picker for eff === "mixed" too, giving Mixed the same on-timeline + inspector image
visibility as the other anchor modes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two bugs from the Tab update:
1. Tab didn't finish the trigger at end-of-text. The skip-space regex included `$`,
so when the caret was at the end of the field (the common case) NO trailing space
was added — the menu then re-opened on the just-accepted trigger (it matches
itself) and appeared stuck. Drop `$`: always add the space unless a space/delimiter
already follows.
2. Orphaned menu stranded in the top-left with no way to dismiss it. The menu lives in
document.body; when a panel re-render removes its host textarea, removal doesn't fire
blur, so the menu was never cleaned up and a later scroll repositioned it against a
detached element (rect 0,0 → corner). Now: open() sweeps stray .ac-menu (single menu
app-wide) and bails if the textarea is detached; refresh()/position() close on a
detached textarea; and a MutationObserver closes + disconnects when the textarea
leaves the DOM, so it hides on its own.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The first cut withheld the anchor_guide image (set_primary=False) to get an
empty latent "for free". That broke real (custom) pipelines: the image vanished
from the timeline and never reached the graph, so a downstream Image Transform
node — which derives width/height from the input image even when i2v is
bypassed — had no input and generation failed.
Corrected model: the image flows into the pipeline like any anchor (copied as
primary -> source_image / image_processing), shows on the timeline, and is
required. The EMPTY LATENT comes from bypassing the i2v node (the value-only
node_overrides), not from withholding the image. On the built-in pipeline there
is no bypassable i2v node, so it runs as a normal i2v anchor + frame-0 guide;
the inspector warns when no i2v node is declared.
- timeline: anchorMediaRef / SRC_ICON / appendSrcBadge show the anchor_guide
thumbnail + a "guide" badge.
- store: _anchorAvailable / _continuesChainRun treat it as an anchor; drop keeps
guide mode instead of forcing plain image.
- backend: _prepare_media / scene_anchor_media_refs / _anchor_media_ref /
source_needs_anchor_media include anchor_guide; removed the now-dead
anchor_guide_media_refs guide-only copy path (image is a normal anchor now).
- inspector: relabel to "Anchor image (guide mode)", warn when no i2v node set.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The "Filter nodes…" box only showed for "Any node" mode; role-based modes
filled the dropdown directly with no way to search. Now the filter is shown
for any selected model type and applies to role candidates and Any-node alike
(applyFilter drives both paths).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Mixed scenes carried prior-scene guides but the FIRST scene (nothing prior to
carry) got no guide attention at all — only the i2v anchor. Generalize the
anchor_guide self-image guide path to also cover mixed: each mixed scene's own
image is added as a reinforcing frame-0 guide (strength 0.35), merged on top of
the carried prior guides. Renamed build_anchor_guide_guides ->
build_self_image_guides. Mixed images are already copied as anchors, so guide
refs resolve via funpack_scene_media_refs with no extra media prep.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New scene Source mode: the image is applied as a frame-0 guide via the
existing guide-attention path while the latent fed to the sampler stays empty
(text-to-video). The image is never the i2v anchor, so frame 0 is not locked.
Backend (timeline.py / server.py):
- SceneSource.guide_strength (0..1, per-scene; default 0.35).
- build_anchor_guide_guides() emits a frame-0 self-image guide per anchor_guide
scene; merge_scene_guide_payloads() overlays it onto continuity/manual stacks.
- anchor_guide images are copied guide-only (set_primary=False) so source_image
is never wired -> empty latent comes free in the built-in pipeline.
- _apply_node_overrides(): force widget inputs on built-graph nodes from a
client-supplied node_overrides list (the optional custom-i2v bypass).
Frontend:
- inspector: Source option + guide image picker + strength slider.
- editor_settings: per-browser "Anchor as guide" section — declare a custom
i2v node and the input/state to force on those runs (value-only). Built-in
pipeline needs none of this.
- store: sends node_overrides only for runs containing an anchor_guide scene;
pipeline_caps: anchor_guide is chain-only.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Minimize now collapses a FloatingWindow to its title bar where it sits (a
window-shade), instead of sending a pill to a bottom-left dock. The button
toggles +/—; double-click the bar also expands. Removed the dock/pill code
and CSS.
Autocomplete accept (Tab/Enter/click) now appends a trailing space so the
trigger is "finished" and the menu doesn't re-open on the just-completed
trigger (it matched itself); skips the space when a space/delimiter follows.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
multiline_textbbox() returns float coords on Pillow >= 10, so tw/th flowed into
Image.new() as floats -> "TypeError: 'float' object cannot be interpreted as an
integer" the first time a styled text overlay was exported. Round the bbox coords
to int before using them for sizes and offsets. Surfaced by running the (previously
PIL-skipped) test_render_text_overlay_styled in the ComfyUI venv; all overlay tests
now pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The canonical generation/preview/key splitter (split_scenes) only treated a
shortcut as a scene cut when the shortcut's TRIGGER word was a key in the
transition DB. But split markers are commonly keyed by the EXPANSION phrase: a
"cut" shortcut expands to "Scene cut.", and the split marker is "scene cut.".
So the lookup `custom_map.get(_norm(raw))` missed, the shortcut was treated as
plain content, and NO cut was made — split_scenes returned one scene for
"A cut B cut C" while the verbatim editor split returned three. That disagreement
collapsed the timeline's middle scenes (and would have generated one scene).
Fix: when the trigger word isn't in the DB, also match the shortcut's EXPANSION
(`custom_map.get(_norm(exp))`). The generic "scene <N>" label is still NOT matched
on expansions, so an incidental "scene 2" inside a content shortcut never cuts.
Verified against the user's on-disk cut/qcut defs: split_scenes now agrees with
the verbatim split (2 scenes for cut x2 / qcut x2 / mixed). Added regression tests.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The query was the whole token since the last , ; \n delimiter, and a trigger only
matched if that entire token was a substring of it. Typing a normal multi-word
prompt grew the token past any short trigger, so suggestions never appeared.
Now match TRAILING WORD-RUNS of the token, longest first ("golden ho" before
"ho"), keeping substring matching so "@golden" still matches "golden". The longest
run that hits any trigger wins; its span is what acceptance replaces, so completing
a multi-word trigger can't duplicate words. Verified the matching across start-of-
field, mid-prose partials, post-comma, and no-match prose cases.
Also lifted .ac-menu z-index (9000 -> 99999) so it can never render behind the
Composer floating window when completing in the Compose tab.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reordering was Edit-menu-only (Move Clip Left/Right). Added ◀ ▶ buttons to each
clip's head bar (next to Remove) that call the same moveTimelineClip, disabled at
the ends. Works for both generative and video clips. (Add was already on the
timeline toolbar via + Add → Clip.)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The rebuilt editor never exposed character creation/assignment, so the feature
was vestigial: dead frontend plumbing plus generation branches that only fired
for legacy/imported projects. Removed it wholesale per decision.
Backend:
- Deleted movie_editor/backend/characters.py and the /library/characters routes.
- timeline.py: dropped normalize_character_bible / build_characters_anchor /
_load_character_map / _scene_character_prefix / character_media_refs_for_project
and friends. effective_anchor/effective_negative_prompt now return the project's
manual text; resolve_scene_identity_pin(cs) returns the project-level identity
pin only. Removed Scene.character_ids and Project.character_bible fields and the
character_ids fingerprint key.
- Continuity auto-guides keep working off continuity_settings.identity_pin_ref.
Frontend:
- store.js: removed state.characters, the character preview-key plumbing,
load/save/deleteCharacter, sceneCharacterIds/toggleSceneCharacter, character_ids
in patch/archive paths and exports.
- timeline.js: dropped clip-char badge rendering; api.js: dropped character routes;
view_bus.js: dropped chars fingerprint; tour.js: dropped demo characters + copy;
styles.css: dropped .clip-chars/.clip-char.
Tests: removed test_characters.py and the character-bible timeline tests; added
manual-anchor / manual-negative / project-identity-pin tests. 133 passed, 4 skipped.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Both class families had zero JS references in the rebuilt UI. Removed all of
.char-* (character inspector/chips — no surface in the new editor) and the
.plan-* plan-strip styling (plan UI is gone). Kept the two still-live classes
that share neither prefix's full set: .clip-chars/.clip-char (clip badges) and
.clip.off-plan (removed_from_plan marker).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Composer pt.2 backlog (#6/#7/#8):
- Import now asks Merge (overlay, name-overwrite) vs Replace all (wipe first),
for both shortcuts and split markers. Backend import_* gain a replace flag;
routes read ?mode=replace.
- Delete-all buttons clear every shortcut+category / every split marker, via new
clear_shortcuts / clear_transitions bridge fns + /clear routes.
- New Composer "Files" tab: on-disk file manager over the prompt-library JSONs and
the refinement-key store (keys + sidecars + value/latent .pt) with size, per-file
delete, and per-group delete-all. Path-traversal-safe (basename-only, root-checked).
Deleting library JSONs reloads Shortcuts/Splits so no stale entries linger.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Centralized text styling in OverlayUI (applyTextCss + textStyleControls) shared by
the program monitor, the Add-text modal, and the inspector. Pillow export renderer
honors every prop (real bold/italic faces or faux stroke/shear).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1. Image drop → i2v anchor: re-wire S.assignMediaToScene onto the timeline clip
(it was orphaned when the Plan card, its only caller, was removed).
2. Full rewiring in Full control: nodes.core_producers() now enumerates every
installed core node's outputs (Studio model/conditioning/sigmas, sampler
latent/images…), so a custom slot (e.g. a replacement sampler) can source
them via input_sources. core_graph() tags each output with source_id + lists
slot consumers; Models shows all core outputs (tappable in Full control).
3. Preview stuck on the media-bin preview ('anchor'): clear the transient
mediaPreviewId on transport scrub/seek (_seekNow), play (_play), and clip
selection (selectScene) so the program resumes following the playhead.
4. Remove t2v ('empty') as a selectable scene source; default new scenes to i2v
anchor. Anchorless scenes still fall back to t2v in the engine.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Scene properties: 'More editing' → slim 'Scene options'; Frames/FPS hoisted
to the always-visible body; effects (blur/fade/zoom) dropped here (now applied
from the timeline + Add → Effects, same scene.effects); source trim, i2v
guides, and Exclude kept.
- Composer: shortcut editor modal now stacks above the floating window (z-index).
- Composer button restyled to match the neighbouring panel tabs.
- Categories/sub-categories: persisted managed list (nested) in templates.py;
shortcut editor uses Category/Sub-category dropdowns with inline '+ Add new…'
mini-modals; Shortcuts '+ Add' is now a dropdown (Shortcut/Category/Sub-category).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- templates.py: persist category + sub_category on each shortcut (normalized,
free-text; sub-category nests under category).
- Composer shortcut editor: Category + Sub-category inputs; list rows show a
"category · sub" tag and filter on it.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Composer button moves next to the Assets/Preview/Properties tabs (was in the
menu bar).
- Remove Characters entirely from the UI (Composer tab + the scene inspector's
character chips). Backend character code left dormant.
- New "Compose" tab hosts the Global prompt (moved out of the inspector); stays
in sync with the timeline, never clobbers active typing.
- Properties decluttered: drop Video transition, Blend length, Generation split
marker and "Pause before next clip" from a scene, and "Split before scene 1"
from the project — these are driven by the global prompt and timeline.
- Swap Import/Export arrows in Shortcuts & Splits (Import ↓ "to me", Export ↑).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Strip the five non-media tabs from the left panel — it shows projects + the
media bin and nothing else:
- Characters / Shortcuts / Split markers already live in the Composer window.
- Effects / Transitions are edited per-clip in the Properties inspector
(Video effects + Outgoing seam), so the preset-apply tabs were redundant.
Removed the orphaned tab renderers and their helpers (editors, modal,
search/filter, characterForm). Updated the welcome tour: the old "Media
libraries / .bin-tabs" step now points at the Composer button, and the
split-marker hint points to the Composer.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reshape the editor frame to OpenCut's layout (Assets | Preview | Properties
over a full-width Timeline), keeping every panel's mount point so existing
modules keep working:
- index.html: single horizontal main-row of three resizable columns; preview
is the flexible center, Assets/Properties flank it. Plan strip removed
(recipe now lives in the Properties column per the one-timeline model).
- styles.css: new workspace layout + graceful column-toggle degradation;
floating-window + Composer-button styling.
- app.js / layout.js: rewire splitters (--media-w / --properties-w / --timeline-h)
and column-visibility chips for the new arrangement.
- floating_window.js: reusable OS-style window (drag / minimize-to-pill /
maximize / close); foundation Models & Engine settings can adopt later.
- composer.js: Composer window hosting Characters / Shortcuts / Split markers,
toggled by a header "Composer" button.
- remove plan_strip.js (superseded).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
'Remove from plan' (plan card) now: if the gen-unit has a render, mark it excluded
(so generation + prompt skip it everywhere — reuses every existing !excluded filter,
no audit) plus removed_from_plan (hide from the plan strip, override the single export
skip so the clip still renders, and skip the 'excluded' dim styling). Ungenerated
scenes are still a plain delete. Inspector shows a 'Restore to plan' banner on an
off-plan scene; timeline marks it with a subtle dashed outline.
This retires ghosts for the plan-removal path: the removed scene persists as a real
result clip in the cut, not a separate ghost. New Scene.removed_from_plan field
(persisted). Backend tests green (62).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The timeline is the result; its order is now project.timeline_order (scene ids),
which plan reorder never touches. buildPreviewSegments + _renderClips (export) read
this cut order via orderedTimelineScenes(); it's self-healing (drop gone ids, append
new scenes in plan order) and maintained on load + structure change, with a backend
field so it persists.
- Menubar 'Move Clip Left/Right' reorders the CUT (moveTimelineClip → timeline_order).
- Plan-card '← Plan / Plan →' reorders the PLAN (moveScene → scenes / generation order)
without moving the timeline clip.
- view_bus fingerprints include timeline_order so a cut reorder re-renders.
Reordering the plan no longer moves or alters already-generated videos on the
timeline. Backend tests green (62). Empty timeline_order falls back to plan order
(back-compat). Still TODO: 'remove from plan keeps the clip on the timeline'
(ghost retirement) — entangled with generation/export skip semantics, do next.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The timeline is the rendered result, so setting up a generation must not touch it.
Removed the clip-level anchor drop and the timeline track's image->anchored-scene
drop. Image media now drops onto Plan cards (sets that scene's i2v anchor) or onto
empty Plan space (creates a new anchored scene). Video clips (finished results)
still drop on the timeline track. Plan-only image filter; teal drop-target hint.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Completes untying plan edits from the rendered result on the timeline. The clip
is the RESULT, so it now labels itself from the frozen render prompt
(renderPromptForScene) instead of the live scene text — editing a scene's prompt
in the plan no longer mutates the already-generated clip's identity here (it just
shows 'edited' until you regenerate). Falls back to live plan text only when the
scene isn't generated yet. Video clips unchanged.
With the earlier immutable-length fix, a plan edit (prompt/length) now leaves an
existing generated video's content, duration, AND label on the timeline alone;
only regeneration updates it. Editorial props (effects/trim/audio) stay live.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New plan_strip.js band (#plan-zone) above the timeline: compact recipe cards
(anchor thumb + prompt + status: not generated / in sync / edited), click to
select, chevron opens a full-width inline editor (prompt, source, anchor picker,
Generate this scene, Remove, Advanced -> inspector). Collapsible. Placed above
#split-bottom so the timeline splitter / --timeline-h math is untouched; it's a
bounded, additive band (dock flex:1 absorbs it).
Plan = 'what will generate'; the timeline below is the immutable rendered result.
Edits are quiet/debounced and the band won't rebuild while a field is focused
(no input disruption). Selection syncs with the timeline.
Phase 1 / additive: the inspector's per-scene panel is intentionally kept as the
full editor + fallback (the plan can be Hidden) — retiring/merging it and removing
ghosts are the next steps.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The convert verbs don't fit the revamped plan/result direction and need a
rethink (see deferred notes). Remove the toolbar buttons now and the two
inspector hints that pointed at them, so nothing references a control that's
gone. The convertToVideo/convertToScene store functions are left intact and
callable — only the UI entry points are removed; the rework comes later.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A render never recorded the length it was actually made at — sceneDurationSec
recomputed from the LIVE plan every time, so changing project/scene length
retroactively truncated already-generated videos and made their tail unreachable
in the preview, player, and final export alike.
Now each render freezes its real length at generation time (durationSec). A
generated scene in project (default) frames mode plays/lays-out/exports at that
frozen length; the project/scene default only drives the NEXT generation.
Explicit per-scene length (timeline/custom), slip-trim, and splits still win
(a split clears the frozen length so both halves revert to plan layout).
- store: renderDurationSec + _planDurationSec; sceneDurationSec is render-aware;
_recordSegment freezes durationSec on scene renders and ghosts; trim/resize
measure from the shown length; segmentDurationSec delegates ghost length to
_ghostDurationSec (de-dupes the inline calc).
- inspector: scene duration hint shows 'Rendered ~Xs - plan Ys - Regenerate to
apply' when a render is frozen at an older plan length.
Centralized in sceneDurationSec so timeline, player, audio offsets/durations and
the final stitch all agree. No-op in the common case (plan == render). Renders
made BEFORE this change have no frozen length and stay plan-driven until
regenerated.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Exposed node controls (e.g. a LoRA strength in project settings) now carry the
node's actual min/max/step/default from object_info instead of step=1/no bounds:
- capture numeric widget meta at expose time and on link creation (models.js)
- apply it in the Models node editor and the inspector's Exposed controls
- backfill meta onto pre-existing exposures when Models is opened / refreshed
Typing an exposed value no longer gets disrupted: the field now carries a data-k
so the edit guard protects it, and setModelInput/setModelLink update in place +
debounce the server save (was one saveModels POST per keystroke, notifying twice
and rebuilding the field mid-type). Pending model saves flush on blur and before
generate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Rebuild guard now protects only typed/dragged fields (text/number/range),
not selects/checkboxes — so dependent controls (custom length input, Ken
Burns knobs, Steer mode 'absolute', Embed/Mid-scene guide) reveal on the
toggle instead of only after blur (inspector.js + engine_settings.js).
- Tag blend-length and video 'Source in' fields so non-quiet patchScene no
longer yanks them mid-type.
- Blur % and Zoom amount % slider labels update live while dragging.
- Surface Width/Height in the Project Output section (out of the collapsed
Advanced fold); leave Max scenes in Advanced.
- Custom scene length reflects its snapped value back into the field on commit.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
With exactly one transition trigger in the prompt (one "cut", one "qcut", etc.),
split_scenes produced anchor + 1 scene — so len(canon_scenes) == 1. The
previous guard `> 1` skipped the clean-text encode path, leaving
output_conditioning built from the raw prompt_to_encode which still contained
the trigger word. The CLIP encoder received "cut" and the model generated it
in audio.
Changing to `>= 1` ensures any split with at least one clean scene uses the
properly stripped scene text, even when there's only one scene to encode.
The chain sampler receiving a single conditioning entry is fine — it just
renders a single pass with no chaining.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Normalization is now available in both Hybrid Euler 2S and Distilled Flow
samplers, making the standalone Normalizing sampler redundant. Removes the
node class, its sampler function, two private helpers (_parse_norm_factors,
_apply_av_norm_factors), the Studio/Movie Editor "Normalizing" type option,
and the defaultNormalizing() factory. Stale "same as the Normalizing sampler"
tooltip references in both sampler nodes are updated.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
A renamed or removed file (e.g. an old distilled LoRA) left a slot's saved
combo value out of sync with object_info's current choices. The Models menu
select then showed the live first choice (browser default for "no matching
option") while the saved config still held the stale string, which the
builder passed straight through to ComfyUI and failed validation.
Coerce in both places: the builder falls back unknown combo values to the
node's current default/first choice, and the Models menu select persists
what it actually displays instead of leaving the stale value on disk.
onStore marked the data fingerprint as handled before checking whether
render() actually redrew. render() can decline (focus/drag/scroll), so
post-generation prompt edits left the timeline showing stale text and
the "Generated with" badge. Only commit the fingerprint when the render
succeeds, both in timeline.js's onStore and view_bus.js's subscribeZone.
Deletes the FunPack Scene Builder node and the Studio Scene Builder feature
— the per-key scene database (scene_db / universal_memory / saved scenes),
the Studio "Scene" tab, scene-phrase authority over classification, and the
scene-database wildcard cleanup. It was redundant: helpful on paper but
effectively unused, undrivable from the Cutting Room, and a risk to shortcuts.
Removed:
- node registration (__init__.py, funpack.py) + web/funpack_scene_builder.js
- templates.py: scene-DB storage layer (load/save/normalize/empty_scene_db,
SCENE_DB_VERSION/SCENE_STATE_FIELD/SCENE_CATEGORY_SOURCES, scene_store_path),
all scene_* helpers, resolve_scene_database_wildcards, the FunPackSceneBuilder
class, and the /funpack/scenes* routes
- conditioning.py: _v2_scene_builder_db / _v2_scene_memory_item /
_v2_apply_scene_builder_authority / _v2_scene_builder_category_for_entry /
_v2_sync_scene_builder_memory / _v2_resolve_scene_builder_wildcards (+ wildcard
helpers + _v2_scene_key), the scene_db threading through classify/learning,
the scene_category_locked phrase fields + their training branch, the
state["scene_builder"] preservation, and the Studio scene_builder prompt mode
- web/funpack_studio.js: Scene tab, SB_MODES, scene_builder settings, renderScene,
fetch/saveScene, the Session Scene-Builder section, and the Refiner banner/notice
- tests/test_scene_builder.py (whole file) + scene-builder tests in
test_v2_category_alignment.py; the SceneBuilder example workflow + its doc;
README link; Scene Builder mentions in docs/FunPackStudio.md
Kept intact: shortcuts (apply_prompt_shortcuts / shortcut DB), transitions and
the canonical split_scenes splitter, and FunPackRefinementKeyLoader. Studio now
always uses the connected positive_prompt. No new test failures (the 16/97
remaining in tests/ are pre-existing env/sampler failures); movie_editor 140 pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A scene removed mid-generation becomes a ghost; when that in-flight run
completes, _recordSegment attaches the finished media to the ghost
(pendingGen:false) and deliberately does NOT push its id to
recordedSceneIds. But _pruneGhostsAfterRegen dropped any ghost whose
afterSceneId was in recordedSceneIds — and a ghost anchored after a sibling
scene in the same run matches that, so the freshly-finished ghost was
removed from the timeline the instant generation ended.
Collect the ids of ghosts that received media this pass (completedGhostIds)
and protect them in _pruneGhostsAfterRegen. Genuinely stale ghosts (anchored
after a recorded scene, not updated this run) still get pruned as before.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reworks the "Wrong appearance" rating from a (now-removed) prompt-repair
signal into a conditioning-level consistency anchor (option b). "Wrong
appearance" now means "character consistency wasn't preserved" and steers
the next generation back toward the established character.
Capture (_v2_update_appearance_anchor, wired into both the single-run
learning path and the shared per-scene suite _v2_learn_scene_into_state):
- good rating (like/nailed_it/loved_it/loved) → store the rated run's
conditioning as the per-key "blessed appearance" (overwrite = last good)
- wrong_appearance → store the rejected run's conditioning as the "drift"
global_state is already per-refinement-key, so both live with that key.
Apply (_v2_apply_conditioning_memory_impl, after the intent-family delta):
when the user rated the previous gen wrong_appearance, gently pull this gen
toward the blessed appearance (lerp 0.05) and repel from the drift (0.04),
reusing _v2_apply_conditioning_payload / _v2_repel_conditioning_payload. No
ramping; the existing 7.5% delta cap bounds the net effect. No-op when
nothing is stored or shapes mismatch.
Drops the dead wrong_categories field (zero consumers after Part A) and
keeps skip_value_function (the anchor is a conditioning nudge, not a reward).
Tests: 7 new unit tests (storage + overwrite + skip + pull/repel + idle +
non-trigger); updated test_wrong_appearance_rating_is_available for the new
semantics. Zero new failures vs HEAD (the 10/31 remaining are pre-existing
env failures from missing server/comfy modules).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Removes the now-unreferenced repair-only machinery left behind after
Stage 2 (1/3) neutralized the application:
- _v2_prompt_repair_text_allowed
- _v2_emphasized_prompt
- _v2_repair_prompt_for_missing_axes and the repair-candidate helpers
- perfect_repairs / rejected_repairs storage + perfect-repair eviction
note in the intent-family learn path
Shared helpers still used by intent-alignment (e.g. _v2_repair_intent_roots,
_v2_repair_candidate_matches_intent, _v2_prompt_contains_text) are kept, as
is the repair_feedback / active_repair_axes "what's missing" signal the
advisor reads.
Deletes the 11 category-alignment tests that exercised the removed methods
directly. No new test failures (the 10/31 remaining are pre-existing env
failures from missing server/comfy modules).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neutralize the repair application in refine(): the intent-aligned prompt is
encoded as-is — perfect-repair phrase injection, missing-axis repair, and the
emphasis pass are gone. The advisor remains the only prompt-rewriting path, and
repair_feedback/active_repair_axes is KEPT (it's the 'what's missing' signal the
advisor still reads). Drop the prompt_repair param from refine(), INPUT_TYPES,
FunPackStudio, and both UIs (web + engine_settings).
The dead repair-only methods (_v2_repair_prompt_for_missing_axes, perfect-repair
phrases, etc.) come out in the next commit; shared helpers like
_v2_repair_intent_roots (used by intent alignment) stay.
Deleted the now-obsolete test_repair_candidates_saved_as_json_lists (tested the
removed injection). No new test failures vs dev.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Generation now reads split_scenes, so the duplicate _v2_split_prompt_by_transitions
method has zero callers — deleted. bridge.parse_timeline (the 'what Studio sees'
preview) now derives from split_scenes too, so the preview's scene count/boundaries
match generation exactly (no spurious 'split produced N but timeline has M' warnings).
The lossless RAW editing split (parse_timeline_verbatim / split_timeline_verbatim)
stays separate — it has a genuinely different lossless requirement (round-trips the
exact typed text). It still uses the old offset-projection path; converting it to a
lossless piece-walker is the one remaining Stage-1 loose end.
Tests: 33 + 140 pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>