feat(sidebar): add onboarding guide (#107)

* feat(sidebar): add onboarding guide

* docs(guide): clarify tag search casing

* docs(guide): clarify workflow save copy

* docs(guide): refine sidebar visuals

* docs(guide): refresh save snapshot visual

* docs(guide): refresh load snapshot visual

* docs(guide): refresh module save visual

* docs(guide): use real sidebar screenshot

* docs(guide): render sidebar overview screenshot directly

* docs(guide): soften sidebar overview annotations

* docs(guide): clarify nodes action bar callout

* docs(guide): clarify workflow action bar callout

* docs(guide): simplify sidebar overview markers

* docs(guide): align sidebar overview intro

* docs(guide): use real snapshot recipe screenshots

* docs(guide): simplify project workflow diagram

* docs(guide): make function cards scannable

* docs(guide): sketch module recipe icon focus

* docs(guide): use real icon screenshot for module recipe

* docs(guide): add cropped workflow action screenshot

* docs(guide): use full toolbar screenshot for module recipe

* docs(guide): use real search screenshot

* docs(guide): use real node search screenshot

* docs(guide): standardize screenshot recipe cards

* docs(guide): tighten recipe callout styling

* docs: require visual QA for UI work

* docs(guide): address pass-2 review nits
This commit is contained in:
malkuthro
2026-05-08 13:44:55 +02:00
committed by GitHub
parent b185118950
commit 27705be037
19 changed files with 951 additions and 296 deletions
+27
View File
@@ -0,0 +1,27 @@
# ComfyUI-Koolook Codex Instructions
## Required Project Context
Read `CLAUDE.md` before making substantive changes. It contains the
project-specific workflow, dev-sync rules, release rules, and sidebar
maintenance notes.
## Visual QA Is Mandatory For UI Work
For any change that affects rendered UI, guide pages, screenshots,
CSS/layout, onboarding docs, or browser-visible behavior:
1. Do not rely on CSS coordinates, source inspection, or user screenshots alone.
2. Open the changed page/app in a browser-rendered environment that Codex can
screenshot.
3. If a `file://` guide page is blocked by browser tooling, serve the repo over
local HTTP instead, for example:
`python3 -m http.server <port>` from the repo root, then open
`http://127.0.0.1:<port>/...`.
4. Take a rendered screenshot after the change and inspect the actual visual
result before committing or pushing.
5. If visual verification is blocked, say that clearly and do not present the UI
change as ready unless the user explicitly waives visual QA.
This is especially important for overlays, icon highlights, responsive layout,
text fitting, and visual guide pages.
+20 -1
View File
@@ -7,6 +7,16 @@ The format is inspired by Keep a Changelog and SemVer.
## [Unreleased]
### Added
- **Bundled visual onboarding guide for the Kforge Labs sidebar.** The
existing Tools-row `H` help shortcut now opens `web/guide/index.html`, an
offline visual guide that frames Snapshots as a reusable project kit for
favorite nodes, cross-sidebar search, saved workflows, modules, tags,
autosaves, and starter presets. Its static styling borrows the dark,
token-driven card language from the ForgeFlow sibling project's design docs.
The first version ships annotated mock images under
`web/guide/img/` so they can be replaced by real ComfyUI screenshots later
without changing the guide structure. Linked from the README and user guide
index for users browsing docs outside ComfyUI.
- **Subgraph-aware module saves.** Selection saves now carry the
transitively referenced `definitions.subgraphs` entries for selected
ComfyUI subgraph wrapper nodes, so the saved workflow has the definitions
@@ -67,7 +77,16 @@ The format is inspired by Keep a Changelog and SemVer.
save now use the approved compact letter / simple-glyph treatment from
`docs/designs/sidebar-icon-proposals.html`, reducing repeated generic
cloud / grid / floppy symbols while leaving all actions and tooltips
unchanged. Tools now also exposes an `H` help shortcut to the user guide.
unchanged. The existing Tools-row `H` help shortcut is now wired to the
bundled visual onboarding guide.
- **Node help text tightened for scannability.** The Easy Resize description
and HDR VAE encode/decode tooltips now use shorter, action-oriented text so
the ComfyUI node help stays readable while detailed behavior remains in the
user guide.
- **README refocused as a short product front door.** The repo landing page
now leads with the Kforge Labs sidebar, Snapshots, search, workflows, and
recovery, then links out to the deeper user/maintainer/fork docs instead of
carrying long maintainer workflow and implementation sections inline.
- **Node-list hover previews now stay at the intended 300px mock-node width.**
The preview card previously had only a `min-width` plus viewport `max-width`,
so long node descriptions could set the card's intrinsic width and stretch the
+54 -236
View File
@@ -1,268 +1,86 @@
# ComfyUI-Koolook-Nodes
# ComfyUI-Koolook
This repository provides custom nodes for ComfyUI tailored for VFX and AI image/video generation workflows.
Kforge Labs for ComfyUI: a project-kit sidebar plus Koolook nodes for VFX,
image, and video workflows.
For change history see [`CHANGELOG.md`](CHANGELOG.md). For workflow conventions and naming see [`CLAUDE.md`](CLAUDE.md) and the [glossary](docs/reference/glossary.md). Full project documentation lives under [`docs/`](docs/).
The main experience is the **Kforge Labs sidebar**. It helps you keep a
project setup together: favorite nodes, saved workflows, reusable modules,
tags, snapshots, and recovery tools.
### Koolook nodes (root package)
## Kforge Labs Sidebar
| Node | Display name | Category | Source |
|------|--------------|----------|--------|
| `EasyWan22Prompt` | Wan 2.2 Easy Prompt (Koolook) | `Koolook/Wan_Video` | `k_easy_wan22_prompt.py` |
| `EasyResize_Koolook` | Easy Resize (Koolook) | `Koolook/Image` | `k_easy_resize.py` |
| `EasyAIPipeline` | Easy AI Pipeline (Koolook) | `Koolook/Pipeline` | `k_ai_pipeline.py` |
| `easy_ImageBatch` | Easy Image Batch (Koolook) | `Koolook/Image` | `k_easy_image_batch.py` |
| `KoolookLoadCameraPosesAbsolute` | Koolook Load Camera Poses (Absolute Path) | `Koolook/Camera` | `k_easy_track.py` |
Use the sidebar as a reusable project kit.
Brief descriptions:
| Feature | What it does |
|---|---|
| **Snapshots** | Save and load the whole Kforge Labs state: favorite nodes, workflows, modules, tags, archive, and recovery data. |
| **Search** | Find nodes, workflows, directories, and tags from one field. Tags keep exact capitalization, so `Depth` and `depth` can be separate folders. |
| **Nodes** | Keep favorite nodes close, grouped by theme or repository name. |
| **Workflows** | Save the whole script, save a selection of nodes, load workflows, or insert saved modules into the current canvas. |
| **Recovery** | Use autosaves, starter presets, snapshot library settings, and missing-pack install helpers. |
- **Wan 2.2 Easy Prompt**: Dynamic prompt builder driven by `config.json` (light source, lighting type, time of day, etc.). Outputs a comma-separated prompt string and optional CLIP conditioning.
- **Easy Resize (Koolook)** — `EasyResize_Koolook`: Aspect-aware image resize that enforces divisibility (e.g., `32`) for model compatibility. Modes: stretch, letterbox, pillarbox; padding and cropping supported. Originally inspired by the `Resize Image V2` node from [kijai/ComfyUI-KJNodes](https://github.com/kijai/ComfyUI-KJNodes) (GPL-3.0 — see [`forks/THIRD_PARTY.md`](forks/THIRD_PARTY.md) for the full attribution + change log). The legacy bare-name `EasyResize` ID is kept as a deprecated alias for saved-workflow compatibility.
- **Easy AI Pipeline**: Aggregates VFX shot parameters (shot duration, seed, base path, shot name, AI method, version) into a fully formatted output file path with overwrite protection. For organized writes from Save EXR / Save Image.
- **Easy Image Batch**: Builds an `IMAGE` + `MASK` batch of length `total_frames` from 1–4 keyframe images placed at explicit frame indices (with `start_frame` offset). Empty frames are filled with black/gray and the mask marks empty=white / occupied=black. Useful for sparse keyframe control with Wan-style video models.
- **Koolook Load Camera Poses (Absolute Path)**: Loads RealEstate10k-style `CAMERACTRL_POSES` from any absolute path (no ComfyUI path stripping), with overrideable pose width/height. Pairs with AnimateDiff CameraCtrl downstream.
New users should start with the bundled visual guide:
[`web/guide/index.html`](web/guide/index.html)
### Radiance Koolook nodes (v2_3_3 fork — video-friendly VAE)
Inside ComfyUI, open it from the Kforge Labs sidebar with **Tools → Info**.
These come from [`forks/radiance_koolook/versions/v2_3_3/`](forks/radiance_koolook/versions/v2_3_3) and load through the root `__init__.py`. They are slim, rank-agnostic re-implementations of the upstream Radiance v2.3.3 VAE encoder/decoder that work correctly with video VAEs (Wan 2.2, Hunyuan, CogVideoX, LTX) — they skip the upstream's 4K cosine-blend tile engine, which conflicts with video VAEs that already handle their own internal stitching.
## Included Nodes
| Node ID | Display name | Category |
|---|---|---|
| `EasyWan22Prompt` | Wan 2.2 Easy Prompt (Koolook) | `Koolook/Wan_Video` |
| `EasyResize_Koolook` | Easy Resize (Koolook) | `Koolook/Image` |
| `EasyAIPipeline` | Easy AI Pipeline (Koolook) | `Koolook/Pipeline` |
| `easy_ImageBatch` | Easy Image Batch (Koolook) | `Koolook/Image` |
| `KoolookLoadCameraPosesAbsolute` | Koolook Load Camera Poses (Absolute Path) | `Koolook/Camera` |
| `Easy_hdr_VAE_encode` | Easy HDR VAE Encode (Koolook) | `Koolook/VAE` |
| `Easy_hdr_VAE_decode` | Easy HDR VAE Decode (Koolook) | `Koolook/VAE` |
> **History note:** the v0.1.0–v0.1.4 releases also shipped a much larger `versions/v1_0_1/` fork that wrapped 26 Radiance v1.0 classes (HDR, EXR, OCIO, log curves, etc.) under the `__koolook_v1_0_1` namespace. Those wrappers were vestigial — never used by Koolook authors — and were removed in v0.1.5. Users who want that functionality should install upstream Radiance directly. See [`forks/THIRD_PARTY.md`](forks/THIRD_PARTY.md) for full attribution and removal rationale.
The root Koolook nodes and the slim Radiance Koolook VAE wrappers have no
extra Python dependencies beyond `torch`, which ComfyUI already requires.
See [`forks/README.md`](forks/README.md) for the full fork workflow.
## Install
## Features
- **Dynamic Inputs for Prompts**: Fields and dropdowns in Wan 2.2 Easy Prompt are defined in `config.json`, allowing easy customization without code changes—great for VFX artists iterating on lighting or camera parameters.
- **Image Resizing with Aspect Control**: Easy Resize ensures precise resolutions for AI models, with options for keep_proportion preservation, padding colors, and device selection (CPU/CUDA). Supports masks for compositing in VFX.
- **Pipeline Path Generation**: Easy AI Pipeline assembles VFX-style output paths and filenames from shot/version inputs, with optional version disabling and overwrite protection.
- **Sparse Keyframe Batches**: Easy Image Batch constructs aligned `IMAGE` + `MASK` batches from up to four keyframe images, ready for sparse video-model control.
- **Camera Pose Loading**: Koolook Load Camera Poses (Absolute Path) reads RealEstate10k pose TXT files from any disk location and emits `CAMERACTRL_POSES`.
- **Startup Loading**: Nodes load configurations at ComfyUI launch; edit `config.json` and restart to update.
- **Output Formatting**: Wan 2.2 Easy Prompt outputs comma-separated strings (skipping "none"), compatible with prompt builders. Easy Resize outputs resized images, masks, and width/height integers.
- **Error Handling**: Fallbacks for missing/invalid JSON in Wan 2.2 Easy Prompt; validation for aspect ratios and divisibility in Easy Resize.
- **Compatibility**: Works with ComfyUI-Manager for easy installation via Git URL. The Koolook root nodes and the slim v2_3_3 VAE wrappers have no extra Python dependencies beyond `torch` (already required by ComfyUI itself).
### ComfyUI-Manager
## RunPod
1. Open ComfyUI Manager.
2. Choose **Install Custom Nodes**.
3. Install by Git URL:
`https://github.com/malkuthro/ComfyUI-Koolook.git`
4. Restart ComfyUI.
5. Open the **Kforge Labs** sidebar tab.
RunPod management has been moved to a separate private repository for active operations and iteration.
### Manual
- Runtime/deployment scaffolding is no longer maintained in this public repo.
- This public repo remains focused on the ComfyUI nodes/plugin code.
## Release & Stability
For production usage, install a pinned stable tag/commit instead of following moving branch heads.
- **Release procedure**: [`docs/maintainers/releasing.md`](docs/maintainers/releasing.md) (canonical, step-by-step)
- **Comfy Registry API** (deprecate / yank versions): [`docs/maintainers/registry-api.md`](docs/maintainers/registry-api.md)
- **Node versioning rules** (how to change a node without breaking saved workflows): [`docs/maintainers/node-versioning.md`](docs/maintainers/node-versioning.md)
- Per-release checklist template: [`.github/ISSUE_TEMPLATE/release_checklist.md`](.github/ISSUE_TEMPLATE/release_checklist.md)
- Change history: [`CHANGELOG.md`](CHANGELOG.md)
- Fork tracking: [`forks/THIRD_PARTY.md`](forks/THIRD_PARTY.md), [`forks/forks_manifest.yaml`](forks/forks_manifest.yaml)
- Fork workflow guide: [`forks/README.md`](forks/README.md)
### Tagging Policy (from now on)
- Repo releases: `vMAJOR.MINOR.PATCH` (example: `v0.2.0`).
- Fork code versions in paths use underscore format: `v1_0_1`, `v2_3_3`.
- Comfy node ID namespace suffixes match fork version paths: `__koolook_v1_0_1`.
- External raw checkout naming:
- pinned: `<repo>-v<version>-koolook`
- rolling upstream: `<repo>-main-upstream`
## Sibling Projects
Some related work lives in **sibling folders/repositories** outside MAIN. They are *consulted* (read-only knowledge sources, references, etc.) but never imported by MAIN at runtime. To keep the public repo free of machine-specific absolute paths, every sibling is referenced through an environment variable.
### Conventions
- Variable prefix: `KOLOOK_*` (matches the existing `KOLOOK_FORKS_DIR`).
- Real paths live in a local, gitignored `.env` file. The committed `.env.example` declares the variable names with placeholder values.
- Public docs and committed code reference siblings only via the env var name (and an optional portable relative default like `../<folder>`). Never hardcode an absolute path with a username.
- A sibling project is a *runtime-optional* reference. If the variable is unset and no default is documented, agents/code must treat the sibling as unavailable and continue gracefully.
### Registered siblings
| Role | Env var | Portable default | Status |
|------|---------|------------------|--------|
| External forks root (raw upstream clones) | `KOLOOK_FORKS_DIR` | `../ComfyUI-Forks` | documented in `forks/forks_manifest.yaml` |
| ComfyUI knowledge database | `KOLOOK_COMFYUI_KB_DIR` | `../ComfyUI_knowledge___DB` | read-only knowledge source |
| Personal knowledge database | `KOLOOK_PERSONAL_KB_DIR` | *(no default — user-specific)* | optional |
### Local setup
Clone this repository into `ComfyUI/custom_nodes/`:
```bash
cp .env.example .env
# Edit .env to point at the real paths on your machine.
git clone https://github.com/malkuthro/ComfyUI-Koolook.git
```
Do **not** commit `.env`. The default `.gitignore` already excludes `.env`, `.env.local`, and `.env.*.local`.
Restart ComfyUI after installation.
## External Fork Workflow (No Vendoring in MAIN)
## Learn More
This repository is the MAIN control repo. Large third-party repositories must stay outside MAIN.
- **Visual sidebar guide:** [`web/guide/index.html`](web/guide/index.html)
- **User guide:** [`docs/user_guide/`](docs/user_guide/)
- **Change history:** [`CHANGELOG.md`](CHANGELOG.md)
- **Maintainer docs:** [`docs/maintainers/`](docs/maintainers/)
- **Fork attribution and provenance:** [`forks/THIRD_PARTY.md`](forks/THIRD_PARTY.md)
- **Versioning reference:** [`docs/reference/versioning.md`](docs/reference/versioning.md)
- Default external forks root (relative): `../ComfyUI-Forks`
- MAIN stores only:
- wrappers under `forks/`
- provenance/tracking under `forks/`
- MAIN does not store full external trees (no vendored copies).
## Stability
### Radiance Koolook Version Layout
- Package entry path: `forks/radiance_koolook/__init__.py`
- Active version path: `forks/radiance_koolook/versions/v2_3_3/`
- Modified node source is local and tracked in MAIN:
- `forks/radiance_koolook/versions/v2_3_3/nodes_vae.py`
- External checkout is reference-only raw upstream:
- default location: `../ComfyUI-Forks/radiance-v2.3.3-koolook`
- baseline used for comparison: upstream commit `f262f47ddfda01ece154bf80c22769b1e4cef795` (the v2.3.3 release commit; the cleanest tag pointing at it is the typo'd `radinace2.3.3`, so we pin by SHA)
- Node IDs in the v2_3_3 fork are exposed verbatim as `Easy_hdr_VAE_encode` / `Easy_hdr_VAE_decode` (the `__koolook_v2_3_3` namespace suffix is skipped via `SKIP_VERSION_SUFFIX` in `versions/v2_3_3/__init__.py` because the Koolook-specific names already differentiate them from upstream).
- Each version folder should include `UPSTREAM_PIN.yaml` to keep parity with external pinned references.
- The historical `v1_0_1` folder was removed in v0.1.5; see [`forks/THIRD_PARTY.md`](forks/THIRD_PARTY.md).
### Version Pinning (Portable Across PCs/macOS)
- Track every external repo in `forks/forks_manifest.yaml` with:
- `source_ref` (tag/version)
- `pinned_commit` (exact hash used in production)
- `external_checkout.relative_path_from_forks_root`
- Keep checkout folder names versioned, e.g.:
- `radiance-v1.0.1-koolook`
- `radiance-v2.3.3-koolook`
### Machine Setup Example
From the parent directory that contains `ComfyUI-Koolook`:
```bash
mkdir -p ../ComfyUI-Forks
cd ../ComfyUI-Forks
git clone https://github.com/fxtdstudios/radiance.git radiance-v1.0.1-koolook
cd radiance-v1.0.1-koolook
git checkout f1b8ae330848fa08aba24c9d3e355cb432d3515b
```
This external folder is for upstream comparison/sync work only.
## Installation
### Via ComfyUI-Manager (Recommended)
1. Open ComfyUI and access the Manager interface.
2. Go to "Install Custom Nodes" > "Install via Git URL".
3. Paste the repository URL: `https://github.com/malkuthro/ComfyUI-Koolook.git`.
4. Install and restart ComfyUI.
5. Nodes appear under these categories in the node search:
- `Koolook/Camera` — Koolook Load Camera Poses (Absolute Path)
- `Koolook/Image` — Easy Resize (Koolook), Easy Image Batch (Koolook)
- `Koolook/Pipeline` — Easy AI Pipeline (Koolook)
- `Koolook/VAE` — Easy HDR VAE Encode/Decode (Koolook)
- `Koolook/Wan_Video` — Wan 2.2 Easy Prompt (Koolook)
### Manual Installation
1. Clone this repository into your `ComfyUI/custom_nodes/` directory:
```
git clone https://github.com/malkuthro/ComfyUI-Koolook.git
```
2. Ensure `__init__.py` and `config.json` are in the cloned folder.
3. Restart ComfyUI.
The root Koolook nodes have no additional Python dependencies. To enable the Radiance Koolook v1.0.1 nodes that handle EXR / OCIO / HDR work, install the optional packages: `OpenEXR`, `Imath`, `PyOpenColorIO`, `colour-science`, `opencv-python`, and `imageio`.
## Usage
### Wan 2.2 Easy Prompt
1. Add the "Wan 2.2 Easy Prompt" node to your workflow under "Koolook/Wan_Video".
2. Select options from the dropdowns (e.g., Light Source: "Sunny lighting", Lighting Type: "Soft lighting").
3. Add custom text in the "body" field for main prompt content.
4. Optionally connect a CLIP for conditioning output.
5. Connect the STRING outputs (combined_prompt or fields_only) to a prompt input, such as the "prompt" slot in the PromptJSON node (from [NeuralSamurAI/ComfyUI-PromptJSON](https://github.com/NeuralSamurAI/ComfyUI-PromptJSON)).
6. To customize fields:
- Edit `config.json` (see example below).
- Restart ComfyUI to apply changes.
7. VFX Tip: Use for generating consistent lighting/shot descriptions in video generation workflows, like with AnimateDiff or SVD.
#### Example config.json
This is the default configuration based on Wan 2.2 parameters:
```json
{
"category": "Koolook/Wan_Video",
"node_name": "Wan_2.2",
"fields": [
{
"name": "light_source",
"type": "combo",
"options": ["none", "Sunny lighting", "Artificial lighting", "Moonlighting", "Practical lighting", "Firelighting", "Fluorescent lighting", "Overcast lighting", "Mixed lighting"],
"default": "none"
},
{
"name": "lighting_type",
"type": "combo",
"options": ["none", "Soft lighting", "Hard lighting", "Top lighting", "Side lighting", "Underlighting", "Edge lighting", "Silhouette lighting", "Low contrast lighting", "High contrast lighting"],
"default": "none"
},
// ... (additional fields like time_of_day, shot_size, etc.)
],
"output_type": "STRING"
}
```
### Easy Resize (Koolook)
1. Add the "Easy Resize (Koolook)" node (ID `EasyResize_Koolook`) to your workflow under "Koolook/Image".
2. Connect an IMAGE (and optional MASK) input.
3. Set the base dimension (Width or Height), base size, aspect ratio (e.g., "16:9" for landscape, "9:16" for portrait), and other options like keep_proportion (stretch, letterbox, pillarbox), pad_color (e.g., "0, 0, 0" for black), crop_position, divisible_by, and device.
4. Connect the outputs: IMAGE and MASK for further processing, INT width/height for resolution-aware nodes like samplers or upscalers.
5. VFX Tip: Use for preprocessing footage in multi-resolution pipelines, ensuring divisibility for efficient GPU processing in tools like IPAdapter or ControlNet.
## Node Code Overview
The core logic is split across files for modularity:
Root Koolook nodes:
- **k_easy_wan22_prompt.py** — loads `config.json` at import time, builds inputs dynamically (combos for dropdowns, strings for text), and formats selections into prompt strings with optional CLIP conditioning.
- **k_easy_resize.py** — parses aspect ratios, computes divisible dimensions, resizes with `common_upscale`, and handles padding/cropping. Inspired by Resize Image V2 from ComfyUI-KJNodes.
- **k_ai_pipeline.py** — `EasyAIPipeline` builds VFX output paths/filenames from shot/version inputs and creates the output directory.
- **k_easy_image_batch.py** — `easy_ImageBatch` builds aligned `IMAGE`+`MASK` keyframe batches with placeholder fill.
- **k_easy_track.py** — `KoolookLoadCameraPosesAbsolute` loads RealEstate10k pose TXT files from any path.
Forked/wrapped nodes:
- **forks/radiance_koolook/** — version-namespaced wrapper for the Radiance fork. Currently exposes the `v2_3_3` set; modified node sources live in `forks/radiance_koolook/versions/v2_3_3/nodes_vae.py`. The wrapper supports the `__koolook_vX_Y_Z` ID suffix pattern but lets specific Koolook-named IDs (like `Easy_hdr_VAE_encode/decode`) ship without the suffix via the `SKIP_VERSION_SUFFIX` set.
- **forks/forks_manifest.yaml**, **forks/THIRD_PARTY.md**, **forks/README.md** — fork tracking metadata.
Glue and frontend:
- **__init__.py** — imports all node packages, merges `NODE_CLASS_MAPPINGS` / `NODE_DISPLAY_NAME_MAPPINGS`, and exposes `WEB_DIRECTORY = "./web"`.
- **web/** — JavaScript extensions loaded by ComfyUI for the Koolook nodes (e.g., `ai_pipeline.js`).
For advanced customizations (e.g., different output formats or additional resize modes), modify the `execute` or `adjust_to_aspect` methods in the respective files.
## Troubleshooting
- **ComfyUI Won't Start**: Check console logs for errors (run `python main.py`). Common: Missing `config.json` or invalid JSON—use a validator like jsonlint.com.
- **No Fields Visible in Wan 2.2 Easy Prompt**: Indicates JSON load failure; the node falls back to empty inputs.
- **Errors in Easy Resize**: Ensure aspect ratio is "w:h" format, divisible_by >=1, and pad_color is "r, g, b" floats (0.0-1.0).
- **Updates**: Pull latest from GitHub and restart.
## Credits
- Based on ComfyUI custom node examples.
- Parameters for Wan 2.2 Easy Prompt derived from Wan 2.2 docs (https://alidocs.dingtalk.com/i/nodes/EpGBa2Lm8aZxe5myC99MelA2WgN7R35y).
- Easy Resize inspired by ComfyUI-KJNodes (https://github.com/kijai/ComfyUI-KJNodes), specifically the Resize Image V2 node in image_nodes.py.
- Compatible with nodes like PromptJSON for LLM workflows.
For production work, install a pinned release tag or commit instead of following
a moving branch head. Node IDs are treated carefully so saved ComfyUI workflows
continue to load across compatible updates.
## License
**GPL-3.0** (see [`LICENSE`](LICENSE)).
**GPL-3.0**. See [`LICENSE`](LICENSE).
This package incorporates and adapts code from
[fxtdstudios/radiance](https://github.com/fxtdstudios/radiance) (also
GPL-3.0) under `forks/radiance_koolook/`. Per GPL-3.0 §5(c), the entire
work is licensed as GPL-3.0. Attribution and per-fork modification notes
are tracked in [`forks/THIRD_PARTY.md`](forks/THIRD_PARTY.md) and
This package incorporates and adapts GPL-3.0 code from
[fxtdstudios/radiance](https://github.com/fxtdstudios/radiance) under
`forks/radiance_koolook/`. Attribution and per-fork modification notes are
tracked in [`forks/THIRD_PARTY.md`](forks/THIRD_PARTY.md) and
[`forks/forks_manifest.yaml`](forks/forks_manifest.yaml).
> **Note for downstream users:** any work that incorporates, links to, or
> derives from `ComfyUI-Koolook` must itself be distributed under GPL-3.0
> (or a compatible license). If you need a non-copyleft license for any
> piece of this code, contact the maintainers — some Koolook-original
> nodes (those with no upstream Radiance lineage) may be available under
> a more permissive license on request.
+2
View File
@@ -22,6 +22,8 @@ attribution is visible without needing a fork-shaped directory tree.
Pages here cover ideas that span more than one node:
- [Kforge Labs sidebar guide](../../web/guide/index.html) — visual onboarding for
Snapshots, favorite nodes, saved workflows, reusable modules, tags, and recovery.
- [VAE encode/decode pairing](nodes/radiance_koolook_v2_3_3/encode_decode_pairing.md) — which
encoder fields must match the decoder for a clean roundtrip, with
worked examples for SDR / HDR / cinema-log / video workflows.
@@ -103,11 +103,8 @@ class Easy_hdr_VAE_encode:
EXTENDED_SOURCE_SPACES,
{
"default": "Linear",
"tooltip": "Color space of the input pixels. "
"Auto-converted to scene-linear Rec.709 before exposure "
"and HDR processing. Log curves (LogC3, LogC4, S-Log3, "
"V-Log, DaVinci Intermediate, Log3G10) and ACES variants "
"(ACEScg, ACES 2065-1) are decoded properly.",
"tooltip": "Input color space. Converted to scene-linear "
"Rec.709 before exposure and HDR handling.",
},
),
},
@@ -119,41 +116,29 @@ class Easy_hdr_VAE_encode:
"min": -10.0,
"max": 10.0,
"step": 0.1,
"tooltip": "Exposure adjustment in stops, applied in "
"linear space (correct semantics regardless of input "
"color space).",
"tooltip": "Exposure in stops, applied after color conversion.",
},
),
"alpha_handling": (
["Preserve", "Ignore"],
{
"default": "Preserve",
"tooltip": "Preserve: surface input alpha as the third "
"IMAGE output (zeros if input had no alpha). "
"Ignore: always emit zeros for alpha.",
"tooltip": "Preserve input alpha, or emit blank alpha.",
},
),
"hdr_mode": (
HDR_MODES,
{
"default": "Soft Clip",
"tooltip": "How to handle values outside [0,1] before "
"encoding. Clip (SDR): hard clamp. Soft Clip: tanh "
"rolloff above 0.85. Compress (Log): encode through a "
"cinema log curve (uses source_space if it is a log "
"space, otherwise ARRI LogC4) — pairs with the same "
"hdr_mode on decode for HDR-clean roundtrips. "
"Passthrough: no clamp.",
"tooltip": "Out-of-range handling before encode. Match this "
"setting on decode for roundtrips.",
},
),
"latent_sampling": (
LATENT_SAMPLING_MODES,
{
"default": "sample",
"tooltip": "How to sample from the VAE posterior. "
"'sample' is ComfyUI's default (random). 'mean' or "
"'mode' are deterministic — best for img2img where "
"you want minimum reconstruction noise.",
"tooltip": "sample is random; mean/mode are deterministic.",
},
),
},
@@ -164,11 +149,8 @@ class Easy_hdr_VAE_encode:
FUNCTION = "encode"
CATEGORY = "Koolook/VAE"
DESCRIPTION = (
"Encode 32-bit Linear / ACEScg / cinema-log images or image "
"sequences (video) to VAE latents. 12 source spaces, 4 HDR "
"modes, deterministic sampling option, real alpha roundtrip. "
"Skips upstream Radiance's 4K tile engine for compatibility "
"with video VAEs (Wan 2.2, Hunyuan, CogVideoX, LTX)."
"Encode Linear, ACES, or cinema-log images/video to VAE latents. "
"Use matching HDR settings on decode for clean roundtrips."
)
def encode(
@@ -328,8 +310,7 @@ class Easy_hdr_VAE_decode:
EXTENDED_TARGET_SPACES,
{
"default": "Linear",
"tooltip": "Color space to convert the decoded image into. "
"Same 12 spaces as the encoder.",
"tooltip": "Output color space for the decoded image.",
},
),
},
@@ -341,29 +322,21 @@ class Easy_hdr_VAE_decode:
"min": -10.0,
"max": 10.0,
"step": 0.1,
"tooltip": "Exposure adjustment in stops, applied in "
"linear space for correctness.",
"tooltip": "Exposure in stops, applied in linear space.",
},
),
"hdr_mode": (
HDR_MODES,
{
"default": "Clip (SDR)",
"tooltip": "Must match the encode setting. "
"Compress (Log): inverts log-curve encoding with "
"soft-shoulder + log-space highlight denoise for "
"clean HDR output. Soft Clip / Passthrough: extended "
"sRGB EOTF. Clip (SDR): standard sRGB EOTF.",
"tooltip": "Match the encode HDR mode for roundtrips.",
},
),
"source_space": (
EXTENDED_SOURCE_SPACES,
{
"default": "Linear",
"tooltip": "Only used with hdr_mode='Compress (Log)' "
"to identify which log curve was used at encode. "
"Set this to whatever you set source_space to on "
"the encoder. Ignored for other hdr_modes.",
"tooltip": "For Compress (Log), match the encoder source_space.",
},
),
},
@@ -374,11 +347,8 @@ class Easy_hdr_VAE_decode:
FUNCTION = "decode"
CATEGORY = "Koolook/VAE"
DESCRIPTION = (
"Decode VAE latents (image or video) directly to 32-bit "
"Linear / ACEScg / cinema-log images. 12 target spaces, "
"Compress (Log) HDR pipeline with soft-shoulder + log denoise. "
"Rank-agnostic — works with whatever tensor shape the underlying "
"VAE returns."
"Decode image or video VAE latents to Linear, ACES, or cinema-log "
"images. Match encode HDR settings for clean roundtrips."
)
def decode(
+4 -10
View File
@@ -52,15 +52,9 @@ class EasyResize:
FUNCTION = "adjust_to_aspect"
CATEGORY = "Koolook/Image"
DESCRIPTION = """
Adjusts the input image to a target resolution based on a base dimension (width or height),
an aspect ratio (e.g., '16:9' for landscape, '9:16' for portrait), ensuring both dimensions
are divisible by the specified value. Supports stretch or pad/crop modes for proportion control.
Outputs the resized image, optional mask, and final width/height for VFX pipeline integration.
Also outputs a solid color panel (canvas) of the target size using the specified panel_color_mode and optional custom panel_color.
When selecting 'Custom' for pad_color_mode or panel_color_mode, enter the color in the corresponding field as comma-separated floats, e.g., '0.5, 0.5, 0.5' for gray.
The 'composed_IMAGE' is the resized image composited onto the color panel using the mask (if provided; falls back to resized image if no mask).
If 'invert_composed_MASK' is enabled, the composed_IMAGE will use an inverted mask for compositing (swapping the roles of image and panel).
The 'inverted_MASK' is the inverted version of the mask (if provided).
Resize an image to a target aspect ratio and model-friendly divisible size.
Use stretch, letterbox, or pillarbox; optional masks can produce a composed
image, inverted mask, color panel, and final/original size outputs.
"""
def adjust_to_aspect(self, image, base_on, base_size, aspect_ratio, upscale_method, keep_proportion, pad_color_mode, crop_position, divisible_by, device, panel_color_mode, mask=None, pad_color="0, 0, 0", panel_color="0, 0, 0", invert_composed_MASK=False):
@@ -248,4 +242,4 @@ NODE_CLASS_MAPPINGS = {
NODE_DISPLAY_NAME_MAPPINGS = {
"EasyResize_Koolook": "Easy Resize (Koolook)",
"EasyResize": "Easy Resize (deprecated, use 'Easy Resize (Koolook)')",
}
}
+525
View File
@@ -0,0 +1,525 @@
/* SPDX-FileCopyrightText: 2025-2026 Kforge Labs <https://github.com/malkuthro/ComfyUI-Koolook> */
/* SPDX-License-Identifier: GPL-3.0-only */
:root {
color-scheme: dark;
/* ForgeFlow-inspired static guide skin.
Source reference: ../ForgeFlow/docs/UI_DESIGN_SYSTEM.md */
--bg: #0e0e0e;
--panel: #151515;
--panel-2: #1a1a1f;
--titlebar: #24242c;
--text: #f9fafb;
--muted: #707982;
--muted-deep: #4d535d;
--line: #302f2f;
--blue: #4268ba;
--sky: #052f4a;
--sky-hover: #1a6d94;
--green: #4a8058;
--amber: #461901;
--purple: #452e83;
--pink: #77234d;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
min-width: 320px;
background:
radial-gradient(rgba(150, 150, 150, 0.08) 1px, transparent 1px),
var(--bg);
background-size: 13px 13px;
color: var(--text);
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
.hero,
main {
width: min(1180px, calc(100% - 32px));
margin: 0 auto;
}
.hero {
padding: 48px 0 24px;
}
.eyebrow {
margin: 0 0 8px;
color: var(--blue);
font-size: 12px;
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
}
h1,
h2,
h3,
p {
margin-top: 0;
}
h1 {
max-width: 780px;
margin-bottom: 14px;
font-size: clamp(34px, 7vw, 68px);
line-height: 1;
letter-spacing: 0;
}
h2 {
margin-bottom: 12px;
font-size: clamp(27px, 4vw, 42px);
line-height: 1.05;
letter-spacing: 0;
}
h3 {
margin-bottom: 8px;
font-size: 18px;
letter-spacing: 0;
}
.lead {
max-width: 700px;
color: var(--muted);
font-size: 19px;
}
.section {
display: grid;
grid-template-columns: minmax(240px, 0.82fr) minmax(0, 1.18fr);
gap: 28px;
align-items: center;
padding: 34px 0;
}
.section-copy {
max-width: 440px;
padding-left: 16px;
border-left: 4px solid var(--blue);
}
.section-copy.wide {
max-width: 720px;
grid-column: 1 / -1;
}
.section-copy p,
.band > p,
.cards p,
figcaption {
color: var(--muted);
}
.visual {
margin: 0;
}
.visual img {
display: block;
width: 100%;
height: auto;
border: 1px solid var(--line);
background: var(--panel);
border-radius: 8px;
}
.overview-map {
display: grid;
grid-template-columns: minmax(240px, 0.78fr) minmax(220px, 0.72fr);
gap: 48px;
align-items: center;
padding: 22px 28px 22px 22px;
border: 1px solid var(--line);
border-radius: 8px;
background: #101010;
}
.overview-shot {
position: relative;
width: min(100%, 450px);
margin: 0 auto;
overflow: visible;
}
.overview-shot img {
border-color: #3c3c3c;
background: #151515;
}
.overview-box {
position: absolute;
right: -18px;
width: 4px;
border: 0;
border-radius: 999px;
background: currentColor;
opacity: 0.78;
pointer-events: none;
}
.overview-box::after {
content: none;
}
.overview-snapshot {
top: 1.8%;
height: 6.8%;
color: #4a8058;
}
.overview-tools {
top: 9.7%;
height: 6.4%;
color: #4268ba;
}
.overview-search {
top: 17.8%;
height: 5.6%;
color: #d59b3d;
}
.overview-nodes {
top: 26.2%;
height: 8.2%;
color: #b64747;
}
.overview-workflows {
top: 34.9%;
height: 8%;
color: #452e83;
}
.overview-saved {
top: 43.5%;
height: 51.8%;
color: #4a8058;
}
.overview-callouts {
display: grid;
gap: 22px;
}
.overview-callout {
position: relative;
padding-left: 18px;
color: var(--blue);
}
.overview-callout::before {
content: "";
position: absolute;
top: 4px;
bottom: 4px;
left: 0;
width: 4px;
border-radius: 999px;
background: currentColor;
opacity: 0.82;
}
.overview-callout::after {
content: none;
}
.overview-callout h3 {
margin: 0 0 2px;
color: currentColor;
font-size: 20px;
}
.overview-callout p {
margin: 0;
color: var(--muted);
font-size: 14px;
}
.overview-callout.snapshot::before,
.overview-callout.saved::before,
.overview-callout.snapshot,
.overview-callout.saved {
color: var(--green);
}
.overview-callout.tools {
color: var(--blue);
}
.overview-callout.search {
color: #d59b3d;
}
.overview-callout.nodes {
color: #b64747;
}
.overview-callout.workflows {
color: var(--purple);
}
figcaption {
margin-top: 10px;
color: var(--muted);
font-size: 13px;
}
.band {
margin: 28px 0;
padding: 0;
border: 1px solid var(--line);
border-radius: 6px;
background: var(--panel);
overflow: hidden;
}
.band > div {
position: relative;
padding: 16px 22px;
background: var(--panel);
border-bottom: 1px solid var(--line);
}
.band > div::before {
content: "";
position: absolute;
inset: 0 auto 0 0;
width: 4px;
background: var(--green);
}
.band > p {
max-width: 760px;
padding: 18px 22px 0;
font-size: 17px;
}
.full {
margin: 18px 22px 22px;
}
.steps {
margin: 0;
padding-left: 20px;
color: var(--muted);
}
.steps li {
margin-bottom: 9px;
}
.steps strong {
color: var(--text);
font-weight: 650;
}
.cards {
display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr));
gap: 12px;
padding: 30px 0;
}
.cards article {
position: relative;
min-height: 142px;
padding: 18px 16px 16px 20px;
border: 1px solid var(--line);
border-radius: 6px;
background: var(--panel);
overflow: hidden;
}
.cards article::before {
content: "";
position: absolute;
inset: 0 auto 0 0;
width: 4px;
background: var(--blue);
}
.cards article:nth-child(2)::before {
background: var(--sky-hover);
}
.cards article:nth-child(3)::before {
background: var(--purple);
}
.cards article:nth-child(4)::before {
background: var(--green);
}
.cards article:nth-child(5)::before {
background: var(--pink);
}
.function-list {
display: flex;
flex-wrap: wrap;
gap: 7px;
margin-top: 14px;
}
.function-list span {
display: inline-flex;
align-items: center;
min-height: 28px;
padding: 4px 8px;
border: 1px solid #3d3d3d;
border-radius: 4px;
background: #1a1a1f;
color: var(--text);
font-size: 12px;
font-weight: 700;
line-height: 1.2;
}
.recipes {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 18px;
padding: 34px 0 64px;
}
.recipe-real {
padding: 14px;
border: 1px solid var(--line);
border-radius: 8px;
background: var(--panel);
}
.recipe-real img {
border-color: #454545;
background: #101010;
}
.recipe-shot {
position: relative;
}
.focus-dot {
position: absolute;
width: 72px;
height: 72px;
border-radius: 999px;
background: rgb(66 104 186 / 30%);
box-shadow: 0 0 0 2px rgb(66 104 186 / 88%);
pointer-events: none;
}
.focus-save {
right: 3%;
bottom: 7%;
}
.focus-load {
left: 7%;
top: 39%;
}
.focus-module {
right: 0.5%;
bottom: 0.5%;
background: rgb(201 148 75 / 30%);
box-shadow: 0 0 0 2px rgb(201 148 75 / 88%);
}
.focus-node-search {
left: 12%;
top: 19%;
background: rgb(74 128 88 / 30%);
box-shadow: 0 0 0 2px rgb(74 128 88 / 88%);
}
.focus-workflow-search {
left: 10%;
top: 16%;
background: rgb(69 46 131 / 30%);
box-shadow: 0 0 0 2px rgb(69 46 131 / 88%);
}
.recipe-callout {
width: fit-content;
max-width: min(520px, calc(100% - 44px));
margin: 18px auto 0;
padding: 14px 18px 14px 22px;
border-left: 5px solid var(--blue);
border-radius: 8px;
background: #111111;
box-shadow: 0 14px 30px rgb(0 0 0 / 26%);
}
.recipe-callout p {
margin: 0;
color: var(--muted);
font-size: 17px;
line-height: 1.55;
}
.recipe-callout strong {
color: var(--text);
font-size: 18px;
font-weight: 800;
}
.recipe-callout.amber {
border-left-color: #c9944b;
}
.recipe-callout.green {
border-left-color: var(--green);
}
.recipe-callout.purple {
border-left-color: var(--purple);
}
@media (max-width: 980px) {
.cards {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 860px) {
.section,
.recipes {
grid-template-columns: 1fr;
}
.overview-map {
grid-template-columns: 1fr;
}
.cards article {
min-height: 0;
}
}
@media (max-width: 520px) {
.hero,
main {
width: min(100% - 20px, 1180px);
}
.hero {
padding-top: 34px;
}
.band {
padding: 18px;
}
.cards {
grid-template-columns: 1fr;
}
}
+26
View File
@@ -0,0 +1,26 @@
<svg xmlns="http://www.w3.org/2000/svg" width="900" height="600" viewBox="0 0 900 600" role="img" aria-labelledby="title desc">
<title id="title">Autosave recovery recipe</title>
<desc id="desc">Annotated mock screenshot for recovering from autosaves.</desc>
<rect width="900" height="600" fill="#131315"/>
<g font-family="Arial, sans-serif">
<rect x="82" y="92" width="300" height="396" rx="18" fill="#151515" stroke="#302f2f"/>
<text x="112" y="136" fill="#f9fafb" font-size="24" font-weight="700">Load Snapshot</text>
<rect x="112" y="176" width="240" height="52" rx="9" fill="#0e0e0e" stroke="#302f2f"/>
<text x="136" y="209" fill="#f9fafb" font-size="16">Client_Shot010</text>
<rect x="112" y="246" width="240" height="52" rx="9" fill="#0e0e0e" stroke="#302f2f"/>
<text x="136" y="279" fill="#f9fafb" font-size="16">Lookdev_HDR</text>
<text x="112" y="348" fill="#4268ba" font-size="15" font-weight="700">AUTOSAVES</text>
<rect x="112" y="368" width="240" height="52" rx="9" fill="#162556" stroke="#4268ba"/>
<text x="136" y="401" fill="#f9fafb" font-size="15">_autosave_periodic_01</text>
<path d="M352 394 H548" stroke="#4268ba" stroke-width="4"/>
<path d="M548 394 l-18 -12 v24 z" fill="#4268ba"/>
<rect x="574" y="296" width="250" height="172" rx="16" fill="#1a1a1f" stroke="#4268ba"/>
<text x="602" y="342" fill="#f9fafb" font-size="25" font-weight="700">Recover safely</text>
<text x="602" y="384" fill="#707982" font-size="17">Autosaves are kept in the</text>
<text x="602" y="410" fill="#707982" font-size="17">same Snapshot library.</text>
<text x="602" y="436" fill="#707982" font-size="17">Load one if state was lost.</text>
<rect x="574" y="114" width="250" height="122" rx="16" fill="#1a1a1f" stroke="#c9944b"/>
<text x="602" y="160" fill="#f9fafb" font-size="25" font-weight="700">Library folder</text>
<text x="602" y="202" fill="#707982" font-size="17">Set it per project or facility.</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

+18
View File
@@ -0,0 +1,18 @@
<svg xmlns="http://www.w3.org/2000/svg" width="760" height="640" viewBox="0 0 760 640" role="img" aria-labelledby="title desc">
<title id="title">Project workflow</title>
<desc id="desc">Six step workflow for using snapshots and modules.</desc>
<rect width="760" height="640" fill="#151515"/>
<g font-family="Arial, sans-serif">
<text x="56" y="62" fill="#4268ba" font-size="15" font-weight="700" letter-spacing="2">PROJECT RHYTHM</text>
<text x="56" y="106" fill="#f9fafb" font-size="32" font-weight="700">Use one snapshot per project context.</text>
<g transform="translate(56 150)" fill="#707982" font-size="18">
<circle cx="26" cy="30" r="24" fill="#4268ba"/><text x="20" y="37" fill="#0e0e0e" font-weight="700">1</text><text x="74" y="37" fill="#f9fafb">Load or create Client_Shot010.</text>
<circle cx="26" cy="110" r="24" fill="#4a8058"/><text x="20" y="117" fill="#0e0e0e" font-weight="700">2</text><text x="74" y="117" fill="#f9fafb">Add favorite nodes while building.</text>
<circle cx="26" cy="190" r="24" fill="#c9944b"/><text x="20" y="197" fill="#0e0e0e" font-weight="700">3</text><text x="74" y="197" fill="#f9fafb">Save reusable clusters as modules.</text>
<circle cx="26" cy="270" r="24" fill="#452e83"/><text x="20" y="277" fill="#0e0e0e" font-weight="700">4</text><text x="74" y="277" fill="#f9fafb">Quick Save during the session.</text>
<circle cx="26" cy="350" r="24" fill="#a04040"/><text x="20" y="357" fill="#0e0e0e" font-weight="700">5</text><text x="74" y="357" fill="#f9fafb">Save named snapshots by shot or task.</text>
<circle cx="26" cy="430" r="24" fill="#4a8058"/><text x="20" y="437" fill="#0e0e0e" font-weight="700">6</text><text x="74" y="437" fill="#f9fafb">Load the right kit when you return.</text>
<path d="M26 55 V85 M26 135 V165 M26 215 V245 M26 295 V325 M26 375 V405" stroke="#302f2f" stroke-width="4"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

+37
View File
@@ -0,0 +1,37 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="520" viewBox="0 0 1200 520" role="img" aria-labelledby="title desc">
<title id="title">Snapshot mental model</title>
<desc id="desc">Sidebar state becomes a snapshot file in a library, then can be loaded later.</desc>
<rect width="1200" height="520" fill="#131315"/>
<g font-family="Arial, sans-serif">
<text x="60" y="72" fill="#4268ba" font-size="17" font-weight="700" letter-spacing="2">MENTAL MODEL</text>
<text x="60" y="116" fill="#f9fafb" font-size="34" font-weight="700">Snapshot saves the whole project kit.</text>
<g transform="translate(72 178)">
<rect width="210" height="190" rx="16" fill="#1a1a1f" stroke="#302f2f"/>
<text x="24" y="42" fill="#f9fafb" font-size="22" font-weight="700">Sidebar state</text>
<text x="24" y="82" fill="#707982" font-size="16">favorite nodes</text>
<text x="24" y="112" fill="#707982" font-size="16">workflows / modules</text>
<text x="24" y="142" fill="#707982" font-size="16">tags</text>
</g>
<path d="M306 273 H430" stroke="#4268ba" stroke-width="4"/>
<path d="M430 273 l-18 -12 v24 z" fill="#4268ba"/>
<g transform="translate(456 178)">
<rect width="210" height="190" rx="16" fill="#162556" stroke="#4268ba"/>
<text x="24" y="42" fill="#f9fafb" font-size="22" font-weight="700">Snapshot file</text>
<text x="24" y="82" fill="#707982" font-size="16">Client_Shot010</text>
<text x="24" y="112" fill="#707982" font-size="16">portable JSON</text>
<text x="24" y="142" fill="#707982" font-size="16">saved on disk</text>
</g>
<path d="M690 273 H814" stroke="#4a8058" stroke-width="4"/>
<path d="M814 273 l-18 -12 v24 z" fill="#4a8058"/>
<g transform="translate(840 178)">
<rect width="260" height="190" rx="16" fill="#1a1a1f" stroke="#302f2f"/>
<text x="24" y="42" fill="#f9fafb" font-size="22" font-weight="700">Project library</text>
<text x="24" y="82" fill="#707982" font-size="16">one folder for a show</text>
<text x="24" y="112" fill="#707982" font-size="16">or one per client</text>
<text x="24" y="142" fill="#707982" font-size="16">load it later</text>
</g>
<path d="M970 388 V432 H177 V392" fill="none" stroke="#c9944b" stroke-width="4"/>
<path d="M177 392 l-12 18 h24 z" fill="#c9944b"/>
<text x="418" y="462" fill="#c9944b" font-size="19" font-weight="700">Return to the project without rebuilding your setup</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

+214
View File
@@ -0,0 +1,214 @@
<!--
SPDX-FileCopyrightText: 2025-2026 Kforge Labs <https://github.com/malkuthro/ComfyUI-Koolook>
SPDX-License-Identifier: GPL-3.0-only
-->
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Kforge Labs Sidebar Guide</title>
<link rel="stylesheet" href="./guide.css">
</head>
<body>
<header class="hero">
<p class="eyebrow">Kforge Labs</p>
<h1>Use the sidebar as a project kit.</h1>
<p class="lead">Save the nodes, modules, workflows, tags, and snapshot state you need for a project, then load that setup again when the work comes back.</p>
</header>
<main>
<section class="section">
<div class="section-copy">
<p class="eyebrow">Start here</p>
<h2>The sidebar has six main areas.</h2>
<p>Snapshot, Tools, Search, Nodes, Workflows, and saved lists work together to keep each project kit easy to save, find, and reload.</p>
</div>
<figure class="visual">
<div class="overview-map">
<div class="overview-shot">
<img src="./img/screenshots/sidebar-overview.png" alt="Kforge Labs sidebar overview screenshot">
<span class="overview-box overview-snapshot" aria-hidden="true"></span>
<span class="overview-box overview-tools" aria-hidden="true"></span>
<span class="overview-box overview-search" aria-hidden="true"></span>
<span class="overview-box overview-nodes" aria-hidden="true"></span>
<span class="overview-box overview-workflows" aria-hidden="true"></span>
<span class="overview-box overview-saved" aria-hidden="true"></span>
</div>
<div class="overview-callouts" aria-label="Sidebar sections">
<article class="overview-callout snapshot">
<h3>Snapshot row</h3>
<p>Load, Quick Save, Save, Settings.</p>
</article>
<article class="overview-callout tools">
<h3>Tools row</h3>
<p>Maintenance plus the Help guide.</p>
</article>
<article class="overview-callout search">
<h3>Search</h3>
<p>Find nodes, workflows, folders, and tags.</p>
</article>
<article class="overview-callout nodes">
<h3>Nodes action bar</h3>
<p>Switch tree or list view, then add a favorite node.</p>
</article>
<article class="overview-callout workflows">
<h3>Workflows action bar</h3>
<p>Save the canvas or selected nodes, then browse saved workflows.</p>
</article>
<article class="overview-callout saved">
<h3>Saved lists</h3>
<p>Nodes, Workflows, and Tags stay visible below.</p>
</article>
</div>
</div>
<figcaption>First read the sidebar from top to bottom: Snapshot, Tools, Search, Nodes, Workflows, Tags.</figcaption>
</figure>
</section>
<section class="band">
<div>
<p class="eyebrow">Most important idea</p>
<h2>Snapshot = your project kit</h2>
</div>
<p>A Snapshot saves Kforge Labs state: favorite nodes, saved workflows, modules, tags, archive, and the current sidebar organization. Use one named snapshot per project, shot, client, or experiment.</p>
<figure class="visual full">
<img src="./img/snapshot-flow.svg" alt="Snapshot flow from sidebar state to saved file to project library and later reload">
</figure>
</section>
<section class="section">
<div class="section-copy">
<p class="eyebrow">Project rhythm</p>
<h2>A simple workflow</h2>
<ol class="steps">
<li>Load or create a snapshot, for example <strong>Client_Shot010</strong>.</li>
<li>Add favorite nodes while building the shot.</li>
<li>Save reusable node clusters as modules.</li>
<li>Quick Save during the session.</li>
<li>Save named snapshots for each project, shot, or task.</li>
<li>Load the right snapshot when you return.</li>
</ol>
</div>
<figure class="visual">
<img src="./img/project-workflow.svg" alt="Six step project workflow for snapshots and modules">
<figcaption>The goal is not to remember every button. The goal is to keep each project setup reusable.</figcaption>
</figure>
</section>
<section class="cards" aria-label="Main sidebar functions">
<article>
<h3>Snapshots</h3>
<p>Save and reload the whole project kit.</p>
<div class="function-list" aria-label="Snapshot functions">
<span>Load</span>
<span>Quick Save</span>
<span>Save</span>
<span>Settings</span>
</div>
</article>
<article>
<h3>Nodes</h3>
<p>Keep favorite nodes organized and easy to update.</p>
<div class="function-list" aria-label="Node functions">
<span>Search</span>
<span>Add</span>
<span>Remove</span>
<span>Group</span>
</div>
</article>
<article>
<h3>Search</h3>
<p>Find saved work from one field. Tags keep exact capitalization.</p>
<div class="function-list" aria-label="Search functions">
<span>Nodes</span>
<span>Workflows</span>
<span>Folders</span>
<span>Tags</span>
</div>
</article>
<article>
<h3>Workflows</h3>
<p>Save full scripts or reusable node selections.</p>
<div class="function-list" aria-label="Workflow functions">
<span>Save script</span>
<span>Save selection</span>
<span>Load</span>
<span>Insert module</span>
</div>
</article>
<article>
<h3>Safety / setup</h3>
<p>Quiet helpers protect projects and make saved kits portable.</p>
<div class="function-list" aria-label="Safety and setup functions">
<span>Autosaves</span>
<span>Missing packs</span>
<span>Starter preset</span>
<span>Library folder</span>
</div>
</article>
</section>
<section class="recipes">
<div class="section-copy wide">
<p class="eyebrow">Visual recipes</p>
<h2>Common things you will do</h2>
</div>
<figure class="visual recipe-real">
<div class="recipe-shot">
<img src="./img/screenshots/save-snapshot.png" alt="Save snapshot dialog showing library folder and save options">
<span class="focus-dot focus-save" aria-hidden="true"></span>
</div>
<div class="recipe-callout blue" aria-label="Save snapshot notes">
<p><strong>Save</strong> updates the current project kit. <strong>Save as new</strong> creates another named snapshot.</p>
</div>
<figcaption>Save the current sidebar state as a named project snapshot.</figcaption>
</figure>
<figure class="visual recipe-real">
<div class="recipe-shot">
<img src="./img/screenshots/load-snapshot.png" alt="Load snapshot dialog showing saved snapshots and recovery autosaves">
<span class="focus-dot focus-load" aria-hidden="true"></span>
</div>
<div class="recipe-callout blue" aria-label="Load snapshot notes">
<p><strong>Snapshot row</strong> restores that saved project kit. <strong>Recovery auto-saves</strong> are available below saved snapshots.</p>
</div>
<figcaption>Load a snapshot when you switch projects or return to a shot.</figcaption>
</figure>
<figure class="visual recipe-real module-recipe">
<div class="recipe-shot">
<img src="./img/screenshots/all-icons-new.png" alt="Sidebar toolbar screenshot with workflow save-selection highlighted">
<span class="focus-dot focus-module" aria-hidden="true"></span>
</div>
<div class="recipe-callout amber" aria-label="Save selected nodes as module notes">
<p><strong>Workflow save-selection</strong> is the bottom-right workflow action. Use it after selecting nodes on the canvas.</p>
</div>
<figcaption>Save selected nodes as a module, then insert that module into another canvas.</figcaption>
</figure>
<figure class="visual recipe-real">
<div class="recipe-shot">
<img src="./img/screenshots/search-C.png" alt="Search results showing matching favorite nodes">
<span class="focus-dot focus-node-search" aria-hidden="true"></span>
</div>
<div class="recipe-callout green" aria-label="Node search notes">
<p><strong>Node search</strong> narrows favorites so useful nodes are easier to scan and add.</p>
</div>
<figcaption>Search narrows the Nodes list so useful favorites are easier to scan and add.</figcaption>
</figure>
<figure class="visual recipe-real">
<div class="recipe-shot">
<img src="./img/screenshots/search-B.png" alt="Search results showing matching nodes and workflows">
<span class="focus-dot focus-workflow-search" aria-hidden="true"></span>
</div>
<div class="recipe-callout purple" aria-label="Workflow search notes">
<p><strong>One search field</strong> finds nodes and workflows, including saved workflows found through tags.</p>
</div>
<figcaption>Search finds both nodes and workflows from the same field, including saved workflows found through tags.</figcaption>
</figure>
<figure class="visual">
<img src="./img/autosave-recovery.svg" alt="Annotated mockup showing autosave recovery">
<figcaption>If something goes sideways, load an autosave from the Snapshot Load dialog.</figcaption>
</figure>
</section>
</main>
</body>
</html>
+1
View File
@@ -79,6 +79,7 @@ export const WORKFLOWS_FALLBACK_KEY = "koolook.workflows.fallback.v1";
export const WORKFLOWS_SEEDED_KEY = "koolook.workflows.seeded.v1";
export const WORKFLOWS_CHANGED_EVENT = "koolook-workflows-changed";
export const WORKFLOWS_DEFAULTS_URL = new URL("../workflow_defaults.json", import.meta.url).href;
export const GUIDE_URL = new URL("../guide/index.html", import.meta.url).href;
// Convention-driven "module" classification — a saved workflow tagged with
// this literal string is treated as a reusable building block (insert into
+8 -4
View File
@@ -23,6 +23,7 @@ import {
GROUP_MODE_KEY,
GROUP_MODE_DEFAULT,
MODULE_TAG,
GUIDE_URL,
ensureStyle,
toast,
compareNames,
@@ -118,8 +119,6 @@ const SECTION_ID_WORKFLOWS = "workflows";
const SECTION_ID_TAGS = "tags";
const SVG_NS = "http://www.w3.org/2000/svg";
const HELP_URL = "https://github.com/malkuthro/ComfyUI-Koolook/tree/main/docs/user_guide";
const TOOLBAR_ICONS = {
loadSnapshot: { kind: "letter", text: "L" },
saveSnapshot: { kind: "letter", text: "S" },
@@ -2452,8 +2451,13 @@ export function renderPanel(container) {
toolsRow.appendChild(makeToolbarButton({
icon: TOOLBAR_ICONS.help,
title: "Open Kforge Labs user guide",
onClick: () => window.open(HELP_URL, "_blank", "noopener,noreferrer"),
title: "Open the Kforge Labs visual guide",
onClick: () => {
const opened = window.open(GUIDE_URL, "_blank", "noopener,noreferrer");
if (!opened) {
toast("Could not open the guide. Allow pop-ups for this page, then try again.");
}
},
}));
container.appendChild(toolsRow);