Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
63 lines
2.6 KiB
Python
63 lines
2.6 KiB
Python
"""Temporal style: how motion and time feel, on an LTX model. One mechanism, chosen by name.
|
|
|
|
Everything but `loop` tells the model a different frame rate than the clip's (see style.py);
|
|
`loop` rolls the latent in time so the clip's end joins its start (loop.py).
|
|
|
|
`auto` reads each shot's words and picks one of these styles per shot. The module cannot see the words,
|
|
so the app makes that choice when it builds each run (app/ui/features/temporal) and sends the concrete
|
|
style; an `auto` that reaches here unresolved does nothing.
|
|
"""
|
|
|
|
from ..._core import patching
|
|
from . import loop as _loop
|
|
from . import style
|
|
|
|
ID = "temporal_style"
|
|
TITLE = "Temporal style"
|
|
MOUNT = "generation.sampling"
|
|
STAGE = "sampling"
|
|
CATEGORY = "sampling"
|
|
STATUS = "experimental"
|
|
REQUIRES = ["ltx_av"]
|
|
|
|
STYLES = ["natural", "auto", "accelerate", "decelerate", "freeze", "pulse",
|
|
"rapid_start", "rapid_end", "rapid_start_end", "loop"]
|
|
|
|
SETTINGS = {
|
|
"style": {
|
|
"type": "enum", "default": "natural", "label": "Temporal style",
|
|
"options": [{"value": v, "label": v.replace("_", " ")} for v in STYLES],
|
|
"hint": "Changes how motion feels, such as smoother, punchier or looping. natural leaves it unchanged; auto picks a style per shot from its words.",
|
|
},
|
|
}
|
|
|
|
|
|
def install(patcher, values, key):
|
|
chosen = values.get("style", "natural")
|
|
old = patcher.model_options.get("model_function_wrapper")
|
|
state = {}
|
|
if chosen in style.MULT:
|
|
mult = style.MULT[chosen]
|
|
wrapper = style.make_wrapper(old, lambda args: mult)
|
|
note = f"{chosen}: frame rate x{mult:g}"
|
|
elif chosen == "pulse":
|
|
wrapper = style.make_wrapper(old, lambda args: style.pulse_mult(style.progress_of(args, state)))
|
|
note = "pulse"
|
|
elif chosen in ("rapid_start", "rapid_end", "rapid_start_end"):
|
|
wrapper = style.make_wrapper(old, lambda args: style.rapid_mult(style.progress_of(args, state), chosen))
|
|
note = chosen.replace("_", " ")
|
|
elif chosen == "loop":
|
|
wrapper = _loop.make_loop_temporal_wrapper(old)
|
|
note = "loop: the clip's end joins its start"
|
|
if "context_handler" in patcher.model_options:
|
|
note += " (context windows are on: each WINDOW is looped, not the clip -- turn them off for a seamless clip)"
|
|
else:
|
|
return None # natural, or an auto the app did not resolve
|
|
patcher.set_model_unet_function_wrapper(patching.tag(wrapper, key))
|
|
installed = patcher.model_options["model_function_wrapper"]
|
|
installed._funui_prev = old # so stripping ours puts the earlier one back
|
|
return note
|
|
|
|
|
|
PROVIDES = {"modifier": install}
|