Commit Graph
817 Commits
Author SHA1 Message Date
digital-garbageandClaude Opus 4.8 c47bcfc71b Movie Editor: fix preview freeze from audio-volume assignment
A non-finite video.volume throws on assignment; since _applyFx runs every rAF tick, that
threw inside the tick and froze playback. Volume is now sanitized (finite, clamped) and
the assignment is try-guarded, and the tick's _applyFx call is wrapped so no effect error
can ever stop the playback loop.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 01:11:49 +03:00
digital-garbageandClaude Opus 4.8 54d58a1e6b Movie Editor: audio editing — per-clip volume, inserted tracks, original toggle
- Per-clip original audio gain (Scene.audio_volume; inspector slider, 0 mutes). Applied at
  render (volume filter) and in the live preview (video.volume, clamped 0..1).
- Project-level audio mix: keep_original_audio toggle (drop the generated LTXAV audio) and
  audio_tracks[] — inserted background tracks from the Media bin, each with start offset +
  volume. Mixed at render via adelay + amix(normalize=0), trimmed to the montage length.
- All four cases work: lower/boost a clip, add one or many tracks, keep original + tracks,
  original-only, tracks-only, or fully silent (no audio stream mapped).
- Render route resolves track media to files (media.path_for), appends them as inputs after
  the clips, and maps [aout] only when there's audio. renderFinal flushes the project save
  first (tracks/toggle live on the project, read from disk at render).
- Inspector: per-scene Clip audio + Project Audio section (toggle, track cards, add-from-bin).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 01:03:44 +03:00
digital-garbageandClaude Opus 4.8 aeded5cafa Movie Editor: fix render — normalize canvas + virtual zoom (zoompan)
Render failed two ways: clips with different native sizes (768x768 vs 576x768) broke
xfade (needs matching size/fps/sar), and zoom physically rescaled the frame.

- Every clip is now normalized to one canvas (scale+pad to clips[0] size, fixed fps,
  setsar=1) before effects, so xfade/concat always match.
- Zoom is virtual via zoompan: output stays fixed at canvas size, only the content scales
  within it (in 1.0->1.2, out 1.2->1.0). No frame-size change -> renders cleanly.
- Preview matches (zoom-out now pulls back 1.2->1.0); labels updated (push / pull back).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 00:44:36 +03:00
digital-garbageandClaude Opus 4.8 6eab8d9632 Movie Editor: Effects dropdown on the timeline toolbar
'✨ Effects ▾' on the selected clip: pick an effect/transition (zoom in/out, blur, fade
in/out, crossfade/fade-to-black/wipe → next), enter its value (strength/seconds/frames)
where relevant, and Add. Writes onto the scene, so the inspector's per-scene controls
remain the single source of truth and reflect whatever is added here.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 00:39:54 +03:00
digital-garbageandClaude Opus 4.8 4e9d0e4c1d Movie Editor: Play from end-of-timeline restarts from the beginning
If the playhead is at/past the end (or on no clip) when Play is pressed, reset it to 0 and
play from the top instead of doing nothing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 00:31:37 +03:00
digital-garbageandClaude Opus 4.8 8119ba2809 Movie Editor: drag-drop clip reordering on the timeline
Grab a clip body and drag left/right to reorder; an amber insertion line shows the drop
spot, and rebuilds are hard-blocked mid-drag so the dragged clip doesn't vanish. A 5px
threshold keeps plain clicks as select; trim handle and action buttons opt out. store
gains moveSceneTo(id, index). The tiny ‹/› move buttons stay as a fallback.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 00:31:11 +03:00
digital-garbageandClaude Opus 4.8 4da41f3333 Movie Editor: per-scene video effects + seam transitions (render + live preview)
Post-decode pixel ops (never re-encode to latent):
- Per-scene effects: gaussian blur, fade in/out, Ken-Burns zoom in (crop) / out (pad).
  Stored in Scene.effects {blur, fade_in, fade_out, zoom}.
- Seam video transitions: crossfade/dissolve, fade-through-black, wipe L/R via
  Scene.video_transition + transition_frames (length). Crossfade overlaps the clips
  (xfade + audio acrossfade) so the montage shortens by the transition length.
- Render route builds a filter_complex (_build_render_filter): per-clip effect chain via
  scale eval=frame + crop/pad/gblur/fade, then a left-fold of xfade/concat seams.
- Live preview approximates per-clip fx (CSS blur/scale/opacity, playhead-synced so it
  tracks scrubbing); crossfades preview as hard cuts but render correctly.
- Inspector exposes all of it per scene.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 00:28:41 +03:00
digital-garbageandClaude Opus 4.8 6433c87881 Movie Editor: fix dead transport buttons during playback
The playhead listener called _renderTransport on every rAF tick, clearing and recreating
the play/pause/stop buttons ~60x/sec. A click's mousedown/mouseup straddled a rebuild, so
the button was destroyed mid-click and no click fired. Playhead ticks now update only the
timecode text and play-button glyph in place; full rebuilds happen only on discrete
transport actions and store changes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 00:12:22 +03:00
digital-garbageandClaude Opus 4.8 352ed35ef9 Movie Editor: capture frame to Media bin when no scene chosen
The transport frame capture no longer requires a scene: with the selector left on
'— save to Media bin —' it just saves the frame as an asset (usable as an anchor later
via drag/pick); pick a scene to apply it as that scene's i2v anchor. Button label
adapts (Save frame / Use as anchor).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 20:57:16 +03:00
digital-garbageandClaude Opus 4.8 29b7797c80 Movie Editor: timestamp export/render filenames for uniqueness
Scene export -> <project>_sceneN_YYYYMMDD-HHMMSS.mp4; final render ->
<project>_final_YYYYMMDD-HHMMSS.mp4, so repeated saves never collide.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 19:18:00 +03:00
digital-garbageandClaude Opus 4.8 cac5b07e39 Movie Editor: only inject scene separators for multi-scene runs
Single-scene runs are one segment already, so no 'scene N' marker is injected (avoids
leaking it into the prompt). Multi-scene runs inject before every scene lacking a leading
trigger (incl. the first, which Studio would otherwise fold into the anchor).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 19:16:38 +03:00
digital-garbageandClaude Opus 4.8 77bf2f8439 Movie Editor: fix multi-scene runs + anchor/export/fallback + studio toggles
- #1 Multi-scene run only generated scene 1: a carry scene has no leading transition so
  Studio merged it. Generation prompt now injects a separator before any scene lacking a
  leading trigger (transition_to_next or generic 'scene N') so Studio splits into exactly
  one conditioning per scene. Display/global prompt stays verbatim (for_generation flag).
- #2 'Use as anchor' no longer defaults to scene 1 — requires picking a scene, so it can't
  silently overwrite an existing image. Anchor capture drops the obsolete target.
- #3 Export uses unique names: <project>_sceneN.mp4.
- #4 A scene whose image was deleted falls back to carry (i2v guides) in run splitting.
- #5 Timeline/inspector edit-guard could stick (focused control removed w/o focusout),
  freezing refresh. Guards now self-clear when focus is actually gone.
- #6 Expose Studio refiner toggles (vision conditioning, reference injection, prompt
  repair) in the inspector -> studio_settings.refiner.
- #7 Embed-guidance mode (relative/absolute) now selectable (sampler combo knob).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 19:15:46 +03:00
digital-garbageandClaude Opus 4.8 7ffee3e688 Movie Editor: per-clip in/out model — splits & deletes honored in preview + render
Replace whole-run renderedSegments with per-scene sceneRenders {media, inSec}. The
player builds per-scene clips (media, startSec, durationSec, inSec) and plays each clip's
[inSec, inSec+dur] window via a rAF tick (precise out-points, so deleted parts aren't
played; contiguous split seams continue seamlessly). Split sets the second half's inSec;
delete drops the mapping. Render route takes per-clip in/dur and concatenates only kept
clips (ffmpeg -ss/-t + concat filter, audio preserved). Export/hasRender use sceneRenders.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 19:08:49 +03:00
digital-garbageandClaude Opus 4.8 b8fa482512 Movie Editor: don't pop boot overlay on video load errors; keep render across split
- Boot-error overlay ignored resource-load errors: a pooled <video> failing to fetch
  fired a capture-phase 'error' with empty message -> scary 'load error' banner. Now
  skip events targeting an element (resource errors); only real script errors show.
- Split now assigns the new half a client id and adds it to the rendered segment's
  sceneIds, so the existing video spans BOTH halves (one source, like a real NLE) and
  the monitor keeps playing across the cut instead of going blank.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 14:52:32 +03:00
digital-garbageandClaude Opus 4.8 c39af077ab Movie Editor: make Reset Studio session a toggle (disarmable)
Clicking 'Reset Studio session' again now cancels a pending reset (mis-click safe);
the menu shows 'armed — click to cancel' when set.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 14:47:53 +03:00
digital-garbageandClaude Opus 4.8 8ce0a24c40 Movie Editor: fix log panel not closing
.log-panel had display:flex, which overrode the [hidden] attribute's display:none, so
the close/toggle never hid it. Add .log-panel[hidden] { display:none }.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 14:46:14 +03:00
digital-garbageandClaude Opus 4.8 a7b553ca54 Movie Editor: inject scene image without a target; closable boot-error overlay
- _prepare_media no longer requires a per-scene 'target' (removed earlier) — it now
  injects the scene image as a LoadImage from just the asset ref. Fixes 'ImageTransformKJ
  .image (IMAGE): no node outputs IMAGE' for image-anchored scenes/runs: the image is
  now materialised and auto-wires to IMAGE inputs.
- Boot-error overlay gets a ✕ dismiss button so it can't permanently block the top menu
  (so you can still reach Restart ComfyUI etc.).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 14:41:06 +03:00
digital-garbageandClaude Opus 4.8 3ab367fb51 Movie Editor: ComfyUI backend log viewer
Add a 'Log' button in the menubar (next to Saved) that opens a collapsible panel
streaming ComfyUI's real backend log. The bridge tees stdout/stderr into a ring buffer
(writes still pass through to the terminal; captures print + logging); /api/log returns
the tail. Panel polls every 1.5s while open, auto-scrolls (pauses if you scroll up),
with Copy. Far more informative than our wrapped error messages.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 14:39:23 +03:00
digital-garbageandClaude Opus 4.8 50ef7edc57 Movie Editor: Reset Studio session button; don't auto-assign ratings; fix rating dropdown
- FunPack menu 'Reset Studio session' arms reset_session for the FIRST run of the next
  generation (false for the rest); shows ✓ armed. reset_session lives in
  studio_settings.refiner, set explicitly per run by the builder.
- Unrated scenes now send '-Just forget it-' to Studio instead of its default learning
  rating, so the system never learns from a rating the user didn't give (esp. after a
  reset / first generation).
- Timeline no longer rebuilds while a control (rating/transition dropdown, trim input)
  is focused, so autosave/progress notifies can't close the rating dropdown mid-pick;
  it re-syncs on blur.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 14:33:33 +03:00
digital-garbageandClaude Opus 4.8 9f6a6d3ba1 Movie Editor: fix per-scene split — set split_by_transitions in studio_settings
CRITICAL: split_by_transitions is NOT a top-level FunPackStudio input; Studio reads it
from studio_settings.refiner.split_by_transitions (default False). The builder set it
as a top-level input, which ComfyUI silently dropped (not in INPUT_TYPES) — so Studio
ran in single-scene mode and every scene got the whole prompt (scene 2's action bled
into scene 1). Now force split_by_transitions=True INSIDE the studio_settings JSON
(after user overrides), so Studio actually splits the combined prompt per scene.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 14:26:36 +03:00
digital-garbageandClaude Opus 4.8 c38ba2c09e Movie Editor: per-scene Studio rating + wire outputs into widget inputs
Rating:
- Scene.rating (V2_RATING_LABELS); /api/rating-labels exposes the options.
- Timeline toolbar 'Scene N ★' dropdown, shown ONLY when FunPack Studio is the
  conditioning provider AND the selected clip has a render. Rates that clip's own
  scene (cut-aware by scene id).
- Generation injects the run's rating into Studio (studio_inputs.rating) so Studio
  refines the next generation from it; empty = use Studio's default.

Wiring:
- Widget inputs (INT/FLOAT/STRING/BOOLEAN, e.g. EmptyLatentVideo.width/height) are
  now offered as manual wire destinations (ComfyUI converts a widget to an input when
  wired) — so ImageTransform's width/height outputs can drive them. They're still not
  auto-wired, so widget values aren't clobbered unless wired explicitly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 14:22:29 +03:00
digital-garbageandClaude Opus 4.8 77b4084a81 Movie Editor: progress hook accepts ComfyUI's extra kwargs (node_id)
ComfyUI calls PROGRESS_BAR_HOOK with extra args (e.g. node_id), which broke our chained
hook -> VHS_VideoCombine errored. Accept *args/**kwargs and forward them to the previous
hook (falling back to the 3-arg form if it can't take them).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 14:13:31 +03:00
digital-garbageandClaude Opus 4.8 f1c33b81ad Movie Editor: resolve V3 dynamic-combo options to their key value
COMFY_DYNAMICCOMBO_V3 options are dicts {key, inputs}, not strings — we were using the
whole object as the value (showing '[object Object]' and feeding ImageTransformKJ an
object). Normalise combo choices/defaults to the selectable key string everywhere
(_combo_choices/_combo_default), and coerce any stale '[object Object]'/dict slot value
back to the default at build. Combos now show real options and emit valid values.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 14:10:37 +03:00
digital-garbageandClaude Opus 4.8 5079ee7cd2 Movie Editor: seamless scrubbing via preloaded video pool (no black on cuts)
Replaced the single <video> (which reloaded src per clip -> black flash crossing a
cut) with a pool of preloaded <video>, one per clip file, in a persistent stage; only
the active clip is shown. Scrubbing/playing across cut boundaries swaps which video is
visible — already loaded, so the frame appears immediately. The pool is rebuilt as the
timeline changes (cuts/regens) and segment positions recompute live; _currentSeg is
refreshed each render so edits stay in sync.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 14:05:45 +03:00
digital-garbageandClaude Opus 4.8 e4544d2779 Movie Editor: step progress + Interrupt; treat V3 dynamic combos as widgets
- Generation progress: chain ComfyUI's global ProgressBar hook (no clobber) to record
  sampler current/total steps; /api/progress exposes it; the store polls it ~700ms and
  shows 'step X/Y' + a progress bar in the program monitor.
- Interrupt button (player overlay) -> /api/interrupt -> ComfyUI /interrupt; the run
  loop stops and shows 'Interrupted.'
- Fix ImageTransform (V3) blocking: keep_proportion/extra_padding/invert_crop are
  COMFY_DYNAMICCOMBO_V3 dropdown widgets, not sockets. Recognize any 'COMBO'-containing
  type as a widget across connection_inputs / widget_inputs / ports / widget defaults,
  so they're configured as combos and never reported as missing connections.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 13:59:52 +03:00
digital-garbageandClaude Opus 4.8 9a79c29f46 Movie Editor: click empty timeline to clear scene selection
Clicking the timeline background (not a clip, seam, or the ruler) now deselects the
current scene, switching the inspector back to Project view.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 13:54:43 +03:00
digital-garbageandClaude Opus 4.8 14df70a191 Movie Editor: play the whole sequence, not just one clip
The program monitor stalled after the first segment: on segment-end (and on play) it
called video.play() immediately after setting a new src + load(), so the play promise
rejected (media not ready) and the chain stopped — looking like it only plays the one
(highlighted) scene. Added a _playPending flag: when loading a different file, playback
starts on loadedmetadata; same-file seeks play immediately; pause cancels pending
autoplay. Segments now play through seamlessly, skipping ungenerated gaps.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 13:51:55 +03:00
digital-garbageandClaude Opus 4.8 02c89beef7 Movie Editor: drop redundant per-scene 'Feeds node input' target
Routing is owned by Models/nodes now (the scene image is an auto-wiring IMAGE
producer; a node can pull it via Input source = Timeline). The per-scene target was
a confusing second place to wire the same thing. Removed it from the image and
generated-frame sources; the scene just supplies the anchor image and the pipeline
routes it (default → Studio source image). Existing explicit targets still honored.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 13:28:02 +03:00
digital-garbageandClaude Opus 4.8 1214029f1c Movie Editor: scene/timeline image counts as an IMAGE source
A node's IMAGE input (e.g. ImageTransform) reported 'no node outputs IMAGE' because
the scene image comes from the timeline (injected as a LoadImage), not a node output.
Now the builder always materialises the scene image as media_load and registers it as
an IMAGE producer, so unwired IMAGE inputs auto-wire to the scene image. The Models
modal no longer flags required IMAGE inputs (the timeline can always feed them).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 13:24:38 +03:00
digital-garbageandClaude Opus 4.8 15a4fbf7d7 Movie Editor: preserve scroll, stop per-second autosave (save on blur instead)
- Inspector preserves scrollTop across rebuilds, so editing no longer jumps the panel
  to the top.
- Autosave only persists to disk; it doesn't need to fire every keystroke. Free-text/
  number fields now debounce 6s and are FLUSHED on blur (flushSave); discrete actions
  save ~1.2s after the last change. generate()/generateMontage() flush first so the
  server has the latest edits before reading the project.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 13:22:02 +03:00
digital-garbageandClaude Opus 4.8 0ca06b4431 Movie Editor: stop autosave from interrupting field editing
The inspector rebuilt on every autosave (~1s), destroying the field being typed in;
number inputs can't preserve selection (no selectionStart), so a select-all + retype
appended instead of replacing ('512' + '640' -> '512640'). Now the inspector skips
rebuilding entirely while one of its fields is focused, and re-syncs to state ~60ms
after blur (no rebuild if focus moved to another field). Typing is never interrupted.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 13:19:12 +03:00
digital-garbageandClaude Opus 4.8 3eef6de2b8 Movie Editor: flag slots with unfed required inputs; only for active slots; honest 'ready'
- validateSlot now checks required connection INPUTS are actually fed (explicit input
  source, incoming wire, or a single auto-wire producer) — matching the builder's
  blocking — so a node like ImageTransform with an unwired 'image' input is flagged
  instead of showing 'ready'. Flagged slots get a clear red highlight (bg + ring).
- 'Pipeline ready' banner now reads 'Not ready — N slot error(s) to fix' when errors.
- Only ACTIVE slots are validated/blocking: a slot that feeds nothing (no output wire,
  not referenced by a core override) is inert and no longer blocks generation or gets
  highlighted — builder skips inert slots in auto-wire, frontend mirrors the rule.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 13:16:46 +03:00
digital-garbageandClaude Opus 4.8 3ae218c5bf Movie Editor: human-readable node names in generation-blocked messages
Blocking/auto-wire report messages used the internal id (e.g. 'slot_5u09gm5'),
which is exposed nowhere in the UI. Map each node id to 'Label [NodeClass]' (core
nodes use their display name) so errors read like 'Image Transform
[ImageTransformByNormalizedAmount].image (IMAGE): …'. Also reworded the no-source
message to point at adding an outputting node (or that the input may be unneeded).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 13:12:40 +03:00
digital-garbageandClaude Opus 4.8 29e929584a Movie Editor: null-safe modal close; prevent double-open
Fixes 'TypeError: overlay is null' at models.js close handler — opening Models
twice orphaned the first overlay's handlers (they reference the module overlay,
now pointing at the second), so closing then closing again hit a null overlay.
Guard close/backdrop handlers and bail early from open() if a modal is already up.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 13:09:12 +03:00
digital-garbageandClaude Opus 4.8 8ce68e7d74 Movie Editor: fix forceInput-STRING blocking generation; surface exact blocker; move core panel up
- Regression fix: making forceInput STRING sockets count as connection inputs made
  auto-wire treat them as required inputs needing a STRING source — with none, the
  builder blocked with 'no source available' while the Requirements panel (model/clip/
  vae/latent/image only) stayed green. forceInput widget sockets always have a widget
  fallback, so connection_inputs now marks them required=False: still wireable, never
  blocking. Resolves 'A required pipeline input has no source' with everything green.
- Generation errors now pass through the builder's 'Generation blocked — <node>.<input>
  (<TYPE>): …' detail instead of a vague generic message, so the exact culprit shows.
- Built-in pipeline panel moved directly under Pipeline requirements so it's findable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 13:08:00 +03:00
digital-garbageandClaude Opus 4.8 023f42eb8a Movie Editor: show + re-wire the built-in core pipeline
The Models modal only listed user loader slots; the fixed core (Studio, Sampler,
Conditioning, Concat/Separate, audio decode, VHS, SaveRefinement, KeyLoader,
primitives) was invisible, so internal wiring couldn't be inspected or changed.

Add builder.core_graph() describing each core node's inputs (current source +
candidate sources) and outputs (internal destinations), exposed at /api/core-graph.
New collapsible 'Built-in pipeline' panel in the Models modal renders it and — not
read-only — lets each core input be re-wired via a source picker. Overrides are
stored per-project as models.core_overrides and applied by build() (4b), beating the
default CORE_LINKS wiring and auto-wire.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 13:02:18 +03:00
digital-garbageandClaude Opus 4.8 c0dff7893d Movie Editor: emit widget defaults, wireable STRING/forceInput sockets
- builder now emits a value for EVERY widget input (type-appropriate empty when no
  default is declared), matching ComfyUI's frontend. Fixes generation refusing to
  start on required widgets with no default (e.g. ImageTransform's 'bboxes',
  refinement key fields) — they were dropped from the graph and ComfyUI rejected the
  prompt for a missing required input. Empty required widgets are now a warning, not
  a blocking error, in the Models modal.
- connection_inputs + ports_from_input_types now include forceInput STRING sockets,
  so refinement_key_input on Studio and the Chain Sampler is visible and can be wired
  manually (was invisible because STRING is a widget type). Lets a custom STRING
  source override the default keyloader wire.
- Refinement key stays optional: the keyloader defaults to the keyless 'none' key.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 12:56:27 +03:00
digital-garbageandClaude Opus 4.8 d4c1f7f72e Movie Editor: full in-UI editing of shortcuts and transitions
The Shortcuts/Transitions bins only had a crude prompt()-based Add and Delete, so
real editing required round-tripping through ComfyUI + import. Add inline edit forms
(backend CRUD already existed):
- Shortcuts: name, multiple triggers, multiple replacements (random pick), enabled.
- Transitions: name, trigger, placement (global/start/end/silent), visual_effect, enabled.
Each row gets an Edit (pencil) button; Add opens a blank form; rename works via
original_name. Rows now show placement and an (off) marker for disabled items.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 10:20:58 +03:00
digital-garbageandClaude Opus 4.8 99449e33ac Movie Editor: verbatim split via expand -> split -> compact-back
Previous splitter tried to detect transitions WITHOUT expansion, so prompts whose
transitions come from shortcuts (e.g. qcut -> '...cuts to the next scene') never
split — everything landed in one scene.

Now split_timeline_verbatim follows the correct order internally:
1. _expand_with_map() expands shortcuts exactly like apply_prompt_shortcuts while
   recording a position map (expanded offset -> original span).
2. detect transitions + placements in the EXPANDED text and split as Studio does
   (text before the first transition = anchor).
3. compact boundaries back onto the ORIGINAL via _project_offset(): a boundary inside
   a shortcut expansion moves the WHOLE original trigger token to one side per
   placement (start -> leads next scene; end/silent -> trails previous).

Result is lossless verbatim chunks. Verified: 'CHAR: a woman, man qcut hug cut hug
kiss' -> anchor 'CHAR: a woman, man', scene1 'qcut hug cut', scene2 'hug kiss'.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 10:17:52 +03:00
digital-garbageandClaude Opus 4.8 3eb2fe1fa0 Movie Editor: mirror output/input connections both ways; fix global-prompt Apply
- Models modal: an output->input edge can be authored from either side (a slot's
  output wire, or the destination's input source). These were separate stores that
  never synced, so wiring one side didn't show on the other. Now they mirror on
  write (and re-render), so choosing a node as an input source shows the connection
  in the source node's outputs, and a saved output wire shows the destination input
  as connected.
- Global prompt Apply was gated on 'dirty' (only after manual edits), so clicking it
  to split the auto-populated live prompt did nothing because the button was disabled.
  Apply is now enabled whenever there's prompt text to (re)split.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 10:10:49 +03:00
digital-garbageandClaude Opus 4.8 9e63470891 Movie Editor: fix Models wiring not saving until node re-expanded
persist() reassigned 'config' to the server's returned object, detaching every
wire/widget event handler that closed over the original — so an edit only saved
on the first interaction after each render, and you had to collapse/re-expand the
node (re-render) to add another output. Save the same config object in place.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 10:03:32 +03:00
digital-garbageandClaude Opus 4.8 b3daa8dab9 Movie Editor: verbatim global prompt as source of truth (lossless split)
The global prompt is now the verbatim source of truth. New conditioning helper
split_timeline_verbatim() splits it into anchor + scene chunks using shortcut-aware
transition boundaries but WITHOUT expanding shortcuts or dropping any word, so
anchor + scene texts concatenated reproduce exactly what the user typed. A 'start'
trigger leads the new scene; 'end'/'silent' trails the previous chunk.

- build_combined_prompt is now a pure join (anchor + scene texts, single spaces) —
  no injected scene markers. Generation sends this verbatim prompt to Studio, which
  expands shortcuts / splits by transitions / applies the anchor as it always does.
  So editing a scene rewrites only its chunk and the global prompt = concatenation
  (nothing un-typed ever reappears).
- bridge.parse_timeline_verbatim + parsed_verbatim on /parse and /preview.
- applyGlobalPrompt / syncFromPreview consume parsed_verbatim (authoritative).

Example: 'CHAR: a woman, man qcut hug cut hug kiss' -> anchor 'CHAR: a woman, man',
scene1 'qcut hug cut', scene2 'hug kiss'.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 09:50:37 +03:00
digital-garbageandClaude Opus 4.8 468a349204 Movie Editor: ephemeral renders + Export/Save dialogs; fix global-prompt splitting
Renders are now ephemeral — VHS writes to ComfyUI's temp dir (save_output=False)
and the final stitch is written to temp too; both clear on ComfyUI restart.
Persisting is the user's job:
- 'Export' toolbar button saves the selected clip's render via a Save dialog
  (showSaveFilePicker where available, else download). Rendered clips show a green
  dot; the button is disabled until the selected clip has a render.
- 'Render Final Video' stitches available runs to temp and opens a Save dialog.

Fix regression from the shortcut-verbatim change: scene/transition structure can
be produced by shortcut EXPANSION, so the global-prompt / sync now take structure
from whichever split yields more scenes (expanded wins when raw under-splits),
keeping verbatim text only when the raw split structures the prompt equally well.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 09:35:12 +03:00
digital-garbageandClaude Opus 4.8 0ce686c427 Movie Editor: per-project models config, carry default, global-prompt placement
- Models/nodes/links are now carried IN the project (Project.models), not a single
  global file. New projects seed from the global default; saving updates that
  default so the next new project inherits your latest loaders. Per-project routes
  GET/PUT /projects/{pid}/models; generate + image-targets use the project's config;
  editor reloads models on project switch. Global /api/models kept as the seed.
- New scenes default to 'carry' (continuous; scene 1 carrying just starts a fresh
  run). Dropping an image onto a scene still auto-switches it to the image anchor.
- Global prompt is the first entry in the inspector list now (was sticky/hovering).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 09:26:10 +03:00
digital-garbageandClaude Opus 4.8 e1e3261ca0 Movie Editor: keep shortcuts verbatim outside preview/generation
Global prompt and 'Sync from preview' were writing shortcut-EXPANDED scene text
into scenes (parse_timeline expands before splitting), so the verbatim combined
prompt then showed expanded shortcuts. Add bridge.parse_timeline_raw() (split
without expansion) exposed as parsed_raw on /parse and /preview; apply/sync now
take scene text from the raw split (shortcuts preserved) and use the expanded
split only to DETECT transitions (incl. shortcut->transition), mapping them to
the library by visual_effect. Generation and the split preview still expand.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 09:21:44 +03:00
digital-garbageandClaude Opus 4.8 1ffb7abe29 Movie Editor: Split/Remove buttons in the timeline toolbar
Dedicated, always-visible Split (⧅) and Remove (✕) buttons act on the selected
clip — replacing the cramped corner actions that the timecode overlapped. Mirror
the S / Delete shortcuts; disabled when no clip is selected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 09:13:58 +03:00
digital-garbageandClaude Opus 4.8 af8d84e29e Movie Editor: keyboard split/remove for the selected clip
S splits the selected clip at the playhead (midpoint if the playhead is outside
it); Delete/Backspace removes it. Ignored while typing in a field. Replaces the
hard-to-reach corner action buttons; toolbar shows a 'S split · remove' hint.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 09:12:15 +03:00
digital-garbageandClaude Opus 4.8 cd9f4dfb81 Movie Editor: run-based montage generation + final video stitch (video+audio)
Generate Whole Montage now splits active scenes into chain runs bounded by
anchored scenes: a run starts at an empty/image/generated_frame scene and a
'carry' scene appends to it (overlapping via carry_i2v_guides). One ComfyUI
chain-sampler request is fired per run, sequentially; each run's first scene
supplies its i2v anchor. No sampler changes needed.

New 'Render Final Video' button hard-cut concatenates the rendered runs in
timeline order (skipping ungenerated gaps) via ffmpeg, preserving the LTXAV
audio track, and plays the stitched result in the program monitor.

- server.py: generate accepts scene_ids (a run); _segment() clone; carry_i2v_guides
  forced on for multi-scene runs; POST /render ffmpeg concat (-c:a aac).
- store.js: _runs() segmentation, promise-based polling, generateMontage(), renderFinal().
- api.js: generate(scene_ids), renderFinal(); menubar: Render Final Video item.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 09:11:06 +03:00
digital-garbageandClaude Opus 4.8 ff2f3c65d8 Movie Editor: add 'carry i2v guide' scene source mode
A 4th scene source: the scene has no anchor of its own and continues from the
previous scene's i2v guide with overlap (chain-sampler carry behaviour). UI +
data model only; per-scene carry/reset in the sampler is the V2 work to follow.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 09:05:20 +03:00
digital-garbageandClaude Opus 4.8 b313bb69ea Movie Editor: per-scene length/fps modes, pinned global prompt, in-editor Project/Scene switch, single-input links
- Per-scene Frames/FPS gain a 3-way mode (project | timeline | custom): timeline
  follows the trim handle live, custom locks it. Default = timeline length / project fps.
- Global prompt pinned atop the inspector: live view of the combined prompt that
  updates as scenes change; edit + Apply reparses into anchor/scenes/transitions.
- Project/Scene switch is now a segmented control in the inspector (removed from the
  Generate menu).
- Models > Linked inputs now allows single-member links, so a lone node input (e.g.
  FPS) can be tied to a project value without needing a second member.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 08:56:53 +03:00