- 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>
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>
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>
- 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>
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>
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>
Models modal now filters the 'Any node…' list with a live search box
(capped at 300 results) instead of a giant select, and validates the
slot config: per-slot error/warning badges + issue list (missing
required fields, no-option combos, unwired/dangling outputs) plus a
summary banner flagging missing essential roles (Unet/CLIP/Video VAE).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lets the Models UI express the full graph wiring (per user: 'just allow this
wiring, nothing more'):
- 'Any node…' option in the composer: searchable picker over every registered
ComfyUI node (all-nodes), not just the 8 typed roles — so nodes like LoadImage,
VAEEncode, ImageTransformKJ, LTXVImgToVideo* can be added and wired
- backend: all_nodes(), describe_node(cls); pipeline_ports(object_info) now also
exposes LTXV fixed-core external inputs (LTXVConcatAVLatent, LTXVAudioVAEDecode,
LTXVConditioning, Separate, VideoCombine, ...) so loader/image outputs can wire
into them, not just Studio/Chain Sampler
- frontend: unified node-spec-by-class cache + specFor(); routes all-nodes/node/{cls}
- tests: +2 = 17 passing
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- _serve_static: Cache-Control no-store + explicit text/javascript (fixes stale
files / wrong-MIME blanking the app across fast iteration)
- index.html: inline window.onerror/unhandledrejection overlay so any script
failure shows on screen instead of a blank editor (self-diagnosing)
- save user's real montage workflow as backend/reference/montage.workflow.json
to encode the fixed graph builder (loaders + image-proc groups = the pluggable
slots; rest is the fixed path)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Each configured node now declares where its outputs connect, so users rebuild
the node graph as a tidy list instead of canvas spaghetti:
- backend: candidates now expose outputs + connection_inputs; pipeline_ports()
derives Studio/Chain Sampler connection points live from their real INPUT_TYPES
(authoritative); /api/pipeline-ports route
- frontend: per-output 'Wire to' select in each slot card, offering type-matched
destinations (pipeline ports OR another configured node's input). Enables chains
like CLIP Vision -> CLIPVisionEncode -> Studio, or a Latent Combine feeding Studio
- tests: +2 (outputs/connection inputs, port derivation) = 15 passing
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The fixed pipeline only varies in its loaders + a few pipeline nodes (they depend
on installed models). New 'Models' menu configures them via ComfyUI /object_info,
no hardcoded model family:
- backend nodes.py: role registry (Unet, LoRA, Video/Audio VAE, CLIP, CLIP Vision,
Input Image Processing, Empty Latent); filters object_info candidates by output
type (source roles exclude patchers); extracts user widgets (combos w/ installed
files, int/float/string/bool), skips graph-connection inputs; global config store
- bridge.object_info() (cached; refresh = ComfyUI 'R'); server routes for
node-roles / node-candidates / models get|put / refresh
- frontend models.js: Models menu (Settings + Refresh model list) + modal
'Add Model/Node' composer (type -> node -> exposed inputs) + configured slot list
- tests: +5 (filtering, widget extraction, store) = 13 passing
Note: drops the runtime-template concept per user — the editor will own the fixed
graph and inject these loaders. Graph builder is the next step (needs the montage
workflow JSON to encode exactly).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Full frontend redesign into a real movie-editor layout:
- menu bar (File/Edit/View/Generate/FunPack) with dropdowns + status chips
- left Media Browser (projects + media bin drag-drop placeholder)
- right Preview/program monitor + context Inspector (clip props or project
settings + live split preview)
- bottom Timeline track: clips with transition seams, click-to-select drives
the inspector, reorder/exclude/delete
- draggable panel splitters; cinematic dark theme (warm near-black, amber clip
accent, teal selection, film grain), Bricolage Grotesque + IBM Plex Sans/Mono
Architecture: central pub/sub store (store.js) + per-zone view modules; all
backend wiring unchanged (same /funpack/movie/api). Editing moved from cards
into the inspector. Render/Export and media drag-drop are stubbed for later.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Per user: serve from ComfyUI's own aiohttp PromptServer at /funpack/movie/
instead of a separate FastAPI/uvicorn process. Removes fastapi/uvicorn/httpx
entirely (all on ComfyUI's bundled aiohttp); backend/requirements.txt deleted,
root requirements.txt needs nothing new.
- server.py: aiohttp route registration on PromptServer (projects/preview/
generate/status/result/library + static UI), guarded for standalone tests;
wired into root __init__.py like batch_training
- bridge.py: parse_timeline/transitions IN-PROCESS (direct FunPack imports);
/prompt /history /view over loopback HTTP
- config.comfy_base_url(): detect the REAL port from PromptServer.instance /
comfy.cli_args so non-default --port works; browser uses same-origin relative
URLs (api.js derives base from window.location) so the port is automatic
- delete app.py, routes/, comfy_client.py, backend/requirements.txt
- README updated; tests still 8/8
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Editable scene timeline + transition library feeding the existing Studio ->
Chain Sampler chain. Light FastAPI sidecar (no torch/comfy) that drives a
running ComfyUI over its API and reuses /funpack/* routes for parsing.
- backend: project store (JSON), timeline model + Studio-format prompt
assembly, ComfyUI client, graph-agnostic workflow injector, routes
(projects/timeline preview/generate/library), FastAPI app
- frontend: vanilla-JS editable timeline (scene cards, transitions, exclude,
generate-only, source type), live split preview, result player
- forward-compat data model: scene source (empty/image/generated_frame),
per-scene excluded flag, intro_transition for the anchor boundary
- tests: 8 passing (prompt assembly, project CRUD, workflow injection)
V1 drives the uniform chain in one pass; per-scene length/FPS, Empty/Image
latent building, media browser, frame->scene anchors, selective regen and
cuts/trims are scaffolded (UI/model) but deferred to later phases.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
DynamicConditioning is an unpacked-video technique; on LTXAV (packed AV latent, 3D
mask) it can only no-op (comfy's process_timestep patchifies expecting 5D). Rather
than keep dead knobs in the Chain Sampler UI, remove i2v_anchor_power /
i2v_anchor_first_frame_only, the install block, and _install_i2v_anchor entirely.
The packed-safe path for cross-cut appearance carry (strengthen the Chain Sampler's
own carry/guide masks pre-pack) remains available as a future native feature.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The i2v anchor (DynamicConditioning port) crashed on LTXAV with 'not enough values
to unpack (expected 5, got 3)': comfy's process_timestep patchifies the video denoise
mask expecting unpacked 5D [B,C,F,H,W], but LTXAV packs the AV latent so its mask is
3D [B,C,N]. The else-branch (first_frame_only=False) modified + propagated the 3D mask
unguarded -> patchify blew up.
Hard-guard the whole denoise_mask_fn to genuine 5D masks; packed/non-5D -> clean no-op
(one-time log). The technique is fundamentally unpacked-video-only, so on LTXAV it does
nothing -- documented in the tooltip. Native packed-safe carry-strength is the follow-up.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two optional Chain Sampler inputs (i2v_anchor_power, i2v_anchor_first_frame_only),
default power=1.0 = off. When >1.0, installs a denoise-mask model patch via the stock
comfy API (set_model_denoise_mask_function) that raises the denoise mask to power**step,
progressively holding the i2v conditioning frame harder as denoising proceeds -> anti-drift
from the input image. No modified model, no extra forward pass, ~zero overhead.
Patched before the batch/main split so both paths inherit it. Fully defensive: missing
mask / unexpected (e.g. packed) shape / any error falls through to the unmodified mask.
EXPERIMENTAL on packed AV latents - validate in ComfyUI. pos_embedding_exp_values.py was
also assessed and is a dead end (internal RoPE precision-matching constant, not a technique).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Laplacian pyramid blend from the LTXV pack is a SPATIAL pixel-space tool and
doesn't transfer to our temporal latent crossfade (uniform full-frame alpha over a
2-4 latent-frame overlap -> multi-band adds nothing). The actual seam problem is that
a linear lerp of two latents superimposes them and lets magnitude collapse at ~0.5
(ghosting + washout). Fix in-domain instead:
- _slerp_block: spherical interp of the overlap block per (batch, frame), direction
via slerp + magnitude interpolated linearly, so the crossfade keeps its energy.
Uses torch.linalg.vector_norm (Tensor.norm treats a 3-tuple dim as a matrix norm).
- _blend_tensors: smoothstep alpha (less dwell at the 50/50 ghost point) + slerp for
video; audio/any further stream stays on the untouched linear path (audio-safety).
- Verified: exact endpoints, magnitude preserved across the seam vs linear washout.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reverts the separate FunPackVAEDecoderNoise node (boundary-law violation: if the
Chain Sampler can own it, it should). Decode-time noise is now two optional inputs
on the Scene Chain Sampler (decode_noise_scale / decode_timestep), applied to a
shallow VAE copy via _vae_with_decode_noise before any decode so both the main and
batch-training IMAGES paths benefit. Never mutates the shared input VAE.
decode_noise_scale defaults to 0 (off) -> no behavior change unless enabled.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Phase 1 of the LTXVideo-pack technique pull. Standalone VAE->VAE passthrough that
stamps decode_timestep / decode_noise_scale / seed onto the LTX VAE so its internal
decoder restores fine detail/grain. ~zero cost, scale=0 disables. Place before any
VAE decode (Scene Chain Sampler, VAE Decode).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ports LTXVNormalizingSampler's between-step scalar normalization onto the FunPack
Normalizing sampler. Two new STRING inputs on FunPackNormalizingSampler:
video_normalization_factors / audio_normalization_factors (comma-separated per-step
scalars; short lists repeat last value; both default '1' = off/no-op).
Applied to the running latent at the end of each euler step via _apply_av_norm_factors,
using the existing _packed_video_mask to scale the video and audio streams independently.
This is the ONLY FunPack lever that touches audio, and it does so audio-safely by latent
magnitude only (never attention/hidden states) - the same mechanism the reference node
uses. Conservative + opt-in: ships off, audio untouched unless the user authors a schedule
(reference default was '1,1,0.25,1,1,0.25,1,1'). The adaptive normalize_strength remains
the smarter video-side lever; these are a manual per-step gain schedule.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds temporal_style='auto': Studio classifies each scene's prompt for motion
energy and bakes a continuous frame_rate multiplier into that scene's
conditioning metadata; the Scene Chain Sampler applies it per scene via a
layered model_function_wrapper (composes with embed guidance, restored in
install order). Concrete styles keep the global build_enhancements path
unchanged.
- ltx_enhancements: TEMPORAL_STYLES gains 'auto'; single-source TEMPORAL_STYLE_MULT
table; classify_temporal_intent() keyword director (energy->punchier mult<1,
stillness->hold mult>1, loop flag); factored make_temporal_wrapper() shared by
global + per-scene paths; build_enhancements skips the global wrapper for auto.
- conditioning: _v2_apply_auto_temporal() bakes funpack_temporal_mult/label/loop
into each entry inside the single finalize hook; both refine_v2 returns pass
temporal_style + the run prompt as per-scene fallback text. 'auto' added to V2
node dropdown.
- samplers: _scene_temporal_mult() reader + per-scene temporal wrapper around
_sample_chunk in the scene loop.
- web: 'auto' in the Studio dropdown + hint text.
Heuristic is the baseline director, structured so a reward-driven override can
replace the multiplier per intent-family later. loop's RoPE coordinate trick is
still unimplemented (inert flag only); auto detects loop intent but does not yet
honor it.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
clear_refinement_data() early-returned on an empty refinement_key, but a
keyless run stores its blessed/attn maps, creativity latent and velocity-bias
trajectories under the 'default' bucket. So a keyless Session Reset no-opped
and those disk-persisted stores survived restart too -- the first fresh run
felt cleaner than every later run. Normalize empty key to 'default' (matching
the write side) so reset actually wipes that bucket.
Also wire the keyless Absolute taste store (FUNPACK_ABSOLUTE_KEY) into reset:
it learns from every rated run regardless of steer_mode but had no clear path,
so it would survive reset + restart forever. Delete its state json + value fn
on reset_session.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1) Widget order: moved the refinement_key_input forceInput SOCKET to the
end of optional (after decode_tile_size + embed_guidance_source). A
forceInput placed between widgets desynced ComfyUI's widgets_values
mapping on reload -> the combo's "relative" landed on the decode_tile_size
INT (NaN field).
2) RecursionError: _run_batch_training's no-key fallback called self.sample()
with the variant markers still in positive -> sample() re-detected the
batch -> re-entered _run_batch_training -> infinite loop (hit when
Interactive Guessing/batch is armed without refinement_key_input wired).
Now runs keyless as generate-only: loops every variant, concatenates to
the IMAGES output, skips temp-save/manifest/rating. (Per-variant sub-calls
are single-variant -> _split_batch_variants returns None -> no recursion.)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add guess_freeze_seed (default True) threaded refine_v2 -> _v2_pack_batch
-> _v2_pack_guess_ladder and the Studio refine_v2 call. Frozen = every rung
shares one seed (only conditioning strength varies; cleanest for learning).
Off = distinct seed per rung (varied compositions too). New "Freeze seed"
toggle in the Interactive Guessing config; persisted on Arm.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
UI: Batch Training tab gains Mode (Regular / Interactive Guessing),
Direction, Range, and a Learning toggle; Arm sets refiner.guess_* +
batch_learning; auto-disarm clears guess_mode; rating list shows each
rung's [x factor]; Submit passes the learn flag.
Learning (batch_training.py): submit honors learn=false (pure generation,
no training). Guess batches detected via guess_factor -> _learn_guess_ceiling
finds the furthest-pushed acceptable rung before quality broke and stores a
per-key safe ceiling (absolute spread + factor) via _store_guess_ceiling.
Dual auto-cap (refine_v2, normal runs only): soft pre-limit on
absolute_strength + hard clamp of the output conditioning's video-channel
spread to the learned-safe value in _v2_finalize_conditioning. Skipped
during the guessing ladder itself. Helpers conditioning_spread /
scale_conditioning_spread.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New variant producer for Batch Training that, instead of seed/shortcut
variation, scales the conditioning's spread (sigma) on VIDEO channels by a
linear ramp across N rungs, freezing everything else including the noise
seed so the only variable is conditioning strength. Up amplifies toward
overbake, down dampens. Each rung records funpack_guess_factor (in cond
meta + batch manifest) so the ladder is interpretable and Phase-3 learning
can read each rung. Audio channels untouched (scale_conditioning_spread
reuses the LTXAV channel split). Wired refine_v2 -> _v2_pack_batch
(guess_mode branch -> _v2_pack_guess_ladder) and the Studio refine_v2 call
(guess_mode/direction/range from refiner settings).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Previously the batch path returned only the last variant's frames on the
IMAGES slot. Collect each variant's decoded frames (CPU) and concatenate
them so the whole batch comes out IMAGES back-to-back — enabling the
"just make N slight variations, don't rate them" use case. Falls back to
the last variant if frame shapes are incompatible. (Phase 1 of Interactive
Guessing.)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reuse _normalize_video_denoised in _sample_const_rf_full (Hybrid CONST/RF
path) and sample_funpack_distilled_flow: new normalize_strength /
normalize_start_sigma (default 0 = off). Applied to the denoised after
rescue/quality-sharpness, video-only, so audio is never touched and the
samplers keep AB2/Heun/velocity/rescue. Wired node INPUT_TYPES (appended)
-> get_sampler -> Studio _build_one_sampler + JS panels for both.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New SAMPLER for distilled LTXAV at CFG=1: deterministic 1st-order euler
base (clean ddim look + clean audio) plus per-step video-only latent
normalization to counter overbaking / oversaturation / colour drift at
~zero overhead. Tracks the video latent's robust spread, anchors a
reference once x0 is meaningful (normalize_start_sigma), and compresses
inflated later steps (normalize_strength). Benefit-only, no-op when
healthy, audio never touched (whole-latent for single-stream LTXV).
Velocity bias + rescue included, video-only.
Node FunPackNormalizingSampler + Studio sampler option ("Normalizing")
wired through _build_one_sampler and the JS panel. Registered in __init__.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Instead of full AB2 on every step, optionally ramp the AB2 contribution
linearly 0->1 across the schedule: denoised_eff = lerp(raw, ab2, i/(N-1)).
Early/high-sigma steps stay near 1st-order euler (less overshoot); late
steps get full AB2. Reuses the computed AB2 estimate -> no extra model
evals. Aimed at low-step distilled quality. No-op at order=1; audio still
rides plain euler. Wired node -> get_sampler -> Studio panel (+ JS toggle).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The FunPack Hybrid Euler 2S and Distilled Flow samplers applied AB2 denoised
extrapolation and the Heun corrector to the whole packed LTXAV latent, audio
slice included -> degraded audio. (Stock euler/ddim are clean because they're
1st-order; ComfyUI "ddim" == euler.) Confine both to the video stream via
_video_only so audio always rides plain 1st-order euler on the raw model
denoised, regardless of order/correction settings. Distilled Flow s_noise
diversity injection is now video-only too.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Absolute/Relative steer mode (Refiner V2 + Studio) and audio-safe
conditioning steering on LTXAV.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The conditioning-dim diagnostic logged once per process via _FUNPACK_AV_LOGGED,
so after the first generation it went silent — easy to read as "it never ran".
Fold the detected split into the per-run "Absolute steer applied" line so every
generation states whether audio is PROTECTED (video[:v] of D) or NOT split
(unrecognised width -> steering all channels, audio unprotected). Makes the
no-op case visible instead of silent.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
LTXAV splits one conditioning tensor into video|audio channel-slices
(av_model _prepare_context: torch.split(context,[v_dim,a_dim],-1)) and
cross-attends each stream to its own slice. Steering the whole tensor
corrupted the audio's text conditioning -> degraded audio (observed live).
Add protect_audio_channels: restore the audio channel-slice from the
unsteered conditioning so every edit moves video only. Applied at all
steering chokepoints:
- _v2_apply_conditioning_memory (per-prompt: liked/axis/concept/vf-grad)
- _v2_apply_absolute (global taste pull)
- _v2_ascend_conditioning (relative VF ascend+search)
- attn2 K/V direction patch + phrase emphasis
- FunPackConditioningAdjust (manual)
- sampler embed_guidance wrapper + per-scene VF ascend
Split auto-detected from width (7680->3840, 6144->4096); logs once.
Single-stream LTXV / unknown width = no-op (no regression).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Inserting the combo mid-list shifted every saved widgets_values slot in
existing Scene Chain Sampler nodes, so a leftover numeric value validated
against the combo ("0 not in ['relative','absolute']"). Moved it to the end
of optional inputs; old workflows keep their widget positions and fall back
to the 'relative' default.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Relative (default, unchanged) = per-prompt steering. Absolute = a keyless,
prompt-agnostic "global taste" prior that pulls conditioning toward generally-
liked directions regardless of the prompt; Both layers them.
- New keyless Absolute store (FUNPACK_ABSOLUTE_KEY): pooled liked/disliked
direction + global value function, learned across every rated generation.
- Absolute rating semantics: a rating means "details I like in general" (not
prompt adherence) — reward-driven liked/bad-dir storage, axis attribution
bypassed. Perfect = "more of this everywhere".
- _v2_finalize_conditioning replaces the per-key ascend hook on both returns;
pure Absolute also bypasses per-prompt conditioning memory.
- Scene Chain sampler: embed_guidance_source (relative/absolute) lets the
per-step nudge draw from the global direction/value function.
- Studio popup + V2 node expose Steer mode + Absolute strength.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds s_churn/s_tmin/s_tmax to sample_funpack_distilled_flow: optionally
re-noise the latent within [s_tmin, s_tmax] before each eval, then denoise
from the bumped sigma_hat. No extra model calls (still one eval per step,
at a higher noise level). Fights stale/frozen distilled output (more motion)
and can sharpen by letting the model re-resolve. sigma_hat is clamped to the
schedule start so the model never sees a higher-than-trained noise level, the
final jump-to-zero detail step is never churned, and the default 0.5-1.0 band
protects the sub-0.4 detail finish per the empirical sigma findings.
Churn supersedes the legacy s_noise ancestral path while active and is
video-stream-only on packed LTXAV latents. With s_churn=0 the sampler is
byte-identical to the previous deterministic ODE. Wired into the node and
Studio's Distilled Flow config panel.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Port the Hybrid/RF velocity-bias capture/apply and rating-gated reactive
rescue into sample_funpack_distilled_flow, reusing the shared trajectory
memory helpers. Adds velocity_bias_mode/strength/source/key and
rescue_mode/threshold/strength to the FunPackDistilledFlowSampler node and
wires them into Studio's Distilled Flow config panel (same blank/'default'
velocity-key -> refinement-key fallback as Hybrid). Steering is
magnitude-preserving and, on packed LTXAV latents, video-stream only
(audio-safe). With all controls off the sampler is byte-identical to the
previous deterministic ODE.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Document the three undocumented releases (2.7.5 embed guidance + online
value function + mid_scene_guide; 2.7.6 value-function ascent + rating
overhaul; 2.7.7 reactive rescue + Batch Training) and bring the Scene
Chain Sampler, Hybrid Euler-2S, and Studio docs in line with current
parameters and features.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Batch Training confirmed working end to end (controlled batch with transitions, distinct
per-variant seeds, node rating ignored during a batch, per-entry rating + VF/axis learning
on submit). Stripped the temporary trace prints (Batch Training check / Batch check / ACTUAL
scene seeds), keeping clean progress logs. Gitignore the local .testvenv.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The live log showed the single-scene path: 'packed 3 variant conditioning(s)' with ACTUAL
scene_seeds identical across all 3 (all inherited the base entry's funpack_scene_seed). My
earlier seed fix only covered the multi-scene duplication path. When a prompt resolves to one
scene (common), _v2_build_batch_variants reused the base scene seed for every variant ->
identical noise -> identical videos (only tiny diffs from VF ascent).
Fix: _v2_pack_batch now assigns a fresh, well-spread per-variant scene seed (gen-seeded RNG,
reproducible, per-scene offset) to the packed entries in BOTH paths, after building them.
Verified in venv: single-scene 3 variants -> 3 distinct seeds.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The 'seed=' in the batch log was the loop index seed (base+idx), not the seed that drives
noise. The real noise seed is each scene's funpack_scene_seed (set distinct per variant by
_v2_pack_batch). Print those so we can tell whether distinct seeds actually reach the
sampler vs. stale/old-code identical seeds.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1) All batch videos identical: in the transition path each scene carries a
'funpack_scene_seed' the sampler honors over its own seed, so duplicating the scene-set
left every variant with the same seeds. _v2_pack_batch now assigns DISTINCT per-variant
scene seeds via a gen-seeded RNG (well-spread, reproducible per gen). Verified in venv:
4 variants -> 4 distinct seed sets, reproducible.
2) Ignore the node's rating widget while a batch generates: that selection would apply
learning to the PREVIOUS run, but it's stale during a batch (the batch is rated afterward
in the panel). When batch_variants>1, force rating to '-Just forget it-' (skip_learning),
so all learning paths (phrase/conditioning-memory update, VF training, velocity commit)
are skipped. Conditioning APPLICATION still runs (it has no skip_learning guard), so the
batch still uses the learned directions.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Root cause (found via the diagnostics + the venv tests): the producer was gated on
'not split_by_transitions', but the user's workflow is multi-scene chains, so with
transitions on the producer never ran -> no variant markers -> sampler did one pass.
Fix: defer variant packing to the FINAL conditioning, applied right before BOTH returns
(the transition early-return and the normal return), so it wraps whatever output ends up
being. New _v2_pack_batch dispatcher: single-scene output -> _v2_build_batch_variants
(shortcut variants); multi-scene output (transition split) -> duplicate the whole scene
set per variant (seed-only). Each variant tags ALL its scene entries with the same index,
so the sampler groups by marker into N full chains and keeps variants independent.
Verified in the test venv: 3-scene set x 4 -> 12 entries, markers [0,0,0,1,1,1,2,2,2,3,3,3]
-> sampler sees 4 groups of 3 scenes; a single-variant group returns None (chains normally,
no recursion). Marker detection + producer round-trip all green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Prints (a) the batch_variants value + mode flags the refiner sees and how many packed
entries it produced, and (b) the positive entry count + variant markers + group count the
Chain Sampler sees. Pinpoints whether the break is the arm/settings (batch_variants==1 at
the refiner), the conditioning path (markers stripped before the sampler), or the split
logic. Temporary, to be removed once the cause is found.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
It shouldn't have been added there. The node 'Batch Training' button window is the sole
batch UI now (config when idle, rating list when finished). Removes the loadBatch() panel
and its call from renderRefiner; no leftover references, JS parses clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Per feedback: Batch Training is a complete UI thing driven by Studio (the hub), not a
prompt, and it must NOT start generation itself (ComfyUI's Generate does).
- Removed batch_iterations from the Chain Sampler entirely (input + param). The sampler
now enters batch mode ONLY when Studio packs variant markers into positive; the batch
count lives in Studio. _run_batch_training simplified to variant-entries-only.
- The node's 'Batch Training' button now opens a dedicated window (openBatchPanel) that
shows EITHER a config view (set batch size, Arm/Disarm) when no batch is pending, OR the
rating list (preview + per-entry rating + Submit/Forget) when a batch has finished. It
never queues — arming just sets refiner.batch_variants; the user presses Generate.
- Dynamic button label reflects live state: '(off)', '(armed ×N)', '(Processing…)',
'(Finished — rate)'. Driven by execution_start/success/error listeners, which also
one-shot disarm after a batch runs so the next Generate is normal.
The older in-Refiner-tab batch panel remains functional (secondary path); the node-button
window is now the primary entry point.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Submit now does more than train the value function (3a). New refiner method
_v2_learn_from_batch feeds each rated entry's conditioning through the SAME per-axis
direction-memory machinery as a normal rated run (_v2_update_conditioning_memory →
axis directions + liked/bad direction stores), and tallies axis votes across the batch:
because tokens were frozen, an axis rated missing/wrong in >= half the rated entries is a
high-confidence problem (not seed luck). Those consistent axes are written to
active_repair_axes, which the next generation's repair persists until a Perfect — so a
batch where most gens were 'Missing details' makes the next run boost details.
Wiring: batch submit collects (rating, serialized cond) per rated entry, trains the VF,
then calls _v2_learn_from_batch; the resulting insight ('consistent problem axes = ...')
is returned and shown in the Studio submit toast. List route now also returns each item's
variant index + prompt for the panel.
Batch Training is now complete: seed-only + shortcut variants + node button + VF training
+ axis/direction learning, all human-rated.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>