fix(onboarding): setup panes open over the wizard instead of replacing it
The wizard sat at z-index 800, above .modal-overlay (500) and below .fw (4000), so "Open Models…" opened behind it and did nothing visible, and the extras step worked around that by closing the wizard first — which dropped you into a half-finished editor. It now sits at 400: Models, Settings and the Composer layer over it the way they layer over the editor, and closing one returns to the step. Prompt splits called Composer.open(), which does not exist; the export is toggle(). Also: MiniMax H3 no longer pulls in ComfyUI-LTXVideo. LTXFloatToInt only converted the project's frame rate for user slots, and H3's rate is fixed at 24 by the model, so an LTX pack was a hard requirement of a pipeline with no use for it. Core producers are now filtered by what the family's graph actually built. The Cutting Room brand links to the hub, as Easy Gen's already did. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
f28e57fbe3
commit
03c0b2dcd9
@@ -116,6 +116,9 @@ CORE_PRODUCERS: list[tuple[str, int, str]] = [ # (core_id, output_index, type)
|
||||
# concat and the latent slot feeds the sampler directly.
|
||||
# * LTXVAudioVAEDecode reads `audio_vae.first_stage_model.output_sample_rate`, which
|
||||
# H3's audio VAE does not define — it would raise. Core's VAEDecodeAudio is generic.
|
||||
# * LTXFloatToInt only exists to offer an INT copy of the project's frame rate to user
|
||||
# slots. H3's frame rate is fixed at 24 by the model, so there is nothing to convert —
|
||||
# and keeping it made an LTX node pack a hard requirement of a non-LTX pipeline.
|
||||
#
|
||||
# Anything not listed here is shared, so a fix to the core graph reaches both families.
|
||||
DEFAULT_FAMILY = "ltxav"
|
||||
@@ -124,7 +127,7 @@ FAMILIES: dict[str, dict] = {
|
||||
"ltxav": {"label": "LTX-2 / LTXAV"},
|
||||
"minimax_h3": {
|
||||
"label": "MiniMax H3 (Hailuo)",
|
||||
"drop": ("cond", "concat"),
|
||||
"drop": ("cond", "concat", "f2i"),
|
||||
"core": {"audiodec": "VAEDecodeAudio"},
|
||||
"links": {
|
||||
# positive/negative come straight from Studio, with no LTXVConditioning between
|
||||
@@ -976,7 +979,11 @@ def _resolve_target(target: str, port_to_core, slot_node_id) -> Optional[tuple[s
|
||||
def _producers(graph, slots, slot_node_id, slot_def, object_info):
|
||||
"""type -> list of (node_id, output_index). Slots + core producers."""
|
||||
out: dict[str, list] = {}
|
||||
# Only what this family's core actually built — offering a producer the graph dropped
|
||||
# would auto-wire a slot to a node that is not there.
|
||||
for cid, oidx, t in CORE_PRODUCERS:
|
||||
if cid not in graph:
|
||||
continue
|
||||
out.setdefault(t, []).append((cid, oidx))
|
||||
for s in slots:
|
||||
nd = slot_def[s["id"]]
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<body>
|
||||
<!-- ───────────────────────── MENU BAR ───────────────────────── -->
|
||||
<nav class="menubar" id="menubar">
|
||||
<div class="brand"><span class="brand-mark">◉</span> FunPack <span class="brand-sub">Cutting Room</span></div>
|
||||
<a class="brand" href="/funpack/" title="FunPack Hub"><span class="brand-mark">◉</span> FunPack <span class="brand-sub">Cutting Room</span></a>
|
||||
<div class="menus" id="menus"><!-- populated by menubar.js --></div>
|
||||
<div class="menubar-right">
|
||||
<span class="save-chip" id="save-chip"></span>
|
||||
|
||||
@@ -345,7 +345,7 @@
|
||||
splits: {
|
||||
title: "Prompt splits",
|
||||
sub: "Markers that cut one written prompt into separate scenes.",
|
||||
open: () => window.Composer?.open?.(),
|
||||
open: () => { if (!window.Composer?.isOpen?.()) window.Composer?.toggle?.(); },
|
||||
},
|
||||
};
|
||||
const list = el("div", "oo-rows");
|
||||
@@ -359,7 +359,10 @@
|
||||
row.append(main);
|
||||
const b = el("button", "oo-btn oo-btn-small", "Set up");
|
||||
b.type = "button";
|
||||
b.onclick = () => { save(); close(); r.open(); };
|
||||
// The pane opens OVER the wizard; closing it puts you back on this step with
|
||||
// Skip/Continue still there. Closing the wizard here dropped you into the
|
||||
// editor half-set-up.
|
||||
b.onclick = () => { save(); r.open(); };
|
||||
row.append(b);
|
||||
list.append(row);
|
||||
});
|
||||
|
||||
@@ -293,6 +293,9 @@ button, input, select, textarea { font-family: inherit; color: var(--text); }
|
||||
.brand { font-family: var(--font-display); font-weight: 800; letter-spacing: .2px; font-size: 16px; display: flex; align-items: center; gap: 8px; }
|
||||
.brand-mark { color: var(--accent); font-size: 12px; transform: translateY(-1px); filter: drop-shadow(0 0 6px var(--accent-soft)); }
|
||||
.brand-sub { color: var(--faint); font-weight: 500; font-size: 12px; letter-spacing: 2px; text-transform: uppercase; }
|
||||
/* The brand is a link back to the hub in both frontends. */
|
||||
a.brand { text-decoration: none; color: inherit; }
|
||||
a.brand:hover .brand-sub { color: var(--accent-hi); }
|
||||
|
||||
.menus { display: flex; gap: 2px; }
|
||||
.menu { position: relative; }
|
||||
@@ -2153,7 +2156,11 @@ body.tour-mode { overflow: hidden; }
|
||||
}
|
||||
|
||||
.oo-root {
|
||||
position: fixed; inset: 0; z-index: 800;
|
||||
/* Below .modal-overlay (500) and .fw (4000) on purpose: Models, Settings and the
|
||||
Composer open OVER the wizard the same way they open over the editor, and closing
|
||||
one puts you back on the step you left. Above the menubar (200/300) so the editor
|
||||
chrome behind stays covered. */
|
||||
position: fixed; inset: 0; z-index: 400;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
padding: 72px 32px;
|
||||
background:
|
||||
|
||||
@@ -493,11 +493,29 @@ def test_h3_family_drops_the_ltx_only_core_nodes():
|
||||
# LTXVAudioVAEDecode reads an output_sample_rate H3's audio VAE does not define
|
||||
assert "LTXVAudioVAEDecode" not in classes
|
||||
assert "VAEDecodeAudio" in classes
|
||||
# LTXFloatToInt only converted the project's frame rate for user slots. H3's rate is
|
||||
# fixed at 24 by the model, so keeping it made an LTX pack a hard requirement of a
|
||||
# pipeline that has no use for it.
|
||||
assert "LTXFloatToInt" not in classes
|
||||
# the shared half is untouched
|
||||
assert {"FunPackStudio", "FunPackLTXAVSceneChainSampler", "LTXVSeparateAVLatent"} <= classes
|
||||
assert not report["blocking"], report["blocking"]
|
||||
|
||||
|
||||
def test_h3_does_not_offer_the_dropped_frame_rate_converter_as_a_producer():
|
||||
"""A dropped core node must not be auto-wired into a slot that wants an INT."""
|
||||
models = dict(H3_MODELS)
|
||||
models["slots"] = H3_MODELS["slots"] + [
|
||||
{"id": "ip", "role": "image_processing", "node_class": "IntEater", "label": "eats an int"},
|
||||
]
|
||||
oi = dict(H3_OI)
|
||||
oi["IntEater"] = {"input": {"required": {"n": ["INT", {"default": 0}]}}, "output": ["IMAGE"]}
|
||||
graph, _report = builder.build(oi, models, {"prompt": "a shot"})
|
||||
for node in graph.values():
|
||||
for value in node["inputs"].values():
|
||||
assert not (isinstance(value, list) and value and value[0] == "f2i"), value
|
||||
|
||||
|
||||
def test_h3_wires_studio_conditioning_straight_to_the_sampler():
|
||||
graph, _ = builder.build(H3_OI, H3_MODELS, {"prompt": "a shot"})
|
||||
sampler = graph["sampler"]["inputs"]
|
||||
|
||||
Reference in New Issue
Block a user