Commit Graph
789 Commits
Author SHA1 Message Date
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
digital-garbageandClaude Sonnet 4.6 3b02fccfa3 Movie Editor: 'generated frame' i2v anchor capture
- Player: window.Player.captureFrame() draws the current video frame onto a
  canvas and returns a PNG Blob. Transport bar shows '📌 Use as anchor' button
  + scene selector when the playhead is on a rendered segment; clicking it
  captures the frame, uploads to the media bin, and sets the selected scene's
  source to {type: 'generated_frame', media_ref, target:
  'port:FunPackStudio.source_image'} — the builder wires it as the i2v anchor.
  Scene selector defaults to the currently selected scene.
- Inspector: renderGeneratedFrameSource() shows the captured frame thumbnail
  (with a 'replace via player' hint) when media_ref is set, or instructions
  when no frame has been captured yet; includes the destination-input selector
  so the user can redirect the wire if needed.
- server.py: _prepare_media accepts source.type 'generated_frame' in addition
  to 'image' so the captured frame is copied to ComfyUI's input dir and wired.
- styles.css: pm-sep divider, pm-anchor-sel, pm-anchor-btn for transport bar.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 08:19:26 +03:00
digital-garbageandClaude Sonnet 4.6 47c26b2a14 Movie Editor: NLE program monitor with timeline scrubbing
- player.js complete rewrite: persistent <video> element (re-appended on
  re-renders, never destroyed — playback survives any editor state change);
  minibar shows rendered vs ungenerated segments; drag-to-scrub on minibar;
  transport bar (play/pause/stop + timecode); playback auto-jumps to next
  rendered segment or stops at first unrendered gap; window.Player mediates
  playhead between player and timeline
- timeline.js: ruler drag-to-scrub (replaces click-only); playhead reads from
  Player.getPlayhead(); Player.onPlayheadChanged updates only the needle +
  timecode element at video frame rate without triggering a full re-render;
  auto-scroll keeps playhead in view during playback; split-at-playhead reads
  from Player
- store.js: renderedSegments[] tracks which sceneIds map to which video file;
  populated when generation completes; cleared on project switch; generate()
  passes targetSceneIds to poll() so completed segments are recorded correctly
- styles.css: program zone is now a flex column (canvas + minibar + transport);
  pm-canvas fills remaining space with vignette; pm-minibar/pm-chip/pm-needle
  for the segment strip; pm-transport for controls
- server.py: effective_frames uses trimmed scene.frames when all active scenes
  agree, so timeline trim handle affects generation length (provided
  EmptyLTXVLatent is linked to Project Frames via Models → Linked inputs)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 08:07:39 +03:00
digital-garbageandClaude Sonnet 4.6 dc049ad333 Movie Editor: remove low-pass panel; elapsed timer; job-crash detection
sampler_panel.js: remove the Low pass section — Studio outputs high_pass_
sampler/sigmas (indices 4+5) to the chain sampler; the low-pass outputs (6+7)
are not wired in the movie editor graph. Renamed header from "High pass" to
"Sampler" since there's only one now.

store.js: show elapsed time in the generating readout so a slow run doesn't
look frozen ("Generating… 1m 23s" instead of a static "Generating… (running)").

store.js: detect job-disappeared crash — if ComfyUI returns state="pending"
three polls in a row after the job was running (job left the queue but never
appeared in history), stop polling and show "Job disappeared from ComfyUI queue
— it may have crashed. Check the ComfyUI terminal." Previously this left the
UI in "Generating… (running)" indefinitely.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 00:56:30 +03:00
digital-garbageandClaude Sonnet 4.6 fbf7ac5ac0 Movie Editor: force split_by_transitions; fix COMBO; remove auto-wire; surface errors
builder.py: force split_by_transitions=True on FunPackStudio — this was the
root cause of single-scene generation. Studio defaults to False (single-scene
mode); without this flag it ignores the multi-scene prompt structure entirely
and outputs only one conditioning regardless of how many scenes were split.
The flag is now forced and blocked from being overridden via studio_inputs.

nodes.py: add _WIDGET_TYPES = WIDGET_PRIMITIVES | {"COMBO"} and use it in
connection_inputs() and _all_input_types(). "COMBO" (V1 new-style dropdown)
was previously passing the WIDGET_PRIMITIVES exclusion check and appearing as
a graph-connection socket in the UI.

models.js: revert auto-wire-output-on-input-source logic (previous commit).
The heuristic was too aggressive and would pick wrong destinations when
multiple IMAGE ports exist.

server.py + store.js: surface ComfyUI execution errors. Previously a node
failure inside ComfyUI returned state="completed" with no media and the UI
showed "Completed (no media found)." — unhelpful. The status endpoint now
reads history[id].status.messages for execution_error entries and returns
state="error" + error string. The frontend poll shows the node type and
exception message so the user knows what actually failed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 00:48:55 +03:00
digital-garbageandClaude Sonnet 4.6 3d0b86e3be Movie Editor: fix COMBO inputs mistaken as connections; auto-wire output on input source set
nodes.py: "COMBO" (V1/new-style dropdown widget) is a string so it passed
the WIDGET_PRIMITIVES exclusion check and was incorrectly returned as a
graph-connection socket in connection_inputs() and _all_input_types(). Added
_WIDGET_TYPES = WIDGET_PRIMITIVES | {"COMBO"} and use it in both functions.
Old-style list combos (spec[0] is a list) were already excluded correctly.

models.js: when the user assigns an input source for a connection input of
type T, auto-wire the first unwired output of the same type T to the sole
pipeline destination of that type. Applies only when: (1) the selected source
is non-empty, (2) the slot has exactly one output of that type, (3) that
output has no wire set yet, and (4) there is exactly one destination available.
This covers the common image-processor case: set image input → IMAGE output
auto-wired to studio.source_image.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 00:39:25 +03:00
digital-garbageandClaude Sonnet 4.6 30aec950cd Movie Editor inspector: expose conditioning/sampler selectors + settings inline
The conditioning and sampler slot pickers were in the Generate menu (a
window.prompt popup) with no visual path to the settings panels in the
inspector. Users found the menu selectors but never saw the Studio sampler
algorithm controls or the Chain Sampler knobs.

Fix: add conditioning and sampler section headers with inline <select> slot
pickers directly in the project inspector, immediately above their respective
settings panels. Changing the dropdown instantly shows or hides the panel for
that choice. The menubar items remain as shortcuts.

Also wrap SamplerPanel.render() in try/catch so a JS failure shows a visible
error message instead of silently aborting the rest of the inspector render.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 00:35:43 +03:00
digital-garbageandClaude Sonnet 4.6 3c8dda0f5c Movie Editor: fix multi-scene generation — always emit separator before each scene
build_combined_prompt had a bug: when no anchor text was set, need_sep was
False for scene 1 so its text landed in Studio's segments[0] (anchor slot)
and never generated. An N-scene project with no anchor only produced N-1 scenes.

Fix: always emit a separator before every scene. Studio splits on separators,
so segments[0] is always the anchor (empty if no anchor text is set) and
segments[1..N] are the generated scenes. Fallback label is now "scene {i+1}"
(correctly numbered) instead of the previous "scene {label_n+1}" off-by-one.

Also: pass max_scenes = active scene count from the generate route into the
builder so the chain sampler always knows the exact number of scenes to produce.

Note on per-scene images: only the source image on scene 1 (project anchor
image) is wired to studio.source_image. Scene 2+ anchoring works via the
carry_i2v_guides flag on the chain sampler, which carries each scene's last
frame as the i2v source for the next scene. Per-scene i2v requires carry_i2v_guides
to be enabled in the sampler inspector — it is off by default.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 00:30:59 +03:00
digital-garbageandClaude Sonnet 4.6 de52c789fc Movie Editor: normalize COMFY_MATCHTYPE_* → IMAGE; respect V3 optional flag
COMFY_MATCHTYPE_V3 is ComfyUI's dynamic IMAGE-compatible match type used by
nodes like ImageTransformKJ. All four type-extraction paths (_outputs,
_all_input_types, connection_inputs, node_outputs) now call _normalize_type()
so the UI sees "IMAGE" and role-matching, source/dest pickers, and
requirements checks all work correctly.

connection_inputs also checks spec[1].get("optional") so V3 nodes that
declare an input as required in the required group but flag it optional
(e.g. bboxes on ImageTransformKJ) are reported with required=False.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 00:22:26 +03:00
digital-garbageandClaude Sonnet 4.6 f9a96a9827 Movie Editor: pipeline requirements checklist + friendly error messages
Pipeline requirements panel (top of Models modal):
- Shows every required/optional pipeline input (MODEL, CLIP, Video VAE, Audio VAE,
  Audio latent, Source image, Initial latent) with satisfaction status.
- Red row + hint + 'Add' button for unsatisfied required inputs — clicking Add
  pre-selects the right role in the composer so user knows exactly what to add.
- Green row when satisfied; optional inputs shown below in a grayed-out group.
- Overall 'Pipeline ready' status after all required inputs are met.

Backend:
- nodes.py: PIPELINE_REQUIREMENTS constant with human-readable labels and hints.
  Added 'audio_encoder' role for Audio Encoder nodes (outputs LATENT for audio path).
- server.py: pipeline-ports response now includes 'requirements' array.

Friendly generation errors (store.js):
- _friendlyGenError() maps technical builder messages (audiodec.audio_vae no source,
  audio_latent no source, etc.) to plain-English explanations pointing to Models.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 00:17:39 +03:00
digital-garbageandClaude Sonnet 4.6 7933615b81 Movie Editor: fix models.js syntax error — broken inner double-quotes
Curly-quote replacement turned "Link inputs" inside a double-quoted string
into bare straight quotes, breaking the JS parser. Replaced with single quotes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 00:05:37 +03:00
digital-garbageandClaude Sonnet 4.6 8070585fa4 Movie Editor: input sources, editable role labels, better picker labels
Input sources (nodes modal, expanded slot):
- New "Input sources" section per slot — choose where each connection input
  comes from: (auto-wire), Timeline (scene image, IMAGE only), core primitives
  (Project frames/fps), or another slot's named output.
- builder.py step 3b: applies input_sources before auto-wire; "timeline" creates
  media_load node and wires it; "out:<slotId>:<outName>" and "core:<id>:<idx>"
  resolve to specific graph edges.
- nodes.py: core_producers() lists the fixed core primitives as source options.
- server.py: pipeline-ports response includes core_producers array.

Role label editing:
- slot.role_label — user-editable name shown in the slot header role position.
- The rename button (✎) now edits role_label (applies to all slots, not just custom).
- Blank resets to the automatic role name from the roles registry.

Better picker labels:
- slotFullLabel(slot) = "RoleLabel · NodeName" — used in destinations() and
  sources() so every option clearly identifies which slot it belongs to.
- roleLabel handles null/undefined role keys gracefully (shows "?").

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 00:03:46 +03:00
digital-garbageandClaude Sonnet 4.6 1d50e44edf Movie Editor: multi-wire support for slot outputs
- builder.py: wires[outName] now accepts a list of targets (string = legacy single,
  list = multi). Each target in the list gets its own graph edge from the same output.
- models.js: destSelect replaced with destMulti — shows current targets as a list of
  selects each with a remove button, plus an "+ Add" button to wire the same output
  to additional inputs. Old string-format wires normalized to array on first render.
  Health check updated to validate all targets in the array.
- styles.css: wire-multi / wire-multi-row / wire-rm / wire-add classes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 23:58:00 +03:00
digital-garbageandClaude Sonnet 4.6 87906b98e3 Movie Editor: port Studio sampler panel into project inspector
- sampler_panel.js: full port of funpack_studio.js renderSampler() —
  High/Low pass sections with Hybrid Euler 2S / Distilled Flow / Normalizing /
  KSampler modes, velocity bias, rescue, motion pulses, variability macro.
  Writes into project.studio_inputs.studio_settings (JSON) so builder sends it
  as the studio_settings widget value to FunPackStudio.
- inspector.js: renderStudioSettings now renders the full panel; bool knobs
  use setSamplerInputNow for immediate re-render on toggle.
- store.js: setSamplerInputNow / setStudioInputNow for instant notify on
  structural changes (selects, checkboxes).
- styles.css: sp-macro / sp-sub styles for the sampler panel sections.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 23:51:57 +03:00
digital-garbageandClaude Sonnet 4.6 d336f6a008 Movie Editor: expose Studio/Sampler settings in project inspector
- Project now stores negative_prompt, sampler_inputs, studio_inputs
- Builder applies sampler_inputs/studio_inputs as widget overrides on the
  ChainSampler and Studio nodes (only when funpack slot is selected)
- Inspector renderProject shows: negative prompt textarea + full sampler knobs
  (cfg, frame_overlap, carry_i2v_guides, mid_scene_guide + strength,
  embed_guidance + strength, decode_noise_scale, decode_timestep)
- Dependent knobs only appear when their parent bool is on
- Store: setSamplerInput / setStudioInput write into sampler_inputs/studio_inputs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 23:46:54 +03:00
digital-garbageandClaude Sonnet 4.6 9c9e3a02cc Movie Editor: fix U+201C/201D curly-quote syntax error in mediabrowser.js
54 typographic left/right double-quote chars snuck into JS string literals,
causing an immediate SyntaxError that broke the whole app.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 23:43:12 +03:00
digital-garbageandClaude Sonnet 4.6 e6410986fd Movie Editor: anchor bug, error messages, sync-preview, save/load, cond/sampler roles
- Bug: anchor prompt editing (selectedSceneId=null) no longer resets to scene 1 after
  autosave — commit() now only resets selection when a non-null id disappears.
- Bug: generate errors now return {detail: '...'} JSON (400/502) so the frontend shows
  the actual reason (missing node, blocking port, etc.) instead of 'Bad Request'.
- Transition autodetect: Split preview now shows the detected visual_effect badge on each
  seam; a '↺ Sync scenes from preview' button distributes the parsed anchor/scenes/
  transitions back into the project (with confirm dialog).
- Project save/load: File menu gains 'Save Project File…' (downloads .funpack_project.json)
  and 'Load Project File…' (file picker → POST /api/projects/import → new project, safe
  id, auto-opens). Useful for backup/restore when the ComfyUI instance is lost.
- Conditioning/Sampler roles: Project model gains conditioning_slot + sampler_slot
  ('funpack' by default). Generate menu shows current selection and opens a numeric
  prompt picker to switch to any configured slot node. Stored in project JSON; full
  builder wiring is a future phase.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 23:35:05 +03:00
digital-garbageandClaude Sonnet 4.6 c237558571 Movie Editor: bugfixes — import/export, V1 combo inputs, port display, resize selection
- Shortcuts + Transitions bins: Add ↓ Export (download JSON) and ↑ Import (file picker
  → POST to new /api/library/{shortcuts,transitions}/{export,import} routes). bridge.py
  gains import_shortcuts / import_transitions / export_* calling templates.py directly.
- nodes.py widget_inputs: handle V1/io.ComfyNode combo encoding (type "COMBO" with
  options in dict) so LTX2LoraLoaderAdvanced and similar nodes expose all their widget
  inputs. Also skip forceInput=True fields (socket-only, never user widgets).
- menubar.js: show window.location.host instead of internal comfy_url in the FunPack
  menu — stops showing the loopback 8188 port vs the actual browser-facing port.
- store.js resizeScene: switch to scheduleSaveSilent so dragging a clip edge doesn't
  trigger a notify/re-render mid-drag that resets the timeline selection.
- 26 tests pass (+1 test for V1 combo + forceInput coverage).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 23:20:09 +03:00
digital-garbageandClaude Opus 4.8 71bbe732cd Movie Editor: media→node target, editor-driven links, project width/height
Media wiring (chosen destination): a scene's image Source now lets you pick the
media asset AND which node IMAGE input it feeds (/api/image-targets lists core
IMAGE ports + configured nodes' IMAGE inputs). At generate the editor copies the
asset into ComfyUI's input folder (ephemeral) and the builder injects a LoadImage
wired to that input. Clips show the media as a thumbnail.

Editor-driven links: a link can be 'Driven by' a project setting (FPS / Frames /
Width / Height) instead of a manual value; builder fills every member input from
params at generate, so node inputs stay consistent with the timeline. Exposed
editor-driven links show read-only in the inspector.

Project width/height added (Scene gains width/height/source.target too).
Bonus from the backlog: split-at-playhead now respects the playhead position.

+3 builder tests (editor link, media inject, optional ports don't block). 25 pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 23:08:31 +03:00
digital-garbageandClaude Opus 4.8 685ab91f05 Movie Editor: don't block generation on optional/auto-resolvable inputs
The builder treated every open port as mandatory, so a valid text-to-video
montage (no image source) was rejected with 'Incomplete config' because
studio.source_image / studio.latent (both OPTIONAL on FunPackStudio) had no
producer. Now open ports carry a required flag and only required gaps block;
ambiguous REQUIRED inputs (e.g. two VAEs into one) also block with a 'wire it
explicitly' message. Generate returns the full blocking list as the reason.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 21:06:21 +03:00
digital-garbageandClaude Opus 4.8 1bf2a6eab1 Movie Editor: functional media bin + shortcuts/transitions library; calmer autosave
Left panel is now tabbed bins (Media / Shortcuts / Transitions):
- Media: upload via click or drop, thumbnail grid, delete; drag an asset onto a
  timeline clip (or click with a scene selected) to set its image source.
  Backend media store (media.py: upload/list/serve/delete under MEDIA_DIR).
- Shortcuts: list/search FunPack shortcuts, add, delete, click 'insert' to append
  a trigger to the selected scene's prompt.
- Transitions: list/search, add, delete, 'apply' to the selected scene's seam.
  Library CRUD runs in-process via bridge (templates.py functions); new routes
  under /api/library/* and /api/media/*.

Autosave fix: free-text/number fields use quiet patches (state update + debounced
save, no per-keystroke re-render) so typing isn't interrupted; debounce 550→900/
1100ms; inspector preserves focus+caret across the eventual rebuild.

+test_media.py; 22 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 21:01:19 +03:00
digital-garbageandClaude Opus 4.8 cffaeeec13 Movie Editor: linked inputs, node rename, links list
- Link inputs: enter link mode, click + on 2+ node inputs across nodes,
  Save link (named) → one shared control drives them all (e.g. width/height).
  Linked inputs render disabled with a 🔗 tag; edits route through the link.
- Links section in the Models modal lists each link: rename, shared-value
  control, member chips (unlink), expose-to-main-editor eye, unlink-all.
- Exposed links appear in the inspector's Exposed controls (Store.setModelLink
  writes through to all members).
- Rename any configured node (slot.label) via a ✎ in its header.
- Builder applies links: each member input set to the link's shared value.

Scene/models config gains links[]; +builder test. 21 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 20:52:20 +03:00
digital-garbageandClaude Opus 4.8 12c9b607a3 Movie Editor: real NLE timeline (ruler, proportional clips, trim, crossfade)
Rebuilt the timeline as a time-based editor:
- HH:MM:SS:FF-aware ruler with zoom-adaptive tick labels; click to move playhead
- clips laid out on a time axis (width = duration × zoom), absolutely positioned
- drag the right edge to trim → recomputes frame count from duration × fps
  (snapped to LTX-valid 8k+1); live timecode/frame tooltip
- split clip, move, delete; per-scene length/FPS + duration in the inspector
- per-seam crossfade: drag to set transition_frames (new field; post-decode pixel
  op, never re-encodes) + transition-type picker
- zoom −/+/fit, playhead, total-duration readout

Scene gains transition_frames; Store gains resizeScene/splitScene/snapFrames.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 20:45:13 +03:00
digital-garbageandClaude Opus 4.8 cce91c5a45 Movie Editor: expose-to-main-editor eye toggle + collapsible node cards
- each configured node input gets an eye toggle ('Show in main editor
  window'); exposed inputs render as live controls in the inspector's
  'Exposed controls' panel and edit/persist the node config (Store.models is
  now shared between the Models modal and the main editor via a
  funpack-models-changed event)
- node slot cards are collapsed by default and after adding (like Studio
  shortcuts); click the header to expand; header shows exposed count + status

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 20:36:53 +03:00
digital-garbageandClaude Opus 4.8 8b278c9515 Movie Editor: Restart ComfyUI button
FunPack menu -> 'Restart ComfyUI' relaunches the server process in place
(POST /funpack/movie/api/restart -> os.execv, mirroring ComfyUI-Manager's
reboot incl. the comfy-cli session case; no Manager dependency). Restart is
deferred 0.7s so the 200 flushes first. UI shows a blocking spinner overlay,
polls /health, and auto-reloads when ComfyUI is back. Confirms first.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 20:13:26 +03:00
digital-garbageandClaude Opus 4.8 7f479a6a2d Movie Editor: make node listing crash-proof against any registry node
candidates()/all_nodes() now process each node defensively (like ComfyUI's
own /object_info) so one node with an unexpected schema (V3-style dict
outputs, non-list input, etc.) is skipped instead of 500ing the whole list.
node_outputs() hardened to tolerate non-list output/output_name. Routes log a
traceback and return the real error message instead of a blank 500.

Root cause: until object_info was built in-process, the candidate filter had
never actually run against the full live registry. Regression test added.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 20:09:08 +03:00
digital-garbageandClaude Opus 4.8 857c501c5b Movie Editor: surface real node-list error; fix stale FunPack menu health fields
- models composer now shows the actual error text (and logs it) instead of a
  generic 'ComfyUI offline' when the node list fails to load
- FunPack menu reads the current health fields (reference_loaded /
  configured_slots) instead of the removed template_exists

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 20:04:17 +03:00
digital-garbageandClaude Opus 4.8 6931966576 Stop tracking build artifacts; expand .gitignore
The previous commit accidentally swept in untracked junk (__pycache__,
.DS_Store, .claude/, refinements/*.pt runtime artifacts, research PDF) via
git add -A. Untrack them and ignore going forward. No source changes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 19:59:51 +03:00
digital-garbageandClaude Opus 4.8 120b2b7188 Movie Editor: code graph builder + in-process object_info
Generate now builds the fixed FunPack path in code (builder.py) instead of
loading a runtime template:
- emits the fixed core (Studio -> LTXVConditioning -> Chain Sampler ->
  Separate AV -> Audio decode -> Normalize -> VHS Combine, plus Concat AV,
  SaveRefinement, KeyLoader, fps/frames primitives) with internal links and
  widget values seeded from the reference workflow
- splices in the user's configured loader/image-proc/empty-latent slots,
  resolves explicit 'Wire to' links, then auto-wires remaining typed inputs
  from the unique producer of that type; ambiguous/unsatisfied are reported
- forces VHS save_output so results are retrievable
- generate route uses builder + blocks on unsatisfied config; drops the
  template injector (workflow.py removed)

Fix 'ComfyUI offline' when adding loader nodes: object_info is now built
in-process from NODE_CLASS_MAPPINGS (no loopback HTTP, no port guessing;
tuples normalized via JSON), HTTP kept as fallback. Refresh clears
folder_paths.filename_list_cache like ComfyUI's R key.

Tests: +test_builder.py (4), removed obsolete workflow-injection tests; 19 pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 19:59:01 +03:00