Own tab with its full sampling settings (temperature, top-p, top-k, min-p,
repetition/presence penalty, seed, greedy) and a last-run before/after view.
Studio's source_image now reaches the enhancer on the per-scene path too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Runs after shortcuts and after $variables resolve, before encoding — the model
is handed exactly the text that would otherwise have been encoded, and the
result is what ComfyUI generates from, so nothing downstream knows it happened.
Not the repair advisor: that one is triggered by a rating and fixes a named
fault. This runs on every generation, needs no key, no rating and no previous
run, and only elaborates. Uses advisor_clip when one is wired (the Studio node
already has the socket), the generation CLIP otherwise.
Multi-scene enhances each scene separately. The editor's scene list is
authoritative on count, so rewriting the scenes as one paragraph and
re-splitting could come back with a different number and desync every clip from
its anchor. One generation per distinct text, cached within the run.
Every failure path returns the ORIGINAL prompt — an enhancer that empties the
prompt on a bad generation would render a blank video and blame the model.
Thinking traces, code fences, preambles and whole-answer quotes are stripped;
quotes inside the prompt survive, because speech is quoted on purpose.
Settings > Engine > Studio: toggle, editable system prompt (new textarea field
kind), length limit, temperature, top-p, thinking. Off by default.
Tests: 1637 passed (+24).
The four H3 render strengths shipped as hand-set dials. They should not
have: four scalars is a SMALLER search than the sigma profile, which
already converges on ratings alone, so typing them is the user doing work
the loop can do.
Same ES update as the sigma profile, with one difference — that profile is
centred on 0, so its applied value IS its perturbation; these are centred
on 1.0, so the perturbation is (applied - value) and that is what the
reward is credited to. Exploration narrows on a like, widens otherwise,
and is seeded from the run seed so a repeat repeats.
Learned values reach the sampler through the conditioning meta, the bridge
h3 token weighting already uses: Studio owns the key, the sampler owns the
application. h3_gain_mode defaults to "learned" and ignores the widgets;
"manual" uses them as typed and still works with no Refiner in the graph.
Learning runs on every rating regardless of the toggle, the same rule
value_guidance follows.
Also fixes four note_on_change calls added earlier this session that were
missing the required tag argument — they would have raised on the non-H3
and unreadable-tags paths.
A wired positive CONDITIONING means Studio does not encode the prompt.
That is not a preference to configure; it is what wiring the input says,
and it is what a wired negative CONDITIONING has always done. Wanting
CLIP to own the prompt means not wiring one.
Removes clip_owns_prompt from the node, both settings panels and the
settings JSON.
Two defects behind a reported x1.9.
Spans overlap — a phrase and one of its own words match the same tokens
and their biases ADD. Intended, so the word reinforces the phrase, but
unbounded three overlapping x1.5 spans reach an effective x3.4 on one
token. Bounded against the strongest SINGLE span, so an explicit
(word:2.0) still means exactly 2.0.
And it shipped on by default. It changes what the model sees on every
rated run, and it is gated on is_h3_clip — which is why disconnecting
CLIP made generations normal again. Now a toggle, off.
Also replaces prefer_wired_conditioning with clip_owns_prompt: a wired
conditioning owns the prompt by default, and the old order is the opt-in.
It claimed the toggle skips shortcuts, $variables and the scene split.
Only the scene split is true. _expanded_link_texts pre-expands shortcuts
and resolves $variables for every LINKED input, so a node outside Studio
receives the finished text — which is why a prompted soundtrack still
plays with the toggle on.
Also: prompt_base now refuses to place the bias when the text run in the
conditioning does not match the text measured here. A reference node
encodes the whole combined prompt while Studio may be measuring one
scene's, and taking the tail of a longer run would bias the wrong words.
Erase the negative's pooled direction from the positive conditioning
(projection by default, never the vision span). Plus an option to let a
wired positive CONDITIONING own the prompt while CLIP keeps its jobs.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Pass 2 can run a different algorithm. Unwired it reuses pass 1; in the
Editor it is behind Second pass > Own sampler, and Studio mirrors the
high pass into that output when off, so existing projects are unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Lift the unsharp out of the sampler loop through a denoiser proxy, the
same way ALG does. Window is a fraction of the schedule; audio excluded.
Off by default; an unwrappable sampler keeps sampling and says so.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three things that were each locked to one implementation detail:
- steps + schedule were a KSampler-branch feature, though every sampler here
walks a sigma list handed in from outside. They are now pass-level, so
Distilled Flow and Hybrid Euler 2S can run a named schedule (and the second
pass can be computed rather than typed) in both frontends and on the node.
- the project's Frames field snapped to the model's grid on every family. On
H3 that is required, but its arrows moved by 1 and the snap put the value
straight back; on LTX the builder rounds up by itself, so the snap only
fought the user. H3 now steps a whole 17 frames per arrow, LTX keeps what
you type and walks 8k+1 with its arrows.
- ALG lived inside the Distilled Flow step loop, so it was unreachable with a
stock KSampler. Its blurred/sharp swap is decided by the step's sigma, and
sigma is an argument of every model call, so a denoiser proxy drives it from
outside any sampler. New alg_anchor toggle on the Chain Sampler drives the
in-loop version too, so there is one control wherever you are.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A SAMPLER object is only the step function, so picking KSampler used to leave
the pass with no schedule at all unless a sigma list was typed by hand.
steps + schedule now build one from the loaded model's model_sampling, exactly
as ComfyUI's BasicScheduler does. The schedule dropdown is the switch between
the two sources rather than a silent precedence rule: "use_user_sigmas" — the
default, so nothing changes for an existing config — runs the Sigmas field as
typed, and any real scheduler computes instead, leaving the typed schedule
parked in the field to switch back to without retyping it. Studio logs the fact
that the field is being ignored, and steps is only shown while it applies.
Both frontends, same change.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Studio's KSampler mode passes the chosen name straight to comfy.samplers.
sampler_object(), so any sampler this ComfyUI has always worked — but both
frontends offered a hardcoded list of eight written before the rest existed.
That silently hid 36 of them, including res_multistep, which is what ComfyUI's
own MiniMax H3 templates use.
Both now read sampler_name from the live KSampler node spec and fall back to the
old list if that fetch fails. A saved name missing from the live list stays
selectable instead of being swapped for the first option.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Punchy frame_rate mult held over the first/last slice of a scene's
denoise progress, easing to natural in the middle - same progress-
from-sigma mechanism as pulse, shaped as a single edge ramp instead
of repeated segments. Wired through build_enhancements (single-scene),
the Scene Chain Sampler's per-scene wrapper dispatch, and both Studio
and Editor temporal-style dropdowns.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Normalization is now available in both Hybrid Euler 2S and Distilled Flow
samplers, making the standalone Normalizing sampler redundant. Removes the
node class, its sampler function, two private helpers (_parse_norm_factors,
_apply_av_norm_factors), the Studio/Movie Editor "Normalizing" type option,
and the defaultNormalizing() factory. Stale "same as the Normalizing sampler"
tooltip references in both sampler nodes are updated.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Deletes the FunPack Scene Builder node and the Studio Scene Builder feature
— the per-key scene database (scene_db / universal_memory / saved scenes),
the Studio "Scene" tab, scene-phrase authority over classification, and the
scene-database wildcard cleanup. It was redundant: helpful on paper but
effectively unused, undrivable from the Cutting Room, and a risk to shortcuts.
Removed:
- node registration (__init__.py, funpack.py) + web/funpack_scene_builder.js
- templates.py: scene-DB storage layer (load/save/normalize/empty_scene_db,
SCENE_DB_VERSION/SCENE_STATE_FIELD/SCENE_CATEGORY_SOURCES, scene_store_path),
all scene_* helpers, resolve_scene_database_wildcards, the FunPackSceneBuilder
class, and the /funpack/scenes* routes
- conditioning.py: _v2_scene_builder_db / _v2_scene_memory_item /
_v2_apply_scene_builder_authority / _v2_scene_builder_category_for_entry /
_v2_sync_scene_builder_memory / _v2_resolve_scene_builder_wildcards (+ wildcard
helpers + _v2_scene_key), the scene_db threading through classify/learning,
the scene_category_locked phrase fields + their training branch, the
state["scene_builder"] preservation, and the Studio scene_builder prompt mode
- web/funpack_studio.js: Scene tab, SB_MODES, scene_builder settings, renderScene,
fetch/saveScene, the Session Scene-Builder section, and the Refiner banner/notice
- tests/test_scene_builder.py (whole file) + scene-builder tests in
test_v2_category_alignment.py; the SceneBuilder example workflow + its doc;
README link; Scene Builder mentions in docs/FunPackStudio.md
Kept intact: shortcuts (apply_prompt_shortcuts / shortcut DB), transitions and
the canonical split_scenes splitter, and FunPackRefinementKeyLoader. Studio now
always uses the connected positive_prompt. No new test failures (the 16/97
remaining in tests/ are pre-existing env/sampler failures); movie_editor 140 pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neutralize the repair application in refine(): the intent-aligned prompt is
encoded as-is — perfect-repair phrase injection, missing-axis repair, and the
emphasis pass are gone. The advisor remains the only prompt-rewriting path, and
repair_feedback/active_repair_axes is KEPT (it's the 'what's missing' signal the
advisor still reads). Drop the prompt_repair param from refine(), INPUT_TYPES,
FunPackStudio, and both UIs (web + engine_settings).
The dead repair-only methods (_v2_repair_prompt_for_missing_axes, perfect-repair
phrases, etc.) come out in the next commit; shared helpers like
_v2_repair_intent_roots (used by intent alignment) stay.
Deleted the now-obsolete test_repair_candidates_saved_as_json_lists (tested the
removed injection). No new test failures vs dev.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Split markers are prompt-only in Studio and the Cutting Room; video blends and clip effects live in the NLE library and + Add menu. Rename on-disk/export defaults to promptsplit.json and funpack_promptsplit.json.
Co-authored-by: Cursor <cursoragent@cursor.com>
Introduces a new temporal_style option that cycles motion→hold ramps
across each scene's denoise trajectory via a segmented frame_rate wrapper.
Wired through Studio, engine settings, chain sampler conditioning tags,
and build_enhancements for single-scene workflows.
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>
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>
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>
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>
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>
Producer (Studio owns conditioning, per the boundary law): refine_v2 gains batch_variants.
When >1, _v2_build_batch_variants packs N conditioning entries into the single positive wire,
each tagged 'funpack_batch_variant'. Variant 0 is the fully-processed base; variants 1..N-1
re-resolve shortcuts with seed+i (random option per entry) and get the same conditioning-memory
treatment, deduped by expansion text. No shortcut variability -> all entries resolve identical
and reuse the base cond -> the batch becomes seed-only (sampler varies the seed per entry).
Captures the pre-shortcut prompt to re-resolve. Not combined with split_by_transitions.
Trigger: a 'Batch Training' button on the Studio NODE (next to Open Studio) — prompts for N,
sets refiner.batch_variants, queues one prompt, then auto-reverts to 1 (one-shot). Studio is
the batch trigger (hub principle); no sampler input needed.
Sampler: now enters batch mode when positive carries variant markers, even if batch_iterations
is 1 (markers are the trigger; variant count wins). Each entry already saves its own cond, so
Submit trains the VF per variant — teaching which prompt variant rated better. Panel hints now
point at the button.
End-to-end: press Batch Training -> N -> Studio makes N variant conds -> sampler samples N ->
previews to temp -> rate in Studio panel -> Submit trains VF per entry -> batch cleared.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Per the Studio/sampler boundary law (Studio owns conditioning; sampler only samples), the
sampler no longer encodes anything. It now auto-detects when Studio has packed N shortcut
VARIANTS into positive — each scene entry tagged with 'funpack_batch_variant' = variant
index — via _split_batch_variants: if present, it samples one chain per variant (variant
count wins); otherwise it falls back to seed-only repeats of batch_iterations. Decisions:
'sampler loops, Studio varies' + 'pack into positive + markers'.
Each entry now saves its OWN conditioning (<id>.cond.pt) — identical across a seed-only
batch, distinct per variant — and the manifest records variant index + prompt per item.
Submit (batch_training.py) trains the VF per entry from its own cond, so variant batches
teach the model which prompt variant rated better (not just seed-quality variance). Studio
panel shows the variant tag + prompt per row.
Studio-side variant PRODUCTION (resolve shortcuts N times, encode, pack markers) is the
remaining half — a Studio/refiner feature, tracked next. Sampler side is ready for it.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Phase 1 amended: the engine now also saves the frozen conditioning (cond.pt) per batch
so submit can train on (cond, rating).
Phase 2 (panel + API): new batch_training.py registers /funpack/batch/{list,submit,forget}
(follows the existing /funpack/* PromptServer pattern). Studio gains a 'Batch Training'
section under the refiner: lists the pending batch for the active refinement key with each
entry's filename + seed, a Preview button (loads the temp webp via /view?type=temp), and a
per-entry V2-rating dropdown, plus Submit and 'Forget batch'. Previews served straight from
ComfyUI temp — no custom file route needed.
Phase 3 (learning intake): Submit loads cond.pt and trains the value function on
(cond, reward) for every rated entry — same conditioning, N rewards = variance-reduction
RLHF, which directly sharpens conditioning ascent. '-Just forget it-'/unknown ratings are
skipped. Submit consumes (deletes) the batch; Forget discards it without learning. Either
way the panel clears and the sampler is ready for a new batch.
Human stays the rating oracle throughout (no auto-rating) — 'user over everything'.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Audit finding: value_guidance defaulted OFF, and it gated value-function TRAINING — so
by default the VF never trained, conditioning ascent + the chain sampler's embed_guidance
were permanently inert, and a user who ran many gens with it off then enabled it started
from zero (no accumulated learning).
Fix decouples learning from application:
- The VF now ALWAYS trains in the background on rated gens (cheap: small MLP, 20 steps,
no diffusion calls) whenever there's a rated previous run + refinement key. The reward
asset accumulates regardless of the toggle.
- value_guidance now controls only APPLICATION of the learned direction (output ascent +
search), via a new apply= param on _v2_ascend_conditioning. Default ON.
- Defaults flipped to True: refine_v2 signature, Studio settings read, JS default +
migration. Studio toggle relabeled 'Apply value guidance' with corrected help (training
always on; applies after 10+ ratings; off = strict prompt fidelity, learning still
accumulates). Fixed stale '5+ ratings' text (MIN_SAMPLES is 10).
Side effect: embed_guidance (chain sampler) now has a trained VF available by default.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Three issues found tracing the full Studio path with all features on:
1) BUG (silent data loss): a custom velocity_refinement_key captured trajectories
under that key but the refiner committed the rating under the effective refinement
key — so custom velocity keys never learned (banks stayed empty, rescue/velocity a
permanent no-op). This undercut per-key cut-routing. Fix: Studio resolves each pass's
velocity key (same logic as _build_one_sampler) and passes them to refine_v2, which
now commits the verdict to the union of {effective key} + velocity keys (dedup).
Backward compatible (callers without _velocity_keys behave as before).
2) Effectiveness: VELOCITY_BIAS_TARGETS (0.90, 0.80) matched only sigma~0.909 on the
standard 8-step LTX schedule, so rescue fired once per gen at a near-noise step and
never at the detail-forming sigmas. Broadened to (0.90, 0.72, 0.42) -> hits 0.909,
0.725, 0.422. Velocity APPLY still structure-only (highest target); rescue now acts
where runs actually go good/bad. (New detail targets fill as gens are rated.)
3) Redundant value: velocity_aspect_bucket was a manual text field never tied to actual
resolution, and the bank key already includes the full latent shape (which encodes
resolution) — so it was doubly redundant. Removed from the key, all sampler plumbing,
INPUT_TYPES, Studio build, and the JS UI/defaults. Persistence loads old stores fine
(the 'aspect' field is simply ignored; key is now (refkey, target, shape)).
Verified: both py files + JS parse clean; all refactored call signatures aligned.
Tests require the ComfyUI venv (torch) to run.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
UX/variability win — collapse the expert knob-soup into one control plus a
legible summary.
- Variability macro (Chill/Spicy/Chaos presets + 0..1 slider) orchestrates the
stochastic knobs: eta (video variability), eta_final (late-noise ramp, only at
high chaos), quality_sharpness (detail recovery as noise rises), velocity spice
(action injection past Spicy, source=nearest), and motion pulses. Deliberately
keeps high_quality_pct>0 (disabling the deterministic finisher under ancestral
noise = mess). Writes the existing hybrid fields; all still individually editable.
- 'Active features (this config)' readout: green/grey rows for ancestral noise,
velocity spice, rescue, quality pass, motion pulses — turns the invisible stack
legible. Notes audio is auto-held deterministic on LTXAV.
Frontend-only; no model/Python changes (all fields already plumb through).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The real limiter wasn't the 0.35 slider cap but the internal fixed 4.5%-of-|x|
delta clamp, which saturated almost immediately — the upper slider range was a
no-op. Now the rotation cap scales with strength (0.30*strength, capped 0.95), so
the whole range is meaningful: ~0.15 subtle spice (matches old feel), 0.3-1.0 clear
action crossover, 2-3 approaches full action replacement without wiping the current
gen. Magnitude-preserving renorm still keeps |x|, so high strength rotates rather
than blows up. Raised the param/UI cap to 3.0 and updated the tooltip.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Compensate the slow quality degradation from velocity-bias 'apply' (additive
mean-pull) with four guards on the Hybrid Euler 2S sampler (both eps and
rectified-flow/LTXAV paths):
- B: apply is now magnitude-preserving — rotate x toward (x+delta) and
renormalize to |x| instead of x+delta, so no energy is injected.
- C: apply fires only at the highest (structure) velocity target and decays
strength with the sigma ratio; detail sigmas left untouched.
- E: new quality_sharpness knob — temporal-average unsharp on the x0 prediction
during the quality phase to restore high-frequency detail (free, no extra eval).
Default 0.0 (off).
- D: new velocity_bias_source = mean|nearest — 'nearest' steers toward the single
best-matching prompt cluster (one real good gen's detail) instead of the
washed-out average. Affects both apply and rescue. Default 'mean' (off).
Plumbed through get_sampler/INPUT_TYPES, Studio _build_one_sampler, and the
Studio JS sampler panel (both presets + UI controls).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Root cause of "rescued toward an Awful gen": velocity capture was
rating-blind — it wrote every sampled trajectory straight into the one
"good" memory, so a fresh key whose only capture was an awful gen made that
awful run the sole steering target. Ratings (which live in the refiner) never
touched the bank.
Now:
- capture STAGES the current gen's trajectory (VELOCITY_BIAS_PENDING) instead
of committing it; staging runs whenever rescue is on (no separate capture
toggle needed).
- the refiner commits the previous gen's staged trajectory by its rating:
like/loved/nailed -> good bank, awful -> bad bank, everything else dropped.
- rescue steers TOWARD the good bank and AWAY from the bad bank (per prompt
cluster), firing when diverged from good OR aligned with bad beyond
threshold; no-op when neither bank has a prompt match.
- session reset / clear_refinement_data now clears good + bad + pending.
velocity-bias "apply" now also reads the rating-gated good bank. Tooltips and
Studio note updated.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The velocity_refinement_key (namespace for trajectory capture + rescue
clusters) was a separate field defaulting to "default", easy to drift out
of sync with the refinement key Studio actually uses. Now when it is blank
or left at "default", Studio resolves it to the effective refinement key
(same resolution as seed memory / refine_v2), so capture and rescue share
one bucket automatically. An explicit non-default value is still respected.
JS hint added on the velocity key field.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Studio builds its sampler via FunPackHybridEuler2SSampler.get_sampler but
did not pass the new rescue params. Thread rescue_mode/threshold/strength
through _build_one_sampler, add them to the Studio JS hybrid defaults
(high+low) and the sampler config panel, with a note that rescue needs the
velocity-bias memory captured first.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
LTX packs all spatial/temporal dims into a single token [1, 1, C*T*H*W]
during sampling. Per-step latent steering requires hooking into the model
internals, not the k-diffusion callback. Removed: compress_latent(),
_load_latent_value_function(), latent VF training, motion floor callback,
latent_value_guidance toggle in Studio.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Trains a second OnlineValueFunction on rated video latents (compressed via
channel mean-pool). At each denoising step, computes ∂reward/∂latent through
the lightweight MLP and applies it as an in-place drift to the noisy latent —
gradients never touch the 22B transformer. Controlled by embed_guidance_strength
alongside the existing conditioning guidance. Studio toggle: "Latent guidance".
Cleared on session reset alongside the conditioning VF.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two server routes (GET /funpack/value_function/export, POST /funpack/value_function/import)
serve and receive the .pt binary. Studio Session tab gains Export and Import buttons
below the value guidance toggle, keyed to the active refinement key.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
value_function.py: OnlineValueFunction MLP that trains incrementally on
(conditioning, reward) pairs. Uses replay buffer of 100 samples, 20
gradient steps per update. save/load to .pt file via refinement_state_path.
Studio popup: new "Value guidance" toggle. When on, trains the value function
after every rated generation (good and bad). Falls back to no-op if conditioning
deserialization fails.
chain sampler: _load_value_function reads the trained MLP if ready (5+
samples). _build_embed_guidance_wrapper uses value function gradient
(∂reward/∂conditioning) when available, fixed liked direction as fallback.
Log reports which mode is active and sample count.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Reads settings.refiner.vision_conditioning (default true) and gates
source_image passed as reference_image to Gemma3 encoding. Toggle lives
in the popup UI next to Reference injection, not on the node.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mirrors _v2_transition_scene_texts: the text before the first
transition is a character anchor prepended to every scene, not a scene
itself. Show it separately above the rail. scenes[] now matches what
the Scene Chain sampler actually generates.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extract _v2_split_prompt_by_transitions to module-level
split_prompt_by_transitions. parse_timeline_segments now calls it
directly with placement=silent — same code path as generation.
Eliminates all reimplemented splitting logic.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>