Publish snapshot: image editor suite, Krea 2 templates, sidebar fixes
- Image editor: layers with masks/blend modes, lightweight groups, Camera Raw scoped to the selected layer, full-frame i2i, Copy Merged, Photoshop keyboard shortcuts, and a large batch of Photoshop-parity bug fixes. - LoadImage right-click "Open in PromptChain editor" bridge (edit -> lineage child re-pointed onto the node). - Krea 2 Turbo/Realism templates and editor modal integration; remove the krea2 Text-to-Image 3D Regional template. - ControlNet depth + 3D-pose: wire Poser true-depth straight into Apply ControlNet on pose paths. - Sidebar: drag-to-LoadImage now uploads to the input root so the widget value is a valid bare filename; "Copy as path" emits native Windows backslashes. - Contributor/relicensing docs and packaging tweaks.
This commit is contained in:
@@ -7,6 +7,10 @@
|
||||
# dev test harnesses
|
||||
tests/
|
||||
|
||||
# GitHub repo metadata (PR template etc.) — only meaningful on GitHub, not in an
|
||||
# installed pack. CONTRIBUTING.md is kept so the contributor terms ship with it.
|
||||
.github/
|
||||
|
||||
# comfy-node-publish build artifact
|
||||
node.zip
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
> **By opening this pull request, I agree to the terms in
|
||||
> [CONTRIBUTING.md](../CONTRIBUTING.md)** — including the grant that lets the
|
||||
> maintainer relicense my contribution (for example, under the MIT License).
|
||||
|
||||
<!-- The line above is the contributor agreement; please leave it in place. -->
|
||||
|
||||
## What does this PR do?
|
||||
|
||||
|
||||
## Related issues
|
||||
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] I have read and agree to [CONTRIBUTING.md](../CONTRIBUTING.md).
|
||||
@@ -0,0 +1,41 @@
|
||||
# Contributing to PromptChain
|
||||
|
||||
Thanks for your interest in contributing! PromptChain is licensed under the
|
||||
[GNU AGPL-3.0](LICENSE), and it stays that way. The terms below let the project
|
||||
keep that license today while preserving the maintainer's option to relicense
|
||||
later (for example, to a permissive license such as MIT). Please read them
|
||||
before opening a pull request.
|
||||
|
||||
## Contributor terms
|
||||
|
||||
By submitting a contribution to this project — a pull request, patch, or any
|
||||
other change — you agree that:
|
||||
|
||||
1. **License.** Your contribution is licensed to the project and its users
|
||||
under the project's current license, the GNU AGPL-3.0.
|
||||
|
||||
2. **Relicensing grant.** In consideration of the project reviewing, merging,
|
||||
and maintaining your contribution, you also grant the project maintainer
|
||||
(mobcat40) and their successors and assigns a perpetual, worldwide,
|
||||
irrevocable, non-exclusive, royalty-free, sublicensable right to use,
|
||||
reproduce, modify, prepare derivative works of, publicly display and perform,
|
||||
distribute, and relicense your contribution under any license — including
|
||||
permissive licenses such as the MIT License — as part of this project or any
|
||||
future version or derivative of it. This grant does not revoke the AGPL-3.0
|
||||
license in point 1; it adds the maintainer's ability to also distribute your
|
||||
contribution under other terms.
|
||||
|
||||
3. **Right to contribute.** The contribution is your own original work (or you
|
||||
otherwise have the right to submit it), and you have the legal right to make
|
||||
the contribution and to grant the rights above. If your employer has any
|
||||
rights to your contribution, you confirm you have permission to submit it
|
||||
under these terms (or your employer has waived those rights).
|
||||
|
||||
4. **No warranty.** Unless required by law or agreed in writing, you provide
|
||||
your contribution on an "AS IS" basis, without warranties or conditions of
|
||||
any kind, express or implied.
|
||||
|
||||
If you do not agree to these terms, please do not submit a contribution.
|
||||
|
||||
These terms apply to contributions submitted after these terms were added to
|
||||
the project. Opening a pull request is taken as your agreement to them.
|
||||
@@ -112,6 +112,10 @@ Add the **Prompt Chain** node from the node menu, and onboarding takes it from t
|
||||
| Prompt Chain Background Mask (Depth) | Depth-based background mask for bokeh-preserving upscales |
|
||||
| Prompt Chain OpenPose / Depth Anything / Canny / Tile / Luminance / Scribble / Soft Edge / Line Art | Bundled, license-clean ControlNet image preprocessors |
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome. By opening a pull request you agree to the terms in [CONTRIBUTING.md](CONTRIBUTING.md), which keep PromptChain on AGPL-3.0 today while preserving the maintainer's option to relicense contributions (for example, to MIT) in the future.
|
||||
|
||||
## License
|
||||
|
||||
[AGPL-3.0](LICENSE). © 2026 mobcat40. If you run a modified PromptChain as part of a hosted service, you must offer your users the modified source.
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,43 @@
|
||||
# Relicensing checklist (maintainer)
|
||||
|
||||
PromptChain ships under [AGPL-3.0](../LICENSE). This note records what must be
|
||||
true to relicense the project — or a future version — under a permissive license
|
||||
such as MIT. It is a maintainer reference, not part of the contributor terms.
|
||||
|
||||
Two independent things must **both** hold. The contributor grant only handles
|
||||
the first; the second is on you regardless of any contributor terms.
|
||||
|
||||
## 1. Every contributor's code is relicensable
|
||||
|
||||
- Outside contributions are covered by the relicensing grant in
|
||||
[CONTRIBUTING.md](../CONTRIBUTING.md) **only if** they were submitted after
|
||||
that file existed and the contributor accepted the terms (by opening a PR).
|
||||
- **Invariant:** no outside contribution may predate the CONTRIBUTING.md commit.
|
||||
History is currently 100% single-author (mobcat40), so this holds. If it ever
|
||||
stops holding, get an explicit written grant from that author before
|
||||
relicensing — the grant cannot reach backwards.
|
||||
- The grant is a *license*, not an assignment: contributors keep copyright, and
|
||||
the AGPL availability of already-published versions cannot be withdrawn. That
|
||||
does not block offering *future* versions under MIT.
|
||||
- Route all outside contributions through PRs so the assent trigger always
|
||||
fires. A DCO ("Signed-off-by") is **not** a substitute — it certifies origin,
|
||||
not a relicensing right.
|
||||
- Strongest hardening, cheapest before outside PRs arrive: enable **CLA
|
||||
Assistant** as a required status check, so each contributor's grant is backed
|
||||
by a recorded, identity-bound signature rather than only the PR-template line.
|
||||
|
||||
## 2. Every bundled / vendored third-party component is MIT-compatible
|
||||
|
||||
The contributor grant covers only what contributors submit — it does nothing for
|
||||
third-party code the project incorporates. A whole-project MIT relicense
|
||||
additionally requires that **every** copyrightable component be MIT-compatible.
|
||||
|
||||
- Copyleft third-party code (GPL / AGPL / LGPL source) **cannot** be relicensed
|
||||
to MIT. Keep it as an *external dependency* loaded at runtime, not vendored
|
||||
into this tree. Vendoring a copyleft node pack's source would block a clean
|
||||
MIT relicense — watch this when doing full-install / vendoring work.
|
||||
- Permissive third-party code (MIT / BSD / Apache-2.0) may be included, but its
|
||||
own license notices and attribution must be retained. The result is then
|
||||
"MIT project + retained third-party notices," not a single bare MIT file.
|
||||
- Before relicensing, inventory `bundled_packs/`, `vendor/`, and
|
||||
`requirements.txt` and confirm each component's license.
|
||||
@@ -108,12 +108,15 @@ async function handleDrop(e) {
|
||||
if (!fetchResponse.ok) throw new Error(`Failed to fetch: ${fetchResponse.status}`);
|
||||
const blob = await fetchResponse.blob();
|
||||
|
||||
// upload to ComfyUI's input folder
|
||||
// Upload into the input ROOT, not a subfolder. Stock LoadImage's INPUT_TYPES
|
||||
// only enumerates top-level input files, so a "subfolder/name" combo value is
|
||||
// never in its option list — the node loads flagged/errored even though the
|
||||
// backend's VALIDATE_INPUTS (exists_annotated_filepath) still finds the file
|
||||
// and the graph runs. A bare filename keeps the combo valid.
|
||||
const filename = assetData.path.split("/").pop();
|
||||
const file = new File([blob], filename, { type: blob.type });
|
||||
const formData = new FormData();
|
||||
formData.append("image", file);
|
||||
formData.append("subfolder", "promptchain_assets");
|
||||
formData.append("type", "input");
|
||||
formData.append("overwrite", "true");
|
||||
const uploadResponse = await api.fetchApi("/upload/image", { method: "POST", body: formData });
|
||||
|
||||
@@ -1816,9 +1816,10 @@ function injectControlNet(pcNode, controlType) {
|
||||
if (!graph) return false;
|
||||
const LG = window.LiteGraph || graph.constructor?.LiteGraph;
|
||||
if (!LG) return false;
|
||||
// "depth-pose" is the depth branch with a Pose Studio figure as the image
|
||||
// source instead of a LoadImage — the rendered figure goes THROUGH
|
||||
// DepthAnything just like an uploaded photo would.
|
||||
// "depth-pose" is the depth branch sourced from a 3D Poser figure instead of a
|
||||
// LoadImage. The Poser renders its OWN true geometric depth, so it wires straight
|
||||
// into Apply ControlNet — no DepthAnything estimator (that exists only for the
|
||||
// uploaded-image branches, which have no scene geometry to read).
|
||||
const usePose = controlType === "depth-pose";
|
||||
const cfg = CONTROLNET_TYPES[usePose ? "depth" : controlType];
|
||||
if (!cfg) return false;
|
||||
@@ -1838,12 +1839,16 @@ function injectControlNet(pcNode, controlType) {
|
||||
if (!posSrc?.node || !negSrc?.node) return false;
|
||||
|
||||
// Image source: a shared LoadImage (uploaded reference) reused across stacked
|
||||
// branches — or, for "depth + 3D pose", a Pose Studio node whose rendered figure
|
||||
// feeds the depth preprocessor. Pose nodes aren't shared (one figure per branch).
|
||||
// branches — or, for "depth + 3D pose", a Pose Studio node whose true-depth
|
||||
// render IS the control map. Pose nodes aren't shared (one figure per branch).
|
||||
let loadImage = null, newLoadImage = false, poseNode = null;
|
||||
if (usePose) {
|
||||
poseNode = LG.createNode("PromptChain_PoseStudio");
|
||||
if (!poseNode) return false;
|
||||
// Switch the Poser to true geometric depth before its mount seeds the first
|
||||
// capture (read live from pcrOutputMode) — the default disparity curve matches
|
||||
// what the depth ControlNets were trained on.
|
||||
poseNode.properties = { ...(poseNode.properties || {}), pcrOutputMode: "depth", pcrTrueDepth: true };
|
||||
} else {
|
||||
loadImage = graph._nodes?.find(n => n.comfyClass === "LoadImage" && n.title === "ControlNet Reference");
|
||||
newLoadImage = !loadImage;
|
||||
@@ -1851,12 +1856,13 @@ function injectControlNet(pcNode, controlType) {
|
||||
}
|
||||
const sourceNode = poseNode || loadImage;
|
||||
|
||||
const preNode = LG.createNode(resolvePre(cfg.pre));
|
||||
// Pose-direct depth needs no preprocessor — the Poser's IMAGE already IS the map.
|
||||
const preNode = usePose ? null : LG.createNode(resolvePre(cfg.pre));
|
||||
const loaderNode = LG.createNode("ControlNetLoader");
|
||||
const applyNode = LG.createNode("ControlNetApplyAdvanced");
|
||||
const setUnion = cfg.unionType ? LG.createNode("SetUnionControlNetType") : null;
|
||||
const preview = LG.createNode("PreviewImage");
|
||||
if (!preNode || !loaderNode || !applyNode) return false;
|
||||
if ((!usePose && !preNode) || !loaderNode || !applyNode) return false;
|
||||
if (cfg.unionType && !setUnion) return false;
|
||||
|
||||
// Layout mirrors the hand-arranged reference (janku-depth-3): the cluster
|
||||
@@ -1869,7 +1875,7 @@ function injectControlNet(pcNode, controlType) {
|
||||
// Loader sits just below the preprocessor, whose height varies a lot by type
|
||||
// (pose tallest, scribble shortest) — derive from the live node height so one
|
||||
// rule fits all controls. SetUnion is 150 below the loader.
|
||||
const preH = preNode.size?.[1] || 130;
|
||||
const preH = preNode?.size?.[1] || 130;
|
||||
const loaderY = preH + 65;
|
||||
const setUnionY = loaderY + 150;
|
||||
if (poseNode) {
|
||||
@@ -1882,12 +1888,12 @@ function injectControlNet(pcNode, controlType) {
|
||||
graph.add(loadImage);
|
||||
loadImage.size = [250, 340];
|
||||
}
|
||||
preNode.pos = [baseX - 643, baseY + dy];
|
||||
if (preNode) preNode.pos = [baseX - 643, baseY + dy];
|
||||
loaderNode.pos = [baseX - 633, baseY + loaderY + dy];
|
||||
if (setUnion) setUnion.pos = [baseX - 633, baseY + setUnionY + dy];
|
||||
applyNode.pos = [baseX - 313, baseY + dy];
|
||||
if (preview) preview.pos = [baseX - 933, baseY + dy];
|
||||
graph.add(preNode);
|
||||
if (preNode) graph.add(preNode);
|
||||
graph.add(loaderNode);
|
||||
if (setUnion) graph.add(setUnion);
|
||||
graph.add(applyNode);
|
||||
@@ -1895,7 +1901,7 @@ function injectControlNet(pcNode, controlType) {
|
||||
// Sizes set after add so the litegraph size setter runs on a registered node.
|
||||
// Preprocessor: fix width, keep its auto height (varies by widget count —
|
||||
// canny has more rows than depth).
|
||||
preNode.size = [291, preNode.size?.[1] ?? 130];
|
||||
if (preNode) preNode.size = [291, preNode.size?.[1] ?? 130];
|
||||
loaderNode.size = [270, 83];
|
||||
if (setUnion) setUnion.size = [270, 83];
|
||||
applyNode.size = [270, 240];
|
||||
@@ -1917,15 +1923,22 @@ function injectControlNet(pcNode, controlType) {
|
||||
else if (w.name === "start_percent") { w.value = 0.0; w.callback?.(0.0); }
|
||||
else if (w.name === "end_percent") { w.value = cfg.end; w.callback?.(cfg.end); }
|
||||
}
|
||||
for (const w of preNode.widgets || []) {
|
||||
for (const w of preNode?.widgets || []) {
|
||||
if (w.name === "resolution") { w.value = 1024; w.callback?.(1024); }
|
||||
// DWPose ships a toggle specifically for xinsir ControlNet stick scaling.
|
||||
else if (w.name === "scale_stick_for_xinsr_cn") { w.value = "enable"; w.callback?.("enable"); }
|
||||
}
|
||||
|
||||
sourceNode.connect(0, preNode, preNode.inputs?.findIndex(i => i.name === "image") ?? 0);
|
||||
preNode.connect(0, applyNode, applyNode.inputs?.findIndex(i => i.name === "image") ?? 3);
|
||||
if (preview) preNode.connect(0, preview, 0); // show the preprocessed map
|
||||
const applyImageIdx = applyNode.inputs?.findIndex(i => i.name === "image") ?? 3;
|
||||
if (preNode) {
|
||||
sourceNode.connect(0, preNode, preNode.inputs?.findIndex(i => i.name === "image") ?? 0);
|
||||
preNode.connect(0, applyNode, applyImageIdx);
|
||||
if (preview) preNode.connect(0, preview, 0); // show the preprocessed map
|
||||
} else {
|
||||
// Pose-direct: the Poser's true-depth IMAGE is the control map itself.
|
||||
sourceNode.connect(0, applyNode, applyImageIdx);
|
||||
if (preview) sourceNode.connect(0, preview, 0); // the depth-map flash
|
||||
}
|
||||
if (setUnion) {
|
||||
loaderNode.connect(0, setUnion, 0);
|
||||
setUnion.connect(0, applyNode, applyNode.inputs?.findIndex(i => i.name === "control_net") ?? 2);
|
||||
@@ -2344,7 +2357,11 @@ function injectFluxControlNet(pcNode, controlType) {
|
||||
if (!graph) return false;
|
||||
const LG = window.LiteGraph || graph.constructor?.LiteGraph;
|
||||
if (!LG) return false;
|
||||
const cfg = FLUX_CONTROLNET_TYPES[controlType];
|
||||
// "depth-pose" = the depth branch sourced from a 3D Poser figure (true geometric
|
||||
// depth) instead of a LoadImage — wired straight into Apply ControlNet.
|
||||
const usePose = controlType === "depth-pose";
|
||||
const baseControl = usePose ? "depth" : controlType;
|
||||
const cfg = FLUX_CONTROLNET_TYPES[baseControl];
|
||||
if (!cfg) return false;
|
||||
|
||||
const downstream = findDownstreamNodes(pcNode);
|
||||
@@ -2373,47 +2390,62 @@ function injectFluxControlNet(pcNode, controlType) {
|
||||
}
|
||||
}
|
||||
|
||||
// Reuse one shared reference image across stacked branches.
|
||||
let loadImage = graph._nodes?.find(n => n.comfyClass === "LoadImage" && n.title === "ControlNet Reference");
|
||||
const newLoadImage = !loadImage;
|
||||
if (!loadImage) loadImage = LG.createNode("LoadImage");
|
||||
// Image source: a 3D Poser figure (depth + 3D pose) whose true-depth render IS
|
||||
// the control map — or a shared LoadImage reference reused across stacked branches.
|
||||
let loadImage = null, newLoadImage = false, poseNode = null;
|
||||
if (usePose) {
|
||||
poseNode = LG.createNode("PromptChain_PoseStudio");
|
||||
if (!poseNode) return false;
|
||||
// True geometric depth, set before its mount seeds the first capture.
|
||||
poseNode.properties = { ...(poseNode.properties || {}), pcrOutputMode: "depth", pcrTrueDepth: true };
|
||||
} else {
|
||||
loadImage = graph._nodes?.find(n => n.comfyClass === "LoadImage" && n.title === "ControlNet Reference");
|
||||
newLoadImage = !loadImage;
|
||||
if (!loadImage) loadImage = LG.createNode("LoadImage");
|
||||
}
|
||||
const sourceNode = poseNode || loadImage;
|
||||
|
||||
const preNode = LG.createNode(resolvePre(cfg.pre));
|
||||
// Pose-direct depth needs no preprocessor — the Poser's IMAGE already IS the map.
|
||||
const preNode = usePose ? null : LG.createNode(resolvePre(cfg.pre));
|
||||
const loaderNode = LG.createNode("ControlNetLoader");
|
||||
const applyNode = LG.createNode("ControlNetApplyAdvanced");
|
||||
const preview = LG.createNode("PreviewImage");
|
||||
if (!preNode || !loaderNode || !applyNode) return false;
|
||||
if ((!usePose && !preNode) || !loaderNode || !applyNode) return false;
|
||||
|
||||
// Same left-of-node layout as the SDXL cluster, minus the SetUnion node.
|
||||
const existingApplies = downstream.filter(n => n.comfyClass === "ControlNetApplyAdvanced").length;
|
||||
const baseX = pcNode.pos?.[0] ?? 0;
|
||||
const baseY = pcNode.pos?.[1] ?? 0;
|
||||
const dy = existingApplies * 660;
|
||||
const preH = preNode.size?.[1] || 130;
|
||||
const preH = preNode?.size?.[1] || 130;
|
||||
const loaderY = preH + 65;
|
||||
if (newLoadImage) {
|
||||
if (poseNode) {
|
||||
poseNode.pos = [baseX - 1383, baseY + dy];
|
||||
graph.add(poseNode);
|
||||
poseNode.size = [360, 470];
|
||||
} else if (newLoadImage) {
|
||||
loadImage.title = "ControlNet Reference";
|
||||
loadImage.pos = [baseX - 1223, baseY];
|
||||
graph.add(loadImage);
|
||||
loadImage.size = [250, 340];
|
||||
}
|
||||
preNode.pos = [baseX - 643, baseY + dy];
|
||||
if (preNode) preNode.pos = [baseX - 643, baseY + dy];
|
||||
loaderNode.pos = [baseX - 633, baseY + loaderY + dy];
|
||||
applyNode.pos = [baseX - 313, baseY + dy];
|
||||
if (preview) preview.pos = [baseX - 933, baseY + dy];
|
||||
graph.add(preNode);
|
||||
if (preNode) graph.add(preNode);
|
||||
graph.add(loaderNode);
|
||||
graph.add(applyNode);
|
||||
if (preview) graph.add(preview);
|
||||
preNode.size = [291, preNode.size?.[1] ?? 130];
|
||||
if (preNode) preNode.size = [291, preNode.size?.[1] ?? 130];
|
||||
loaderNode.size = [270, 83];
|
||||
applyNode.size = [270, 240];
|
||||
if (preview) preview.size = [250, 360];
|
||||
|
||||
// Flux branches carry a "flux-" prefixed control type so their settings
|
||||
// sections + recommended markers stay distinct from the SDXL defaults.
|
||||
const settingsType = `flux-${controlType}`;
|
||||
applyNode.title = `ControlNet — ${CN_LABELS[settingsType] || controlType}`;
|
||||
const settingsType = `flux-${baseControl}`;
|
||||
applyNode.title = `ControlNet — ${usePose ? "Depth (pose)" : (CN_LABELS[settingsType] || controlType)}`;
|
||||
applyNode.properties = { ...(applyNode.properties || {}), pcrControlType: settingsType };
|
||||
|
||||
setControlNetModel(loaderNode, "fluxunion");
|
||||
@@ -2422,13 +2454,20 @@ function injectFluxControlNet(pcNode, controlType) {
|
||||
else if (w.name === "start_percent") { w.value = 0.0; w.callback?.(0.0); }
|
||||
else if (w.name === "end_percent") { w.value = cfg.end; w.callback?.(cfg.end); }
|
||||
}
|
||||
for (const w of preNode.widgets || []) {
|
||||
for (const w of preNode?.widgets || []) {
|
||||
if (w.name === "resolution") { w.value = 1024; w.callback?.(1024); }
|
||||
}
|
||||
|
||||
loadImage.connect(0, preNode, preNode.inputs?.findIndex(i => i.name === "image") ?? 0);
|
||||
preNode.connect(0, applyNode, applyNode.inputs?.findIndex(i => i.name === "image") ?? 3);
|
||||
if (preview) preNode.connect(0, preview, 0);
|
||||
const applyImageIdx = applyNode.inputs?.findIndex(i => i.name === "image") ?? 3;
|
||||
if (preNode) {
|
||||
sourceNode.connect(0, preNode, preNode.inputs?.findIndex(i => i.name === "image") ?? 0);
|
||||
preNode.connect(0, applyNode, applyImageIdx);
|
||||
if (preview) preNode.connect(0, preview, 0);
|
||||
} else {
|
||||
// Pose-direct: the Poser's true-depth IMAGE is the control map itself.
|
||||
sourceNode.connect(0, applyNode, applyImageIdx);
|
||||
if (preview) sourceNode.connect(0, preview, 0);
|
||||
}
|
||||
loaderNode.connect(0, applyNode, applyNode.inputs?.findIndex(i => i.name === "control_net") ?? 2);
|
||||
if (vaeSrc?.node) {
|
||||
const vaeIdx = applyNode.inputs?.findIndex(i => i.name === "vae") ?? -1;
|
||||
@@ -2452,9 +2491,10 @@ function injectZImageControlNet(pcNode, controlType, isBase = false) {
|
||||
if (!graph) return false;
|
||||
const LG = window.LiteGraph || graph.constructor?.LiteGraph;
|
||||
if (!LG) return false;
|
||||
// "depth-pose" = the depth branch driven by a 3D Poser figure instead of a
|
||||
// LoadImage — the rendered figure goes THROUGH the depth preprocessor, and its
|
||||
// MASKS/POSE outputs are what a follow-up Regional inject binds to.
|
||||
// "depth-pose" = the depth branch sourced from a 3D Poser figure instead of a
|
||||
// LoadImage. The Poser emits its own true geometric depth, so it wires straight
|
||||
// into ZImageFunControlnet (no DepthAnything); its MASKS/POSE outputs are what a
|
||||
// follow-up Regional inject binds to.
|
||||
const usePose = controlType === "depth-pose";
|
||||
const baseControl = usePose ? "depth" : controlType;
|
||||
const cfg = ZIMAGE_CONTROLNET_TYPES[baseControl];
|
||||
@@ -2487,6 +2527,9 @@ function injectZImageControlNet(pcNode, controlType, isBase = false) {
|
||||
if (usePose) {
|
||||
poseNode = LG.createNode("PromptChain_PoseStudio");
|
||||
if (!poseNode) return false;
|
||||
// Poser emits its own true geometric depth → straight into ZImageFunControlnet,
|
||||
// no DepthAnything re-estimation. Set before its mount seeds the first capture.
|
||||
poseNode.properties = { ...(poseNode.properties || {}), pcrOutputMode: "depth", pcrTrueDepth: true };
|
||||
} else {
|
||||
loadImage = graph._nodes?.find(n => n.comfyClass === "LoadImage" && n.title === "ControlNet Reference");
|
||||
newLoadImage = !loadImage;
|
||||
@@ -2494,17 +2537,18 @@ function injectZImageControlNet(pcNode, controlType, isBase = false) {
|
||||
}
|
||||
const sourceNode = poseNode || loadImage;
|
||||
|
||||
const preNode = LG.createNode(resolvePre(cfg.pre));
|
||||
// Pose-direct depth needs no preprocessor — the Poser's IMAGE already IS the map.
|
||||
const preNode = usePose ? null : LG.createNode(resolvePre(cfg.pre));
|
||||
const patchLoader = LG.createNode("ModelPatchLoader");
|
||||
const zcnNode = LG.createNode("ZImageFunControlnet");
|
||||
const preview = LG.createNode("PreviewImage");
|
||||
if (!preNode || !patchLoader || !zcnNode) return false;
|
||||
if ((!usePose && !preNode) || !patchLoader || !zcnNode) return false;
|
||||
|
||||
const existing = downstream.filter(n => n.comfyClass === "ZImageFunControlnet").length;
|
||||
const baseX = pcNode.pos?.[0] ?? 0;
|
||||
const baseY = pcNode.pos?.[1] ?? 0;
|
||||
const dy = existing * 660;
|
||||
const preH = preNode.size?.[1] || 130;
|
||||
const preH = preNode?.size?.[1] || 130;
|
||||
const loaderY = preH + 65;
|
||||
if (poseNode) {
|
||||
poseNode.pos = [baseX - 1383, baseY + dy];
|
||||
@@ -2516,15 +2560,15 @@ function injectZImageControlNet(pcNode, controlType, isBase = false) {
|
||||
graph.add(loadImage);
|
||||
loadImage.size = [250, 340];
|
||||
}
|
||||
preNode.pos = [baseX - 643, baseY + dy];
|
||||
if (preNode) preNode.pos = [baseX - 643, baseY + dy];
|
||||
patchLoader.pos = [baseX - 633, baseY + loaderY + dy];
|
||||
zcnNode.pos = [baseX - 313, baseY + dy];
|
||||
if (preview) preview.pos = [baseX - 933, baseY + dy];
|
||||
graph.add(preNode);
|
||||
if (preNode) graph.add(preNode);
|
||||
graph.add(patchLoader);
|
||||
graph.add(zcnNode);
|
||||
if (preview) graph.add(preview);
|
||||
preNode.size = [291, preNode.size?.[1] ?? 130];
|
||||
if (preNode) preNode.size = [291, preNode.size?.[1] ?? 130];
|
||||
patchLoader.size = [270, 58];
|
||||
zcnNode.size = [270, 130];
|
||||
if (preview) preview.size = [250, 360];
|
||||
@@ -2549,13 +2593,20 @@ function injectZImageControlNet(pcNode, controlType, isBase = false) {
|
||||
for (const w of zcnNode.widgets || []) {
|
||||
if (w.name === "strength") { w.value = cfg.strength; w.callback?.(cfg.strength); }
|
||||
}
|
||||
for (const w of preNode.widgets || []) {
|
||||
for (const w of preNode?.widgets || []) {
|
||||
if (w.name === "resolution") { w.value = 1024; w.callback?.(1024); }
|
||||
}
|
||||
|
||||
sourceNode.connect(0, preNode, preNode.inputs?.findIndex(i => i.name === "image") ?? 0);
|
||||
preNode.connect(0, zcnNode, zcnNode.inputs?.findIndex(i => i.name === "image") ?? -1);
|
||||
if (preview) preNode.connect(0, preview, 0);
|
||||
const zcnImageIdx = zcnNode.inputs?.findIndex(i => i.name === "image") ?? -1;
|
||||
if (preNode) {
|
||||
sourceNode.connect(0, preNode, preNode.inputs?.findIndex(i => i.name === "image") ?? 0);
|
||||
preNode.connect(0, zcnNode, zcnImageIdx);
|
||||
if (preview) preNode.connect(0, preview, 0);
|
||||
} else {
|
||||
// Pose-direct: the Poser's true-depth IMAGE feeds the Z-Image control patch.
|
||||
sourceNode.connect(0, zcnNode, zcnImageIdx);
|
||||
if (preview) sourceNode.connect(0, preview, 0);
|
||||
}
|
||||
patchLoader.connect(0, zcnNode, zcnNode.inputs?.findIndex(i => i.name === "model_patch") ?? 1);
|
||||
if (vaeSrc?.node) vaeSrc.node.connect(vaeSrc.slot, zcnNode, zcnNode.inputs?.findIndex(i => i.name === "vae") ?? 2);
|
||||
// Model line: source → ZImageFunControlnet → sampler.
|
||||
@@ -3049,6 +3100,7 @@ export async function showModelModal(pcNode, modelInfo, anchorEl, { tab = null }
|
||||
label: "ControlNet",
|
||||
children: [
|
||||
{ label: "Depth", value: "FluxControlNet:depth" },
|
||||
{ label: "Depth + 3D pose", value: "FluxControlNet:depth-pose" },
|
||||
{ label: "Canny", value: "FluxControlNet:canny" },
|
||||
{ label: "Pose", value: "FluxControlNet:pose" },
|
||||
{ label: "Soft Edge", value: "FluxControlNet:softedge" },
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { d as delegate, p as push, a as prop, u as user_effect, D as comment, v as first_child, i as if_block, k as append, l as pop, g as get, s as state, f as sibling, o as bind_this, e as set, t as template_effect, y as set_text, j as delegated, A as from_html, n as child } from "./disclose-version-uq4tn5Y6.js";
|
||||
import { a as action } from "./actions-WPfqiWYB.js";
|
||||
import { d as delegate, p as push, a as prop, u as user_effect, D as comment, v as first_child, i as if_block, k as append, l as pop, g as get, s as state, f as sibling, o as bind_this, e as set, t as template_effect, y as set_text, j as delegated, A as from_html, n as child } from "./disclose-version-et9wt-4m.js";
|
||||
import { a as action } from "./actions-zjmT0mOr.js";
|
||||
function portal(node) {
|
||||
document.body.appendChild(node);
|
||||
return { destroy() {
|
||||
@@ -87,4 +87,4 @@ export {
|
||||
ConfirmModal as C,
|
||||
portal as p
|
||||
};
|
||||
//# sourceMappingURL=ConfirmModal-BGcVYndw.js.map
|
||||
//# sourceMappingURL=ConfirmModal-CtR7InHn.js.map
|
||||
+5
-5
@@ -1,9 +1,9 @@
|
||||
import { d as delegate, p as push, a as prop, u as user_effect, i as if_block, g as get, o as bind_this, t as template_effect, k as append, l as pop, m as user_derived, n as child, v as first_child, f as sibling, j as delegated, r as event, A as from_html, s as state, y as set_text, w as each, h as set_class, z as index, e as set, c as proxy, C as tick, x as set_attribute, D as comment } from "./disclose-version-uq4tn5Y6.js";
|
||||
import { s as set_style } from "./style-Boi27oOu.js";
|
||||
import { d as delegate, p as push, a as prop, u as user_effect, i as if_block, g as get, o as bind_this, t as template_effect, k as append, l as pop, m as user_derived, n as child, v as first_child, f as sibling, j as delegated, r as event, A as from_html, s as state, y as set_text, w as each, h as set_class, z as index, e as set, c as proxy, C as tick, x as set_attribute, D as comment } from "./disclose-version-et9wt-4m.js";
|
||||
import { s as set_style } from "./style-B3hsaAru.js";
|
||||
import { app } from "/scripts/app.js";
|
||||
import { j as justifiedLayout } from "./justified-layout-cyVM7i96.js";
|
||||
import { a as action } from "./actions-WPfqiWYB.js";
|
||||
import { p as portal, C as ConfirmModal } from "./ConfirmModal-BGcVYndw.js";
|
||||
import { a as action } from "./actions-zjmT0mOr.js";
|
||||
import { p as portal, C as ConfirmModal } from "./ConfirmModal-CtR7InHn.js";
|
||||
const GALLERY_ROW_HEIGHT_MIN = 40;
|
||||
const GALLERY_ROW_HEIGHT_MAX = 400;
|
||||
const ZOOM_FACTOR = 1.15;
|
||||
@@ -801,4 +801,4 @@ export {
|
||||
clampGalleryRowHeight as c,
|
||||
zoomGalleryRowHeight as z
|
||||
};
|
||||
//# sourceMappingURL=GeneratedGallery-D5XbkMk7.js.map
|
||||
//# sourceMappingURL=GeneratedGallery-DgtlJz3l.js.map
|
||||
@@ -1,10 +1,10 @@
|
||||
import { d as delegate, p as push, a as prop, u as user_effect, g as get, e as set, v as first_child, i as if_block, f as sibling, k as append, l as pop, s as state, m as user_derived, o as bind_this, j as delegated, n as child, D as comment, w as each, z as index, A as from_html, t as template_effect, h as set_class, r as event, y as set_text, x as set_attribute } from "./disclose-version-uq4tn5Y6.js";
|
||||
import { o as onDestroy } from "./index-client-iMRCrpBY.js";
|
||||
import { h as html, P as PopupAnchor } from "./PopupAnchor-C6OWGGTI.js";
|
||||
import { a as action } from "./actions-WPfqiWYB.js";
|
||||
import { s as set_style } from "./style-Boi27oOu.js";
|
||||
import { d as delegate, p as push, a as prop, u as user_effect, g as get, e as set, v as first_child, i as if_block, f as sibling, k as append, l as pop, s as state, m as user_derived, o as bind_this, j as delegated, n as child, D as comment, w as each, z as index, A as from_html, t as template_effect, h as set_class, r as event, y as set_text, x as set_attribute } from "./disclose-version-et9wt-4m.js";
|
||||
import { o as onDestroy } from "./index-client-6amB1qrM.js";
|
||||
import { h as html, P as PopupAnchor } from "./PopupAnchor-D5Lvfjom.js";
|
||||
import { a as action } from "./actions-zjmT0mOr.js";
|
||||
import { s as set_style } from "./style-B3hsaAru.js";
|
||||
import { app } from "/scripts/app.js";
|
||||
import { b as bind_value } from "./input-DFQhebEz.js";
|
||||
import { b as bind_value } from "./input-B9kD0bWJ.js";
|
||||
var root_1$2 = from_html(`<div class="pcr-mode-menu-search-container"><input type="text" class="pcr-mode-menu-search" placeholder="Search options..."/></div> <div class="pcr-mode-menu-separator"></div>`, 1);
|
||||
var root_2$2 = from_html(`<div class="pcr-mode-menu-empty">No matching options</div>`);
|
||||
var root_5$1 = from_html(`<span class="pcr-mode-menu-check"></span>`);
|
||||
@@ -606,4 +606,4 @@ export {
|
||||
Menubar as M,
|
||||
SearchableList as S
|
||||
};
|
||||
//# sourceMappingURL=Menubar-DC12j8gE.js.map
|
||||
//# sourceMappingURL=Menubar-CMm15KuK.js.map
|
||||
@@ -1,5 +1,5 @@
|
||||
import { t as template_effect, S as active_effect, T as assign_nodes, U as get_first_child, V as remove_effect_dom, W as create_element, X as NAMESPACE_SVG, Y as NAMESPACE_MATHML, b as block, Z as EFFECT_TRANSPARENT, B as BranchManager, c as proxy, d as delegate, p as push, a as prop, u as user_effect, o as bind_this, j as delegated, k as append, l as pop, A as from_html, n as child } from "./disclose-version-uq4tn5Y6.js";
|
||||
import { a as onMount, o as onDestroy } from "./index-client-iMRCrpBY.js";
|
||||
import { t as template_effect, S as active_effect, T as assign_nodes, U as get_first_child, V as remove_effect_dom, W as create_element, X as NAMESPACE_SVG, Y as NAMESPACE_MATHML, b as block, Z as EFFECT_TRANSPARENT, B as BranchManager, c as proxy, d as delegate, p as push, a as prop, u as user_effect, o as bind_this, j as delegated, k as append, l as pop, A as from_html, n as child } from "./disclose-version-et9wt-4m.js";
|
||||
import { a as onMount, o as onDestroy } from "./index-client-6amB1qrM.js";
|
||||
function html(node, get_value, is_controlled = false, svg = false, mathml = false, skip_warning = false) {
|
||||
var anchor = node;
|
||||
var value = "";
|
||||
@@ -155,4 +155,4 @@ export {
|
||||
PopupAnchor as P,
|
||||
html as h
|
||||
};
|
||||
//# sourceMappingURL=PopupAnchor-C6OWGGTI.js.map
|
||||
//# sourceMappingURL=PopupAnchor-D5Lvfjom.js.map
|
||||
@@ -1,5 +1,5 @@
|
||||
import { d as delegate, p as push, a as prop, s as state, c as proxy, u as user_effect, e as set, i as if_block, g as get, f as sibling, t as template_effect, x as set_attribute, q as set_value, j as delegated, k as append, l as pop, m as user_derived, n as child, o as bind_this, w as each, h as set_class, y as set_text, z as index, A as from_html } from "./disclose-version-uq4tn5Y6.js";
|
||||
import { s as set_style } from "./style-Boi27oOu.js";
|
||||
import { d as delegate, p as push, a as prop, s as state, c as proxy, u as user_effect, e as set, i as if_block, g as get, f as sibling, t as template_effect, x as set_attribute, q as set_value, j as delegated, k as append, l as pop, m as user_derived, n as child, o as bind_this, w as each, h as set_class, y as set_text, z as index, A as from_html } from "./disclose-version-et9wt-4m.js";
|
||||
import { s as set_style } from "./style-B3hsaAru.js";
|
||||
var root_2 = from_html(`<div class="pcr-slider-zone svelte-nuvs0d"></div>`);
|
||||
var root_3 = from_html(`<div class="pcr-slider-marker svelte-nuvs0d"></div>`);
|
||||
var root_4 = from_html(`<div><span class="pcr-slider-tick-label svelte-nuvs0d"> </span></div>`);
|
||||
@@ -267,4 +267,4 @@ delegate([
|
||||
export {
|
||||
SettingsSlider as S
|
||||
};
|
||||
//# sourceMappingURL=SettingsSlider-CKF_XmgB.js.map
|
||||
//# sourceMappingURL=SettingsSlider-C9Ps16J6.js.map
|
||||
@@ -1,4 +1,4 @@
|
||||
import { a4 as effect, E as untrack, a9 as render_effect, aa as deep_read_state, ab as safe_not_equal } from "./disclose-version-uq4tn5Y6.js";
|
||||
import { a4 as effect, E as untrack, a9 as render_effect, aa as deep_read_state, ab as safe_not_equal } from "./disclose-version-et9wt-4m.js";
|
||||
function action(dom, action2, get_value) {
|
||||
effect(() => {
|
||||
var payload = untrack(() => action2(dom, get_value == null ? void 0 : get_value()) || {});
|
||||
@@ -29,4 +29,4 @@ function action(dom, action2, get_value) {
|
||||
export {
|
||||
action as a
|
||||
};
|
||||
//# sourceMappingURL=actions-WPfqiWYB.js.map
|
||||
//# sourceMappingURL=actions-zjmT0mOr.js.map
|
||||
@@ -1,4 +1,4 @@
|
||||
import { P as setContext, O as getContext } from "./disclose-version-uq4tn5Y6.js";
|
||||
import { P as setContext, O as getContext } from "./disclose-version-et9wt-4m.js";
|
||||
const API_KEY = "pcr-api";
|
||||
function provideApi(api) {
|
||||
setContext(API_KEY, api);
|
||||
@@ -41,4 +41,4 @@ export {
|
||||
safeJson as s,
|
||||
useApi as u
|
||||
};
|
||||
//# sourceMappingURL=api-context-BFKo1mCD.js.map
|
||||
//# sourceMappingURL=api-context-BNqvELYR.js.map
|
||||
@@ -902,6 +902,7 @@
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
padding: 5px 7px; border-radius: 4px; cursor: pointer;
|
||||
background: #1c1c1c; border: 1px solid #2e2e2e;
|
||||
-webkit-user-select: none; user-select: none; /* the name text must not hijack a press-drag */
|
||||
}
|
||||
.pcr-ed-layer-row.svelte-1ozzqkm:hover { border-color: #3d3d3d; }
|
||||
.pcr-ed-layer-row.selected.svelte-1ozzqkm { background: rgba(200, 89, 9, 0.10); border-color: #5a4630; }
|
||||
@@ -919,6 +920,20 @@
|
||||
}
|
||||
.pcr-ed-layer-menu.svelte-1ozzqkm button:where(.svelte-1ozzqkm):hover { background: #c85909; color: #fff; }
|
||||
.pcr-ed-layer-menu.svelte-1ozzqkm button.danger:where(.svelte-1ozzqkm):hover { background: #b23b3b; }
|
||||
.pcr-ed-menu-sep.svelte-1ozzqkm { height: 1px; margin: 4px 6px; background: #3a3a3a; }
|
||||
/* Mask actions collapse into a hover flyout (CSS-only, no timers). The flyout is
|
||||
a DOM descendant of .pcr-ed-layer-menu so the outside-click dismiss still works. */
|
||||
.pcr-ed-submenu-host.svelte-1ozzqkm { position: relative; display: flex; flex-direction: column; }
|
||||
.pcr-ed-submenu-trigger.svelte-1ozzqkm { display: flex; align-items: center; justify-content: space-between; }
|
||||
.pcr-ed-submenu-caret.svelte-1ozzqkm { color: #888; font-size: 11px; margin-left: 8px; }
|
||||
.pcr-ed-submenu.svelte-1ozzqkm {
|
||||
position: absolute; left: 100%; top: -5px; min-width: 160px;
|
||||
background: #232323; border: 1px solid #444; border-radius: 6px; padding: 4px;
|
||||
box-shadow: 0 6px 22px rgba(0, 0, 0, 0.5); display: none; flex-direction: column; z-index: 1;
|
||||
}
|
||||
.pcr-ed-submenu-host.flip.svelte-1ozzqkm .pcr-ed-submenu:where(.svelte-1ozzqkm) { left: auto; right: 100%; }
|
||||
.pcr-ed-submenu-host.svelte-1ozzqkm:hover .pcr-ed-submenu:where(.svelte-1ozzqkm), .pcr-ed-submenu.svelte-1ozzqkm:hover { display: flex; }
|
||||
.pcr-ed-submenu-host.svelte-1ozzqkm:hover .pcr-ed-submenu-trigger:where(.svelte-1ozzqkm) { background: #c85909; color: #fff; }
|
||||
/* (unused) .pcr-ed-layer-bg { cursor: default; opacity: 0.85; }*/
|
||||
.pcr-ed-layer-actions.svelte-1ozzqkm { display: flex; gap: 4px; }
|
||||
.pcr-ed-layer-btn.svelte-1ozzqkm {
|
||||
@@ -928,8 +943,8 @@
|
||||
.pcr-ed-layer-btn.svelte-1ozzqkm:hover:not(:disabled) { color: #fff; border-color: #555; }
|
||||
.pcr-ed-layer-btn.svelte-1ozzqkm:disabled { opacity: 0.4; cursor: default; }
|
||||
.pcr-ed-layer-grip.svelte-1ozzqkm {
|
||||
flex: none; width: 12px; text-align: center;
|
||||
font-size: 11px; line-height: 1; color: #555;
|
||||
flex: none; width: 16px; text-align: center;
|
||||
font-size: 12px; line-height: 1; color: #666;
|
||||
cursor: grab; user-select: none;
|
||||
}
|
||||
.pcr-ed-layer-grip.svelte-1ozzqkm:hover { color: #aaa; }
|
||||
@@ -940,11 +955,19 @@
|
||||
user-select: none; color: #ccc;
|
||||
}
|
||||
.pcr-ed-eye.off.svelte-1ozzqkm { color: #666; }
|
||||
/* Photoshop-style layer-mask thumbnail (shows the mask shape; white glow = active paint target). */
|
||||
.pcr-ed-mask-thumb.svelte-1ozzqkm {
|
||||
flex: none; width: 18px; height: 18px; border-radius: 3px;
|
||||
object-fit: cover; background: #000; border: 1px solid #555; cursor: pointer;
|
||||
}
|
||||
.pcr-ed-mask-thumb.svelte-1ozzqkm:hover { border-color: #888; }
|
||||
.pcr-ed-mask-thumb.editing.svelte-1ozzqkm { border-color: #fff; box-shadow: 0 0 0 1px #fff, 0 0 0 3px rgba(255, 255, 255, 0.30); }
|
||||
.pcr-ed-layer-name.svelte-1ozzqkm { flex: 1; font-size: 12px; color: #ddd; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.pcr-ed-layer-blendtag.svelte-1ozzqkm { margin-left: 5px; font-size: 10px; color: #8b96a5; }
|
||||
.pcr-ed-layer-rename.svelte-1ozzqkm {
|
||||
flex: 1; min-width: 0; font-size: 12px; color: #eee;
|
||||
background: #1b1b1b; border: 1px solid #c85909; border-radius: 3px; padding: 1px 4px;
|
||||
-webkit-user-select: text; user-select: text; /* stays editable under the row's user-select:none */
|
||||
}
|
||||
.pcr-ed-blend-select.svelte-1ozzqkm {
|
||||
width: 100%; margin: 0 0 4px; padding: 3px 6px; font-size: 12px;
|
||||
@@ -952,6 +975,13 @@
|
||||
}
|
||||
.pcr-ed-blend-select.svelte-1ozzqkm:disabled { opacity: 0.45; }
|
||||
.pcr-ed-layer-opacity.svelte-1ozzqkm { width: 70px; accent-color: #c85909; }
|
||||
.pcr-ed-group-row.svelte-1ozzqkm { display: flex; align-items: center; gap: 4px; padding: 3px 5px; border: 1px solid #333; border-radius: 4px;
|
||||
background: rgba(120, 130, 150, 0.12); -webkit-user-select: none; user-select: none; }
|
||||
.pcr-ed-group-row.svelte-1ozzqkm .pcr-ed-eye:where(.svelte-1ozzqkm) { cursor: pointer; }
|
||||
.pcr-ed-group-name.svelte-1ozzqkm { flex: 1; font-size: 12px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; cursor: default; }
|
||||
.pcr-ed-group-x.svelte-1ozzqkm { background: none; border: none; color: #999; cursor: pointer; font-size: 13px; padding: 0 2px; }
|
||||
.pcr-ed-group-x.svelte-1ozzqkm:hover { color: #fff; }
|
||||
.pcr-ed-layer-row.in-group.svelte-1ozzqkm { margin-left: 14px; }
|
||||
.pcr-ed-hist.svelte-1ozzqkm {
|
||||
display: flex; flex-direction: column;
|
||||
max-height: 170px; overflow-y: auto;
|
||||
|
||||
+4
-4
@@ -4282,9 +4282,9 @@ export {
|
||||
untrack as E,
|
||||
update as F,
|
||||
set_checked as G,
|
||||
autofocus as H,
|
||||
to_array as I,
|
||||
from_svg as J,
|
||||
to_array as H,
|
||||
from_svg as I,
|
||||
autofocus as J,
|
||||
noop as K,
|
||||
mount as L,
|
||||
unmount as M,
|
||||
@@ -4343,4 +4343,4 @@ export {
|
||||
set_text as y,
|
||||
index as z
|
||||
};
|
||||
//# sourceMappingURL=disclose-version-uq4tn5Y6.js.map
|
||||
//# sourceMappingURL=disclose-version-et9wt-4m.js.map
|
||||
@@ -1,4 +1,4 @@
|
||||
import { _ as component_context, a0 as lifecycle_outside_component, u as user_effect, E as untrack } from "./disclose-version-uq4tn5Y6.js";
|
||||
import { _ as component_context, a0 as lifecycle_outside_component, u as user_effect, E as untrack } from "./disclose-version-et9wt-4m.js";
|
||||
function onMount(fn) {
|
||||
if (component_context === null) {
|
||||
lifecycle_outside_component();
|
||||
@@ -23,4 +23,4 @@ export {
|
||||
onMount as a,
|
||||
onDestroy as o
|
||||
};
|
||||
//# sourceMappingURL=index-client-iMRCrpBY.js.map
|
||||
//# sourceMappingURL=index-client-6amB1qrM.js.map
|
||||
@@ -1,4 +1,4 @@
|
||||
import { a2 as listen_to_event_and_reset_event, a3 as current_batch, C as tick, E as untrack, a9 as render_effect, a7 as is, a8 as teardown, ad as queue_micro_task } from "./disclose-version-uq4tn5Y6.js";
|
||||
import { a2 as listen_to_event_and_reset_event, a3 as current_batch, C as tick, E as untrack, a9 as render_effect, a7 as is, a8 as teardown, ad as queue_micro_task } from "./disclose-version-et9wt-4m.js";
|
||||
function bind_value(input, get, set = get) {
|
||||
var batches = /* @__PURE__ */ new WeakSet();
|
||||
listen_to_event_and_reset_event(input, "input", async (is_reset) => {
|
||||
@@ -150,4 +150,4 @@ export {
|
||||
bind_value as b,
|
||||
bind_group as c
|
||||
};
|
||||
//# sourceMappingURL=input-DFQhebEz.js.map
|
||||
//# sourceMappingURL=input-B9kD0bWJ.js.map
|
||||
@@ -5,11 +5,11 @@ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot
|
||||
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
||||
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
||||
var _activeNodeId, _treeRoots, _openTabs, _activeWildcardTab, _compiledOutput, _compiledNegOutput, _imageUrl, _previewUrl, _progress, _isGenerating, _sidebarView, _fontSize, _renamingNodeId;
|
||||
import { d as delegate, p as push, a as prop, i as if_block, f as sibling, t as template_effect, e as set, g as get, j as delegated, k as append, l as pop, s as state, n as child, A as from_html, x as set_attribute, u as user_effect, h as set_class, r as event, m as user_derived, R as text, y as set_text, o as bind_this, w as each, z as index, D as comment, v as first_child, c as proxy, M as unmount, L as mount } from "./disclose-version-uq4tn5Y6.js";
|
||||
import { a as onMount, o as onDestroy } from "./index-client-iMRCrpBY.js";
|
||||
import { s as set_style } from "./style-Boi27oOu.js";
|
||||
import { b as bind_value } from "./input-DFQhebEz.js";
|
||||
import { M as Menubar, S as SearchableList } from "./Menubar-DC12j8gE.js";
|
||||
import { d as delegate, p as push, a as prop, i as if_block, f as sibling, t as template_effect, e as set, g as get, j as delegated, k as append, l as pop, s as state, n as child, A as from_html, x as set_attribute, u as user_effect, h as set_class, r as event, m as user_derived, R as text, y as set_text, o as bind_this, w as each, z as index, D as comment, v as first_child, c as proxy, M as unmount, L as mount } from "./disclose-version-et9wt-4m.js";
|
||||
import { a as onMount, o as onDestroy } from "./index-client-6amB1qrM.js";
|
||||
import { s as set_style } from "./style-B3hsaAru.js";
|
||||
import { b as bind_value } from "./input-B9kD0bWJ.js";
|
||||
import { M as Menubar, S as SearchableList } from "./Menubar-CMm15KuK.js";
|
||||
var root_1$4 = from_html(`<img class="pcr-fs-topbar-logo svelte-93wsqh" alt="PromptChain"/>`);
|
||||
var root$5 = from_html(`<div class="pcr-fs-topbar svelte-93wsqh"><div class="pcr-fs-topbar-left svelte-93wsqh"><!> <span class="pcr-fs-topbar-title svelte-93wsqh"></span></div> <div class="pcr-fs-topbar-right svelte-93wsqh"><div class="pcr-fs-topbar-actions svelte-93wsqh"><input type="number" class="pcr-fs-batch-input svelte-93wsqh" min="1" max="99" title="Batch count"/> <span class="pcr-fs-run-btn svelte-93wsqh" title="Queue prompt (Ctrl+Enter)"><svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><path d="M8 5v14l11-7z"></path></svg> <span>Run</span></span> <span class="pcr-fs-cancel-btn pcr-fs-inactive svelte-93wsqh" title="Cancel execution"><svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path></svg></span> <span class="pcr-fs-queue-badge pcr-fs-inactive svelte-93wsqh">0 active</span></div> <div class="pcr-fs-panel-toggles svelte-93wsqh"><span class="pcr-fs-header-btn svelte-93wsqh" title="Toggle 3D Poser panel" data-fs-action="pose"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M20.5 6c-2.61.7-5.67 1-8.5 1s-5.89-.3-8.5-1L3 8c1.86.5 4 .83 6 1v13h2v-6h2v6h2V9c2-.17 4.14-.5 6-1l-.5-2zM12 6c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2z"></path></svg></span> <span class="pcr-fs-header-btn svelte-93wsqh" title="Toggle output panel" data-fs-action="output"><svg width="16" height="16" viewBox="0 -960 960 960" fill="currentColor"><path d="M400-280h160v-80H400v80Zm0-160h280v-80H400v80ZM280-600h400v-80H280v80Zm200 120ZM80-80v-80h102q-48-23-77.5-68T75-330q0-79 55.5-134.5T265-520v80q-45 0-77.5 32T155-330q0 39 24 69t61 38v-97h80v240H80Zm320-40v-80h360v-560H200v160h-80v-160q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H400Z"></path></svg></span> <span class="pcr-fs-header-btn svelte-93wsqh" title="Toggle image preview" data-fs-action="image"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"></path></svg></span></div> <span class="pcr-fs-close-btn svelte-93wsqh" title="Close (Escape)"></span></div></div>`);
|
||||
function Topbar($$anchor, $$props) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { M as unmount, L as mount } from "./disclose-version-uq4tn5Y6.js";
|
||||
import { G as GeneratedGallery } from "./GeneratedGallery-D5XbkMk7.js";
|
||||
import { M as unmount, L as mount } from "./disclose-version-et9wt-4m.js";
|
||||
import { G as GeneratedGallery } from "./GeneratedGallery-DgtlJz3l.js";
|
||||
function mountGallery(target, props) {
|
||||
return mount(GeneratedGallery, { target, props });
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { p as push, a as prop, D as comment, v as first_child, i as if_block, g as get, k as append, l as pop, s as state, e as set, f as sibling, t as template_effect, r as event, A as from_html, n as child, y as set_text, x as set_attribute, d as delegate, c as proxy, u as user_effect, E as untrack, o as bind_this, j as delegated, C as tick, m as user_derived, w as each, z as index, h as set_class, F as update, M as unmount, L as mount } from "./disclose-version-uq4tn5Y6.js";
|
||||
import { s as set_style } from "./style-Boi27oOu.js";
|
||||
import { b as bind_value } from "./input-DFQhebEz.js";
|
||||
import { p as push, a as prop, D as comment, v as first_child, i as if_block, g as get, k as append, l as pop, s as state, e as set, f as sibling, t as template_effect, r as event, A as from_html, n as child, y as set_text, x as set_attribute, d as delegate, c as proxy, u as user_effect, E as untrack, o as bind_this, j as delegated, C as tick, m as user_derived, w as each, z as index, h as set_class, F as update, M as unmount, L as mount } from "./disclose-version-et9wt-4m.js";
|
||||
import { s as set_style } from "./style-B3hsaAru.js";
|
||||
import { b as bind_value } from "./input-B9kD0bWJ.js";
|
||||
import { e as extractPrecisions, r as resolveFilesForPrecision } from "./model-constants-cVxhUf51.js";
|
||||
import { api } from "/scripts/api.js";
|
||||
import { s as safeJson, H as HttpError } from "./api-context-BFKo1mCD.js";
|
||||
import { s as safeJson, H as HttpError } from "./api-context-BNqvELYR.js";
|
||||
var root_2$4 = from_html(`<div class="pcr-hover-card-version svelte-oulz7g"> </div>`);
|
||||
var root_3$4 = from_html(`<div class="pcr-hover-card-meta svelte-oulz7g"> </div>`);
|
||||
var root_4$3 = from_html(`<div class="pcr-hover-card-tags svelte-oulz7g"> </div>`);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { d as delegate, p as push, a as prop, s as state, c as proxy, u as user_effect, e as set, f as sibling, o as bind_this, t as template_effect, g as get, x as set_attribute, q as set_value, j as delegated, k as append, l as pop, m as user_derived, n as child, A as from_html, w as each, z as index, i as if_block, G as set_checked, y as set_text, h as set_class, v as first_child, D as comment, a1 as set_selected, I as to_array, R as text, E as untrack, M as unmount, L as mount } from "./disclose-version-uq4tn5Y6.js";
|
||||
import { s as set_style } from "./style-Boi27oOu.js";
|
||||
import { d as delegate, p as push, a as prop, s as state, c as proxy, u as user_effect, e as set, f as sibling, o as bind_this, t as template_effect, g as get, x as set_attribute, q as set_value, j as delegated, k as append, l as pop, m as user_derived, n as child, A as from_html, w as each, z as index, i as if_block, G as set_checked, y as set_text, h as set_class, v as first_child, D as comment, a1 as set_selected, H as to_array, R as text, E as untrack, M as unmount, L as mount } from "./disclose-version-et9wt-4m.js";
|
||||
import { s as set_style } from "./style-B3hsaAru.js";
|
||||
import { F as FAMILIES, A as ARCHITECTURES } from "./model-constants-cVxhUf51.js";
|
||||
import { api } from "/scripts/api.js";
|
||||
import { S as SettingsSlider } from "./SettingsSlider-CKF_XmgB.js";
|
||||
import { b as bind_value } from "./input-DFQhebEz.js";
|
||||
import { b as bind_select_value } from "./select-Dp4ExMMc.js";
|
||||
import { a as action } from "./actions-WPfqiWYB.js";
|
||||
import { S as SettingsSlider } from "./SettingsSlider-C9Ps16J6.js";
|
||||
import { b as bind_value } from "./input-B9kD0bWJ.js";
|
||||
import { b as bind_select_value } from "./select-Bp4FHWwK.js";
|
||||
import { a as action } from "./actions-zjmT0mOr.js";
|
||||
var root$7 = from_html(`<div class="pcr-slider-container svelte-1pxowmh"><div class="pcr-slider-track svelte-1pxowmh"><div class="pcr-slider-zone pcr-slider-zone-editable svelte-1pxowmh"></div> <div class="pcr-slider-thumb pcr-thumb-blue svelte-1pxowmh"></div> <div class="pcr-slider-thumb pcr-thumb-blue svelte-1pxowmh"></div></div> <input type="number" class="pcr-slider-input pcr-slider-input-half svelte-1pxowmh"/> <span class="pcr-slider-range-sep svelte-1pxowmh">–</span> <input type="number" class="pcr-slider-input pcr-slider-input-half svelte-1pxowmh"/></div>`);
|
||||
function RangeSlider($$anchor, $$props) {
|
||||
push($$props, true);
|
||||
|
||||
@@ -5,15 +5,15 @@ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot
|
||||
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
||||
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
||||
var _mode, _switchIndex, _locked, _disabled, _collapsed, _connectedCount, _hasLabels, _switchLabel, _iterateCurrent, _iterateTotal, _iterateCycle, _switchOptions, _outputPanelOpen, _imagePanelVisible, _aiAssistantOpen, _posePanelVisible, _regionPanelVisible, _hasPoseStudio, _hasRegionBox, _compiledOutput, _compiledNegOutput, _imageUrl, _previewUrl, _progress, _isGenerating, _rollSelected;
|
||||
import { p as push, o as bind_this, k as append, l as pop, A as from_html, d as delegate, a as prop, g as get, j as delegated, m as user_derived, s as state, c as proxy, u as user_effect, i as if_block, f as sibling, r as event, e as set, C as tick, n as child, D as comment, v as first_child, w as each, t as template_effect, y as set_text, h as set_class, x as set_attribute, Q as clsx, z as index, R as text, E as untrack, M as unmount, L as mount } from "./disclose-version-uq4tn5Y6.js";
|
||||
import { u as useApi, p as provideApi } from "./api-context-BFKo1mCD.js";
|
||||
import { M as Menubar } from "./Menubar-DC12j8gE.js";
|
||||
import { o as onDestroy, a as onMount } from "./index-client-iMRCrpBY.js";
|
||||
import { s as set_style } from "./style-Boi27oOu.js";
|
||||
import { h as html, P as PopupAnchor } from "./PopupAnchor-C6OWGGTI.js";
|
||||
import { p as push, o as bind_this, k as append, l as pop, A as from_html, d as delegate, a as prop, g as get, j as delegated, m as user_derived, s as state, c as proxy, u as user_effect, i as if_block, f as sibling, r as event, e as set, C as tick, n as child, D as comment, v as first_child, w as each, t as template_effect, y as set_text, h as set_class, x as set_attribute, Q as clsx, z as index, R as text, E as untrack, M as unmount, L as mount } from "./disclose-version-et9wt-4m.js";
|
||||
import { u as useApi, p as provideApi } from "./api-context-BNqvELYR.js";
|
||||
import { M as Menubar } from "./Menubar-CMm15KuK.js";
|
||||
import { o as onDestroy, a as onMount } from "./index-client-6amB1qrM.js";
|
||||
import { s as set_style } from "./style-B3hsaAru.js";
|
||||
import { h as html, P as PopupAnchor } from "./PopupAnchor-D5Lvfjom.js";
|
||||
import { api } from "/scripts/api.js";
|
||||
import { c as clampGalleryRowHeight, z as zoomGalleryRowHeight, G as GeneratedGallery } from "./GeneratedGallery-D5XbkMk7.js";
|
||||
import { b as bind_value } from "./input-DFQhebEz.js";
|
||||
import { c as clampGalleryRowHeight, z as zoomGalleryRowHeight, G as GeneratedGallery } from "./GeneratedGallery-DgtlJz3l.js";
|
||||
import { b as bind_value } from "./input-B9kD0bWJ.js";
|
||||
import { app } from "/scripts/app.js";
|
||||
import { r as readNodePrompt, c as cryptoId, e as extractNGrams, m as matchCharactersInDb, i as isStandaloneMainPromptChain, a as applyPromptText } from "./ai-patch-helpers-Bayqv0oF.js";
|
||||
var root$d = from_html(`<div class="pcr-editor-frame"></div>`);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { c as proxy, N as effect_root, u as user_effect, d as delegate, p as push, r as event, $ as $window, v as first_child, w as each, f as sibling, i as if_block, g as get, o as bind_this, t as template_effect, j as delegated, k as append, l as pop, s as state, e as set, m as user_derived, n as child, A as from_html, J as from_svg, h as set_class, y as set_text, z as index, q as set_value, x as set_attribute, a as prop, O as getContext, C as tick, D as comment, P as setContext, L as mount, M as unmount } from "./disclose-version-uq4tn5Y6.js";
|
||||
import { a as onMount } from "./index-client-iMRCrpBY.js";
|
||||
import { s as set_style } from "./style-Boi27oOu.js";
|
||||
import { c as proxy, N as effect_root, u as user_effect, d as delegate, p as push, r as event, $ as $window, v as first_child, w as each, f as sibling, i as if_block, g as get, o as bind_this, t as template_effect, j as delegated, k as append, l as pop, s as state, e as set, m as user_derived, n as child, A as from_html, I as from_svg, h as set_class, y as set_text, z as index, q as set_value, x as set_attribute, a as prop, O as getContext, C as tick, D as comment, P as setContext, L as mount, M as unmount } from "./disclose-version-et9wt-4m.js";
|
||||
import { a as onMount } from "./index-client-6amB1qrM.js";
|
||||
import { s as set_style } from "./style-B3hsaAru.js";
|
||||
import { j as justifiedLayout } from "./justified-layout-cyVM7i96.js";
|
||||
import { a as action } from "./actions-WPfqiWYB.js";
|
||||
import { b as bind_value, c as bind_group } from "./input-DFQhebEz.js";
|
||||
import { p as portal, C as ConfirmModal } from "./ConfirmModal-BGcVYndw.js";
|
||||
import { s as safeJson, H as HttpError } from "./api-context-BFKo1mCD.js";
|
||||
import { a as action } from "./actions-zjmT0mOr.js";
|
||||
import { b as bind_value, c as bind_group } from "./input-B9kD0bWJ.js";
|
||||
import { p as portal, C as ConfirmModal } from "./ConfirmModal-CtR7InHn.js";
|
||||
import { s as safeJson, H as HttpError } from "./api-context-BNqvELYR.js";
|
||||
const VIEW_MODES = [
|
||||
{ id: "grid", label: "Grid" },
|
||||
{ id: "justified", label: "Justified" },
|
||||
@@ -3011,7 +3011,10 @@ function AssetBrowser($$anchor, $$props) {
|
||||
const item = (_c = get(ctxMenu)) == null ? void 0 : _c.item;
|
||||
if (item) {
|
||||
const root2 = scopeRoots[nav.scope] || "";
|
||||
const full = root2 ? `${root2}/${item.path}` : item.path;
|
||||
let full = root2 ? `${root2}/${item.path}` : item.path;
|
||||
if (/^[a-zA-Z]:[/\\]/.test(full) || full.startsWith("//")) {
|
||||
full = full.replace(/\//g, "\\");
|
||||
}
|
||||
await navigator.clipboard.writeText(full);
|
||||
(_d = $$props.toast) == null ? void 0 : _d.call($$props, "info", "Path copied to clipboard");
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { d as delegate, p as push, a as prop, w as each, z as index, g as get, f as sibling, i as if_block, k as append, l as pop, m as user_derived, n as child, h as set_class, j as delegated, A as from_html, t as template_effect, x as set_attribute, q as set_value, v as first_child, y as set_text, D as comment, s as state, c as proxy, u as user_effect, e as set, I as to_array, E as untrack, o as bind_this, G as set_checked, M as unmount, L as mount } from "./disclose-version-uq4tn5Y6.js";
|
||||
import { a as onMount, o as onDestroy } from "./index-client-iMRCrpBY.js";
|
||||
import { a as action } from "./actions-WPfqiWYB.js";
|
||||
import { a as bind_checked, b as bind_value } from "./input-DFQhebEz.js";
|
||||
import { d as delegate, p as push, a as prop, w as each, z as index, g as get, f as sibling, i as if_block, k as append, l as pop, m as user_derived, n as child, h as set_class, j as delegated, A as from_html, t as template_effect, x as set_attribute, q as set_value, v as first_child, y as set_text, D as comment, s as state, c as proxy, u as user_effect, e as set, H as to_array, E as untrack, o as bind_this, G as set_checked, M as unmount, L as mount } from "./disclose-version-et9wt-4m.js";
|
||||
import { a as onMount, o as onDestroy } from "./index-client-6amB1qrM.js";
|
||||
import { a as action } from "./actions-zjmT0mOr.js";
|
||||
import { a as bind_checked, b as bind_value } from "./input-B9kD0bWJ.js";
|
||||
import { b as buildInsertText } from "./tag-builder-utils-ng134QDV.js";
|
||||
import { b as bind_select_value } from "./select-Dp4ExMMc.js";
|
||||
import { b as bind_select_value } from "./select-Bp4FHWwK.js";
|
||||
const MULTI_SELECT_GROUPS = ["props"];
|
||||
const CUSTOMIZABLE_CLOTHING_GROUPS = [
|
||||
"legwear",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { d as delegate, p as push, a as prop, s as state, c as proxy, u as user_effect, e as set, f as sibling, n as child, i as if_block, g as get, t as template_effect, j as delegated, k as append, l as pop, v as first_child, h as set_class, y as set_text, A as from_html, m as user_derived, w as each, z as index, I as to_array, C as tick, o as bind_this, D as comment, x as set_attribute, q as set_value, R as text, M as unmount, L as mount } from "./disclose-version-uq4tn5Y6.js";
|
||||
import { a as onMount } from "./index-client-iMRCrpBY.js";
|
||||
import { a as action } from "./actions-WPfqiWYB.js";
|
||||
import { s as set_style } from "./style-Boi27oOu.js";
|
||||
import { a as bind_checked, b as bind_value } from "./input-DFQhebEz.js";
|
||||
import { d as delegate, p as push, a as prop, s as state, c as proxy, u as user_effect, e as set, f as sibling, n as child, i as if_block, g as get, t as template_effect, j as delegated, k as append, l as pop, v as first_child, h as set_class, y as set_text, A as from_html, m as user_derived, w as each, z as index, H as to_array, C as tick, o as bind_this, D as comment, x as set_attribute, q as set_value, R as text, M as unmount, L as mount } from "./disclose-version-et9wt-4m.js";
|
||||
import { a as onMount } from "./index-client-6amB1qrM.js";
|
||||
import { a as action } from "./actions-zjmT0mOr.js";
|
||||
import { s as set_style } from "./style-B3hsaAru.js";
|
||||
import { a as bind_checked, b as bind_value } from "./input-B9kD0bWJ.js";
|
||||
import { b as isStructuralLine, d as isInNegativeBlock } from "./ai-patch-helpers-Bayqv0oF.js";
|
||||
import { f as formatTagsForModel } from "./tag-builder-utils-ng134QDV.js";
|
||||
var root_1$3 = from_html(`<div class="pcr-atb2-cust-loading svelte-1mwxie1">Loading…</div>`);
|
||||
|
||||
+1620
-777
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
import { a2 as listen_to_event_and_reset_event, a3 as current_batch, a4 as effect, a5 as is_array, a6 as select_multiple_invalid_value, a7 as is, a8 as teardown } from "./disclose-version-uq4tn5Y6.js";
|
||||
import { a2 as listen_to_event_and_reset_event, a3 as current_batch, a4 as effect, a5 as is_array, a6 as select_multiple_invalid_value, a7 as is, a8 as teardown } from "./disclose-version-et9wt-4m.js";
|
||||
function select_option(select, value, mounting = false) {
|
||||
if (select.multiple) {
|
||||
if (value == void 0) {
|
||||
@@ -97,4 +97,4 @@ export {
|
||||
init_select as i,
|
||||
select_option as s
|
||||
};
|
||||
//# sourceMappingURL=select-Dp4ExMMc.js.map
|
||||
//# sourceMappingURL=select-Bp4FHWwK.js.map
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ac as to_style } from "./disclose-version-uq4tn5Y6.js";
|
||||
import { ac as to_style } from "./disclose-version-et9wt-4m.js";
|
||||
function update_styles(dom, prev = {}, next, priority) {
|
||||
for (var key in next) {
|
||||
var value = next[key];
|
||||
@@ -36,4 +36,4 @@ function set_style(dom, value, prev_styles, next_styles) {
|
||||
export {
|
||||
set_style as s
|
||||
};
|
||||
//# sourceMappingURL=style-Boi27oOu.js.map
|
||||
//# sourceMappingURL=style-B3hsaAru.js.map
|
||||
@@ -813,32 +813,57 @@ function ensureDepthBranch(graph, LG, usNode, depthSource, loadNode) {
|
||||
const poser = graph._nodes.find((n) => n.comfyClass === "PromptChain_PoseStudio");
|
||||
const sourceNode = depthSource === "pose" && poser ? poser : loadNode;
|
||||
const sourceSlot = sourceNode === poser ? (poser.outputs?.findIndex((o) => o.name === "IMAGE") ?? 0) : 0;
|
||||
// The Poser feeds its IMAGE straight into Apply ControlNet when it ALREADY renders
|
||||
// true depth — its uploaded control map is the depth map itself, so DepthAnything
|
||||
// is skipped. A legacy clay-mode Poser keeps the estimator: nothing re-captures a
|
||||
// depth render at queue time, so pointing a clay render at a depth net would be wrong.
|
||||
const poseDirect = sourceNode === poser &&
|
||||
(poser.properties?.pcrOutputMode === "depth" || poser.properties?.pcrTrueDepth === true);
|
||||
|
||||
const existing = findDepthApply(graph, usNode);
|
||||
if (existing) {
|
||||
if (existing.pre) {
|
||||
if (poseDirect) {
|
||||
// Hint the apply straight from the Poser; retire any DepthAnything in between.
|
||||
sourceNode.connect(sourceSlot, existing.apply, inputIdx(existing.apply, "image", 3));
|
||||
if (existing.pre) existing.pre.mode = 4;
|
||||
} else if (existing.pre) {
|
||||
const cur = traceInput(graph, existing.pre, "image");
|
||||
if (cur?.node !== sourceNode) {
|
||||
sourceNode.connect(sourceSlot, existing.pre, inputIdx(existing.pre, "image", 0));
|
||||
}
|
||||
} else {
|
||||
// The apply was built pose-direct (no preprocessor) but the new source isn't
|
||||
// a true-depth render — a clay-mode Poser or an image. Its raw pixels aren't a
|
||||
// depth map, so splice a DepthAnything estimator back in between source and apply.
|
||||
const pre = LG.createNode(resolvePre(CONTROLNET_TYPES.depth.pre));
|
||||
if (pre) {
|
||||
pre.pos = [existing.apply.pos[0] - 340, existing.apply.pos[1]];
|
||||
graph.add(pre);
|
||||
pre.size = [291, pre.size?.[1] ?? 130];
|
||||
const resW = pre.widgets?.find((w) => w.name === "resolution");
|
||||
if (resW) { resW.value = 1024; resW.callback?.(1024); }
|
||||
sourceNode.connect(sourceSlot, pre, inputIdx(pre, "image", 0));
|
||||
pre.connect(0, existing.apply, inputIdx(existing.apply, "image", 3));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const cfg = CONTROLNET_TYPES.depth;
|
||||
const pre = LG.createNode(resolvePre(cfg.pre));
|
||||
const pre = poseDirect ? null : LG.createNode(resolvePre(cfg.pre));
|
||||
const loader = LG.createNode("ControlNetLoader");
|
||||
const setUnion = LG.createNode("SetUnionControlNetType");
|
||||
const applyNode = LG.createNode("ControlNetApplyAdvanced");
|
||||
if (!pre || !loader || !setUnion || !applyNode) return false;
|
||||
if ((!poseDirect && !pre) || !loader || !setUnion || !applyNode) return false;
|
||||
|
||||
const ax = usNode.pos[0];
|
||||
const ay = usNode.pos[1];
|
||||
pre.pos = [ax - 700, ay + 420];
|
||||
if (pre) pre.pos = [ax - 700, ay + 420];
|
||||
loader.pos = [ax - 700, ay + 640];
|
||||
setUnion.pos = [ax - 700, ay + 780];
|
||||
applyNode.pos = [ax - 360, ay + 420];
|
||||
graph.add(pre); graph.add(loader); graph.add(setUnion); graph.add(applyNode);
|
||||
if (pre) graph.add(pre);
|
||||
graph.add(loader); graph.add(setUnion); graph.add(applyNode);
|
||||
|
||||
applyNode.title = `ControlNet — Depth${sourceNode === poser ? " (pose)" : ""}`;
|
||||
applyNode.properties = { ...(applyNode.properties || {}), pcrControlType: "depth" };
|
||||
@@ -850,15 +875,20 @@ function ensureDepthBranch(graph, LG, usNode, depthSource, loadNode) {
|
||||
else if (w.name === "start_percent") { w.value = 0.0; w.callback?.(0.0); }
|
||||
else if (w.name === "end_percent") { w.value = cfg.end; w.callback?.(cfg.end); }
|
||||
}
|
||||
const resW = pre.widgets?.find((w) => w.name === "resolution");
|
||||
const resW = pre?.widgets?.find((w) => w.name === "resolution");
|
||||
if (resW) { resW.value = 1024; resW.callback?.(1024); }
|
||||
|
||||
const posSrc = traceInput(graph, usNode, "positive");
|
||||
const negSrc = traceInput(graph, usNode, "negative");
|
||||
if (!posSrc?.node || !negSrc?.node) return false;
|
||||
|
||||
sourceNode.connect(sourceSlot, pre, inputIdx(pre, "image", 0));
|
||||
pre.connect(0, applyNode, inputIdx(applyNode, "image", 3));
|
||||
if (pre) {
|
||||
sourceNode.connect(sourceSlot, pre, inputIdx(pre, "image", 0));
|
||||
pre.connect(0, applyNode, inputIdx(applyNode, "image", 3));
|
||||
} else {
|
||||
// Pose-direct: the Poser's true-depth IMAGE is the control map itself.
|
||||
sourceNode.connect(sourceSlot, applyNode, inputIdx(applyNode, "image", 3));
|
||||
}
|
||||
loader.connect(0, setUnion, 0);
|
||||
setUnion.connect(0, applyNode, inputIdx(applyNode, "control_net", 2));
|
||||
posSrc.node.connect(posSrc.slot, applyNode, inputIdx(applyNode, "positive", 0));
|
||||
|
||||
@@ -306,7 +306,15 @@ export async function openViewer(images, startIndex = 0, workflowId = "", onDele
|
||||
onInpaintInstallPack: (injectable) => installInpaintPack(injectable),
|
||||
onMountPromptEditor: mountPromptEditor,
|
||||
onEditPrepare: (entry) => prepareEdit(entry),
|
||||
onEditSave: (prepared, blob, prefix) => saveEditedImage(prepared, blob, prefix),
|
||||
onEditSave: async (prepared, blob, prefix) => {
|
||||
const entry = await saveEditedImage(prepared, blob, prefix);
|
||||
// Opened from a node (e.g. LoadImage) that wants the result wired back.
|
||||
if (entry && typeof opts.onAfterEditSave === "function") {
|
||||
try { await opts.onAfterEditSave(entry); }
|
||||
catch (e) { console.error("[PromptChain] onAfterEditSave failed", e); }
|
||||
}
|
||||
return entry;
|
||||
},
|
||||
onInpaintRegion: (data, args) => inpaintRegion(data, args),
|
||||
onReposeCaps: () => fetchReposeCaps(),
|
||||
onReposeRun: (opts) => runReposeInBackground(opts),
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
// Right-click a LoadImage node -> "Open in PromptChain editor": opens the
|
||||
// node's currently-loaded input image in the PromptChain editor. A saved edit
|
||||
// becomes a lineage child (parent = the loaded image) and re-points THIS node
|
||||
// to the edited result — a NEW input file, not an overwrite of the source.
|
||||
//
|
||||
// A SEPARATE extension (own registerExtension) so a JS error here can never
|
||||
// take down the prompt editor / poser / region box. The menu item rides
|
||||
// getExtraMenuOptions, which fires in both the legacy and Vue node renderers —
|
||||
// the only trigger that works uniformly (a bare click on the on-node image is
|
||||
// not interceptable in Vue mode), mirroring core's "Open in MaskEditor".
|
||||
|
||||
import { app } from "../../scripts/app.js";
|
||||
import { api } from "../../scripts/api.js";
|
||||
import { openViewer } from "./lib/viewer-bridge.js";
|
||||
|
||||
const TARGET_NODES = new Set(["LoadImage"]);
|
||||
|
||||
// The loaded file's identity. node.imgs[i].src is the authoritative
|
||||
// /view?filename=&subfolder=&type= URL; the 'image' widget value is the
|
||||
// fallback (it can carry a trailing " [input]" annotation, which we strip).
|
||||
function readLoadedImage(node) {
|
||||
const src = node.imgs?.[node.imageIndex ?? 0]?.src;
|
||||
if (src) {
|
||||
try {
|
||||
const u = new URL(src, window.location.origin);
|
||||
const filename = u.searchParams.get("filename") || "";
|
||||
if (filename) {
|
||||
return {
|
||||
filename,
|
||||
subfolder: u.searchParams.get("subfolder") || "",
|
||||
type: u.searchParams.get("type") || "input",
|
||||
};
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
const widget = node.widgets?.find((w) => w.name === "image");
|
||||
const raw = typeof widget?.value === "string" ? widget.value : "";
|
||||
const val = raw.replace(/\s*\[(input|output|temp)\]\s*$/, "");
|
||||
if (!val) return null;
|
||||
const parts = val.split("/");
|
||||
const filename = parts.pop();
|
||||
return { filename, subfolder: parts.join("/"), type: "input" };
|
||||
}
|
||||
|
||||
function findImageWidget(node) {
|
||||
return node.widgets?.find(
|
||||
(w) => w.options?.image_upload === true || (w.type === "combo" && w.name === "image")
|
||||
) || null;
|
||||
}
|
||||
|
||||
// The edit is saved to the OUTPUT tree, but LoadImage reads the INPUT root.
|
||||
// image-workflow?hash= stages a content-addressed promptchain_source_<hash>
|
||||
// copy into input/ and hands back input_ref — the same primitive prepareEdit
|
||||
// uses for the source — which is then a valid LoadImage combo value.
|
||||
async function attachEditedToNode(node, entry) {
|
||||
if (!entry?.hash) return;
|
||||
let inputRef = "";
|
||||
try {
|
||||
const res = await api.fetchApi(`/promptchain/image-workflow?hash=${encodeURIComponent(entry.hash)}`);
|
||||
if (res.ok) inputRef = (await res.json())?.input_ref || "";
|
||||
} catch (e) {
|
||||
console.error("[PromptChain] LoadImage attach-back staging failed", e);
|
||||
}
|
||||
if (!inputRef) return;
|
||||
|
||||
const widget = findImageWidget(node);
|
||||
if (!widget) return;
|
||||
// The full re-point: add the option, set the value, fire the combo callback
|
||||
// (Comfy's installed refresh: node.imgs=undefined -> reload -> setDirtyCanvas).
|
||||
// Setting .value alone does NOT reload the preview.
|
||||
if (widget.options?.values && !widget.options.values.includes(inputRef)) {
|
||||
widget.options.values.push(inputRef);
|
||||
}
|
||||
widget.value = inputRef;
|
||||
widget.callback?.(inputRef);
|
||||
node.setDirtyCanvas(true, true);
|
||||
}
|
||||
|
||||
async function openLoadImageInEditor(node) {
|
||||
const img = readLoadedImage(node);
|
||||
if (!img?.filename) {
|
||||
app.extensionManager?.toast?.add?.({
|
||||
severity: "warn",
|
||||
summary: "PromptChain",
|
||||
detail: "This node has no loaded image to edit.",
|
||||
life: 5000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
// A browse-style entry (no DB hash) — identical shape to the sidebar's, so
|
||||
// prepareEdit resolves the input file as the lineage parent.
|
||||
const scope = img.type === "output" ? "output" : "input";
|
||||
const path = img.subfolder ? `${img.subfolder}/${img.filename}` : img.filename;
|
||||
const entry = {
|
||||
hash: path,
|
||||
filename: img.filename,
|
||||
subfolder: "",
|
||||
_directUrl: api.apiURL(`/promptchain/browse/preview?scope=${scope}&path=${encodeURIComponent(path)}`),
|
||||
_browseScope: scope,
|
||||
_browsePath: path,
|
||||
};
|
||||
openViewer([entry], 0, "", null, {
|
||||
autoEdit: true,
|
||||
onAfterEditSave: (saved) => attachEditedToNode(node, saved),
|
||||
});
|
||||
}
|
||||
|
||||
app.registerExtension({
|
||||
name: "PromptChain.LoadImageEditor",
|
||||
async beforeRegisterNodeDef(nodeType, nodeData) {
|
||||
if (!TARGET_NODES.has(nodeData?.name)) return;
|
||||
const original = nodeType.prototype.getExtraMenuOptions;
|
||||
nodeType.prototype.getExtraMenuOptions = function (canvas, options) {
|
||||
const result = original?.apply(this, arguments);
|
||||
const node = this;
|
||||
options.push({
|
||||
content: "Open in PromptChain editor",
|
||||
callback: () => openLoadImageInEditor(node),
|
||||
});
|
||||
return result;
|
||||
};
|
||||
},
|
||||
});
|
||||
+33
-14
@@ -367,20 +367,6 @@ function setupImagePreviewListeners() {
|
||||
// here describe the user's active graph, not that prompt's.
|
||||
if (detail.prompt_id && externallyTrackedPrompts.has(detail.prompt_id)) return;
|
||||
const nodeId = Number(detail.node);
|
||||
let pcNodes = _outputToPC.get(nodeId);
|
||||
let wfId = _executionWorkflowId;
|
||||
if (!pcNodes?.length) {
|
||||
// The SaveImage didn't map to a PromptChain node via the execution_start
|
||||
// graph scan (trace miss / subgraph / workflow-id drift). Don't silently
|
||||
// drop the generation — diagnose, then attribute it to the active graph's
|
||||
// PromptChain node so the generation panel still catches it.
|
||||
if (!wfId) wfId = getWorkflowId();
|
||||
const fallbackPC = (app.graph?._nodes || []).find((n) => n.comfyClass === NODE_TYPE);
|
||||
console.warn(`[PromptChain][record] unmapped output node=${detail.node}->${nodeId} mapKeys=[${[..._outputToPC.keys()]}] wfId=${wfId} graphNodes=${app.graph?._nodes?.length} rootGraph=${!!app.rootGraph} fallbackPC=${fallbackPC?.id ?? "none"}`);
|
||||
if (!fallbackPC || !wfId) return;
|
||||
pcNodes = [fallbackPC];
|
||||
}
|
||||
|
||||
const img = detail.output.images[detail.output.images.length - 1];
|
||||
const params = new URLSearchParams({
|
||||
filename: img.filename,
|
||||
@@ -389,6 +375,39 @@ function setupImagePreviewListeners() {
|
||||
});
|
||||
const imageUrl = api.apiURL(`/view?${params}&rand=${Math.random()}`);
|
||||
|
||||
// A PreviewImage emits type "temp" — a transient guide map (e.g. the 3D
|
||||
// Poser depth control map), not a saved render. It still flashes in the
|
||||
// node panel to guide the user, but must never be recorded: the Generated
|
||||
// gallery holds saved outputs (SaveImage → "output") only.
|
||||
const isSavedOutput = (img.type || "output") === "output";
|
||||
|
||||
let pcNodes = _outputToPC.get(nodeId);
|
||||
let wfId = _executionWorkflowId;
|
||||
if (!pcNodes?.length) {
|
||||
// The SaveImage didn't map to a PromptChain node via the execution_start
|
||||
// graph scan (trace miss / subgraph / workflow-id drift). Don't silently
|
||||
// drop the generation — diagnose, then attribute it to the active graph's
|
||||
// PromptChain node so the generation panel still catches it. A side-branch
|
||||
// preview (the pose depth map) is EXPECTED to be unmapped — don't warn.
|
||||
if (!wfId) wfId = getWorkflowId();
|
||||
const fallbackPC = (app.graph?._nodes || []).find((n) => n.comfyClass === NODE_TYPE);
|
||||
if (isSavedOutput) {
|
||||
console.warn(`[PromptChain][record] unmapped output node=${detail.node}->${nodeId} mapKeys=[${[..._outputToPC.keys()]}] wfId=${wfId} graphNodes=${app.graph?._nodes?.length} rootGraph=${!!app.rootGraph} fallbackPC=${fallbackPC?.id ?? "none"}`);
|
||||
}
|
||||
if (!fallbackPC || (isSavedOutput && !wfId)) return;
|
||||
pcNodes = [fallbackPC];
|
||||
}
|
||||
|
||||
// Transient preview (PreviewImage / non-"output"): flash in the panel to
|
||||
// guide the user, then stop — no metadata, no gallery record.
|
||||
if (!isSavedOutput) {
|
||||
for (const pc of pcNodes) {
|
||||
pc._pcrImagePanel?.updateImage(imageUrl, null);
|
||||
pc._pcrImagePanel?.hideProgress();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// metadata from graph-determined nearest KSampler
|
||||
const entry = _saveNodeGraph.get(nodeId);
|
||||
let meta = entry?.ksampleId != null ? { ..._executionMeta.get(entry.ksampleId) } : {};
|
||||
|
||||
+5
-1
@@ -113,9 +113,13 @@ function installPoseStyles() {
|
||||
// Stop pointer/key events from bubbling to LiteGraph (which would drag the node
|
||||
// or pop its context menu), but only in the BUBBLE phase — OrbitControls listens
|
||||
// on the canvas in the target phase, which runs first, so it still gets to orbit.
|
||||
// `mousedown` is isolated too: when the viewport is docked inside the PromptChain
|
||||
// fullscreen overlay, that overlay preventDefaults stray mousedowns to keep focus
|
||||
// in the editor — which silently suppresses the popup of every native <select>
|
||||
// here (foot/hand pose, body pose, shoe pickers), making them open then snap shut.
|
||||
function isolateViewportEvents(container) {
|
||||
const stop = (event) => event.stopPropagation();
|
||||
for (const type of ["pointerdown", "pointerup", "pointermove", "keydown", "keyup", "contextmenu"]) {
|
||||
for (const type of ["pointerdown", "mousedown", "pointerup", "pointermove", "keydown", "keyup", "contextmenu"]) {
|
||||
container.addEventListener(type, stop);
|
||||
}
|
||||
// LiteGraph captures the pointer on its canvas; release it so a drag here
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
|
||||
[project]
|
||||
name = "comfyui-promptchain"
|
||||
version = "0.1.8"
|
||||
version = "0.1.9"
|
||||
description = "Prompt-authoring and image-iteration suite for ComfyUI: structured prompts, 3D posing, model awareness, regional control, and layered editing."
|
||||
license = { file = "LICENSE" }
|
||||
requires-python = ">=3.10"
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
let {
|
||||
open,
|
||||
sourceCanvas = null, // flattened composite to adjust
|
||||
sourceCanvas = null, // the active layer's pixels to adjust (caller scopes this)
|
||||
filename = "",
|
||||
onApply = null, // (ImageData) => void
|
||||
onCancel,
|
||||
@@ -269,6 +269,11 @@
|
||||
if (cH && y > 0.75) add += cH * (1 - Math.cos(Math.PI * (y - 0.75) / 0.25)) / 2;
|
||||
lut[i] = Math.max(0, Math.min(1, y + 0.25 * add));
|
||||
}
|
||||
// Enforce monotonicity: large/opposing parametric bumps can fold the curve back
|
||||
// on itself (output decreasing as input rises), which inverts/solarizes tones.
|
||||
// Clamp any fold to a flat plateau instead — graceful, and keeps full slider
|
||||
// strength wherever the curve is still rising.
|
||||
for (let i = 1; i < N; i++) if (lut[i] < lut[i - 1]) lut[i] = lut[i - 1];
|
||||
return lut;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -456,7 +456,13 @@
|
||||
const item = ctxMenu?.item;
|
||||
if (item) {
|
||||
const root = scopeRoots[nav.scope] || "";
|
||||
const full = root ? `${root}/${item.path}` : item.path;
|
||||
let full = root ? `${root}/${item.path}` : item.path;
|
||||
// The backend normalizes root/paths to forward slashes for web use; restore
|
||||
// native separators when the path is Windows-rooted (drive letter or UNC) so
|
||||
// it pastes correctly into Explorer and Windows apps.
|
||||
if (/^[a-zA-Z]:[/\\]/.test(full) || full.startsWith("//")) {
|
||||
full = full.replace(/\//g, "\\");
|
||||
}
|
||||
await navigator.clipboard.writeText(full);
|
||||
toast?.("info", "Path copied to clipboard");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user