diff --git a/movie_editor/frontend/engine_settings.js b/movie_editor/frontend/engine_settings.js index 75585100..c2a1956b 100644 --- a/movie_editor/frontend/engine_settings.js +++ b/movie_editor/frontend/engine_settings.js @@ -213,6 +213,9 @@ hint: "Gives every scene the same seed instead of one each. Makes scenes resemble each other more, and makes the run repeatable when you also set a fixed seed below." }, { name: "carry_i2v_guides", label: "Carry i2v guides", kind: "bool", default: false, lockMulti: true, hint: "Shows each scene the protected frames of the one before it, so the look carries down the chain. Costs guide tokens (slightly slower scenes)." }, + { name: "carry_overlap_through_anchor", label: "Carry context through an anchor change", kind: "bool", default: false, + hint: "When a scene starts from its own anchor image, still carry the previous scene's tail into the frames after it — so the background and environment survive the change of subject.", + detail: "Without this an anchored scene is a hard cut with no carried context. The anchor's own first frame is never touched either way, so the cut still reads as a cut; only the frames after it keep the old scene's surroundings. No effect on scenes without their own anchor. Needs Frame overlap above 0." }, { name: "cfg", label: "CFG", kind: "float", default: 1.0, min: 0, max: 20, step: 0.1, hint: "How hard the model is pushed toward the prompt. LTX and H3 are distilled and want 1.0 — raising it burns the image instead of improving prompt-following." }, { name: "embed_guidance", label: "Embed guidance", kind: "bool", default: false, @@ -298,6 +301,26 @@ { name: "h3_audio_clock", label: "H3 audio clock (few-step audio)", kind: "bool", default: false, hint: "MiniMax H3 only: removes audio distortion on few-step turbo schedules. Free.", detail: "H3 runs video and audio on different flow schedules but only one sigma grid reaches the sampler, so audio drifts further the bigger the step. This corrects it for one multiply per step. Exact with FunPack Distilled Flow, Hybrid Euler 2S and euler; leave it off with res_multistep / dpmpp_2m and the rest of the multistep family, which already absorb most of the error. No effect when both sigma shifts are equal, or on two-evals-per-step samplers." }, + { name: "h3_gain_mode", label: "H3 render gains", kind: "combo", choices: ["learned", "manual"], default: "learned", + hint: "MiniMax H3 only. 'learned' takes the five render strengths from your ratings and ignores the dials below. 'manual' uses the dials as typed.", + detail: "Learned needs the Refiner's 'Rating-learned render gains (H3)' left on — with it off, or before anything is rated, learned mode renders at the model's trained strengths and the dials still do nothing. Switch to manual to drive them yourself." }, + { name: "h3_gain_video", label: "Write gain · picture", kind: "float", default: 1.0, min: 0.0, max: 2.0, step: 0.01, + dependsOn: "h3_gain_mode", dependsVals: ["manual"], + hint: "How hard each block writes into the picture rows. Below 1.0 is a calmer, less-committed image; above pushes harder. 1.0 = untouched. Free.", + detail: "Keyframe pins and reference images ride the same modality tag as the video, so this moves the anchor with it." }, + { name: "h3_gain_prompt", label: "Write gain · prompt", kind: "float", default: 1.0, min: 0.0, max: 2.0, step: 0.01, + dependsOn: "h3_gain_mode", dependsVals: ["manual"], + hint: "How much each block rewrites the prompt as it draws. Lower it when a scene slowly stops matching what you asked for; 0.0 freezes the text at its encoded value. 1.0 = untouched. Free." }, + { name: "h3_gain_audio", label: "Write gain · soundtrack", kind: "float", default: 1.0, min: 0.0, max: 2.0, step: 0.01, + dependsOn: "h3_gain_mode", dependsVals: ["manual"], + hint: "How hard each block writes into the audio rows. Below 1.0 builds the soundtrack more conservatively. 1.0 = untouched. Free." }, + { name: "h3_prompt_scale", label: "Prompt loudness", kind: "float", default: 1.0, min: 0.0, max: 2.0, step: 0.01, + dependsOn: "h3_gain_mode", dependsVals: ["manual"], + hint: "How loudly the prompt is READ, as opposed to how much it is rewritten. Above 1.0 it is harder to ignore; below, the anchor or the reference gets more say. 1.0 = untouched. Free." }, + { name: "h3_taste_bias", label: "Taste push", kind: "float", default: 0.0, min: -0.30, max: 0.30, step: 0.01, + dependsOn: "h3_gain_mode", dependsVals: ["manual"], + hint: "Pushes the prompt toward what you have rated well. Negative pushes away from it. Needs at least 3 liked runs on the refinement key; without them it does nothing and says so. 0.0 = off. Free.", + detail: "The Refiner already steers along your liked direction, but on H3 that edit is mixed and renormalized by the token refiner before the model reads it. This adds the same direction after the refiner, where it lands as sent. Measured as a fraction of a typical prompt row, so one value means the same thing on every prompt." }, { name: "segmented_detailing", label: "Segmented detailing (region refine)", kind: "bool", default: false, hint: "Re-renders small regions like hands at higher detail after each scene. Costs about 15%.", detail: "After each scene renders, CLIPSeg finds the named regions, refines them at 2x through Lightricks' latent upsampler and pastes them back through a feathered silhouette. Final resolution never changes. Regions over 35% of the frame are refused; every skip is in the scene report." }, @@ -479,11 +502,11 @@ // ── views (inner-sidebar categories) ─────────────────────────────────────── const CHAIN_VIEW_KNOBS = { - chain_continuity: ["carry_i2v_guides"], + chain_continuity: ["carry_i2v_guides", "carry_overlap_through_anchor"], chain_timing: ["frame_overlap", "transition_duration", "use_same_seed", "cut_opening_frames"], chain_guidance: ["cfg", "embed_guidance", "embed_guidance_source", "embed_guidance_strength", "score_slider", "score_slider_strength", "taste_nearest_prompt", "output_guidance", "output_guidance_strength", "dynashift", "dynashift_strength", "dynashift_threshold"], chain_decode: ["decode_noise_scale", "decode_timestep", "decode_tile_size"], - chain_experimental: ["context_windows", "context_window_length", "context_window_overlap", "context_window_schedule", "context_window_fuse", "context_window_freenoise", "context_window_retain_first", "plateau_cache", "plateau_cache_threshold", "h3_audio_clock", "segmented_detailing", "detail_targets", "detail_strength", "detail_threshold", "detail_max_area", "detail_mode", "detail_denoise", "mid_scene_guide", "mid_scene_guide_strength", "joyai_memory", "joyai_memory_size", "joyai_fix_frames", "joyai_frame_select", "joyai_memory_strength", "joyai_audio_memory", "v2a_grad_scale", "alg_blur_guides", "alg_guide_blur_strength", "alg_guide_blur_sigma_threshold", "bounded_attention_enabled", "identity_transfer_enabled", "source_id", "phase_scale", "id_strength", "arcface_mode", "debug_log"], + chain_experimental: ["context_windows", "context_window_length", "context_window_overlap", "context_window_schedule", "context_window_fuse", "context_window_freenoise", "context_window_retain_first", "plateau_cache", "plateau_cache_threshold", "h3_audio_clock", "h3_gain_mode", "h3_gain_video", "h3_gain_prompt", "h3_gain_audio", "h3_prompt_scale", "h3_taste_bias", "segmented_detailing", "detail_targets", "detail_strength", "detail_threshold", "detail_max_area", "detail_mode", "detail_denoise", "mid_scene_guide", "mid_scene_guide_strength", "joyai_memory", "joyai_memory_size", "joyai_fix_frames", "joyai_frame_select", "joyai_memory_strength", "joyai_audio_memory", "v2a_grad_scale", "alg_blur_guides", "alg_guide_blur_strength", "alg_guide_blur_sigma_threshold", "bounded_attention_enabled", "identity_transfer_enabled", "source_id", "phase_scale", "id_strength", "arcface_mode", "debug_log"], }; function countChainView(p, id, st) { diff --git a/movie_editor/frontend/pipeline_caps.js b/movie_editor/frontend/pipeline_caps.js index f6ff5a69..204b1e27 100644 --- a/movie_editor/frontend/pipeline_caps.js +++ b/movie_editor/frontend/pipeline_caps.js @@ -169,10 +169,24 @@ // Left on against an LTX pipeline they are just as silently inert, so they get a chip // by the same rule — the user should not have to spend a generation to find out. // key -> why it cannot run off H3. + const H3_RENDER_GAIN_REASON = + "The render gains scale H3's per-modality AdaLN gates and its token refiner. LTX has " + + "neither: one modulation path for all streams, and the prompt reaches it through " + + "cross-attention instead of a packed text span."; + const H3_ONLY_SAMPLER_INPUTS = { h3_audio_clock: "The audio clock corrects for H3 denoising video and audio on two different flow " + "schedules. LTX puts both streams on one schedule, so there is nothing to correct.", + // The render gains scale H3's per-modality AdaLN gates and its token refiner. LTX has + // neither — one modulation path, cross-attention instead of a packed text span — so + // there is nothing for these to reach on any other family. + h3_gain_mode: H3_RENDER_GAIN_REASON, + h3_gain_video: H3_RENDER_GAIN_REASON, + h3_gain_prompt: H3_RENDER_GAIN_REASON, + h3_gain_audio: H3_RENDER_GAIN_REASON, + h3_prompt_scale: H3_RENDER_GAIN_REASON, + h3_taste_bias: H3_RENDER_GAIN_REASON, }; // Sub-settings of identity transfer: meaningless wherever the feature itself cannot run,