ComfyUI-PerfectLab
Visual prompt builder for ComfyUI: lighting clock, camera & film, palettes, random categories, template forms and a Shot Series node that turns one person description into a whole photo session. SDXL / Flux / Z-Image / Qwen-Image / Wan.
Nodes (4)
A prompt builder that lives on the canvas
Merge two prompt lists without the 3×7 explosion
Describe the person once, get the whole contact sheet
Pull one prompt out of a batch by number
🧪 PerfectLab — Prompt Assistant for ComfyUI
<p align="center"> <img src="docs/02-node-form.png" alt="PerfectLab Prompt Assistant node: template form, lighting clock, camera, palette and categories, with the assembled prompt previewed in a text node" width="560"> </p>An interactive visual prompt-builder node with a full-featured UI embedded directly in the ComfyUI canvas. Build cinematic, controlled prompts without touching raw text: pick lighting by hour of day, assemble a camera rig, enforce a color palette, and manage randomizable prompt categories with per-category lock/random modes.
The node includes a live preview of the final assembled prompt (connect the PROMPT output to a text preview node, as shown above).
Features
🕐 Lighting Engine

Select an hour of day with the slider or the interactive 24-hour clock and get a matching cinematic lighting description — from deep night to blue hour, golden sunrise to noir.
📷 Camera & Film Builder

Mix device, vibe, lens, film stock and studio lighting into a single camera tag — Sony A7IV + Kodak Portra + Rembrandt lighting, a disposable cam with harsh flash, or anything in between.
🎨 Color Palette

Pick up to 5 colors with modifier presets (Neon, Pastel, Matte, Metallic, ...) to enforce a color scheme.
🗂 Categories

Your own wildcard-style prompt lists:
- LCK (lock) — always uses the selected item.
- RND (random) — picks a random item, driven by the node seed (deterministic and reproducible).
- Matrix view with search, A-Z / usage sorting and usage counters.
Also
- 🎞 Variations — the
variationsinput produces N seeded variations per run as a list (seed, seed+1, ...); ComfyUI iterates it downstream automatically — one run, a whole contact sheet of prompts. - ↔ NEGATIVE output — an optional second output with its own base text and categories, edited in the node's NEG tab. Leave it unconnected if you don't need it.
{a|b|c}dynamic choices — inline alternatives in the base prompt or in any category item, resolved from the seed (nesting supported).{{name}}template fields — put{{outfit}}or{{mood|calm|stormy}}anywhere in the base prompt and a form field appears in the node: fill it with fixed text, or leave it empty with options to roll a fresh choice per variation.- 👤 Characters — save the current set of categories under a name and re-apply it to any node (or to the NEGATIVE tab) with one click.
- 📁 Wildcard files —
__filename__in any text pulls lines fromwildcards/filename.txtin the node folder; files are re-read when they change on disk. - 🔁 Campaign mode (CYC) — a category can advance to its next item every N seeds instead of rolling, so a seed range walks through a whole list in order.
- ⚠ Prompt linter — the badge in the header flags token overflow, duplicate items, unbalanced braces, pointless single-item randoms and an empty NEGATIVE.
- ⬇ Category import — paste JSON or a markdown list, or copy the built-in LLM prompt, let a chat model split your idea into categories, and paste the result back.
- 🌐 UI languages — the header button switches the panel between English, Russian and Chinese.
- 🧩 Companion nodes —
Concatmerges two prompt streams element-wise,Splitpicks one line from a stream by index (negative index counts from the end). Both carry the same branded black panel as the main node. - 🖼 Restore from image — drag a PNG generated with this node onto it: the config is restored from the image metadata (ComfyUI
workflow/promptchunks). - 🔢 Live stats — token estimate per target model and total variation counter.
- ↩ Undo / Redo — 50-step history for the whole node config.
- 📂 Presets — save the current configuration as JSON, load by button or by dragging a
.jsonfile / PNG onto the node. - Model profiles —
SDXLkeeps tag/weight syntax (75-token scale);Flux,Flux/Z-Image,Z-Image Turbo,Qwen-ImageandWan (video)get natural-language cleanup (weights and brackets stripped) with per-model token limits. - 👤 Characters modal — save and re-apply whole category sets.

- ⬇ Import modal — paste JSON / markdown, or let an LLM split an idea into categories.

- ⚠ Linter modal — the header badge collects everything worth fixing in one list.

🎞 Shot Series node
🧪 PerfectLab - Shot Series builds a whole photo session from one person description. Like the main node it carries a branded panel: nine axis rows with live values, a numbered contact sheet showing what each framing looks like, and a grid of outfit demos — click one to copy its full structured prompt to the clipboard.
Describe the person once (connect any text — or two versions: a detailed one for close shots and a shorter one for wide shots), and the node walks through nine axes on its own:
- Framing (7) · Pose (32) · Expression (28) · Focus (12) · Hair (24) · Outfit (14) · Footwear (12) · Lighting (8) · Format (7 aspect ratios).
- Framing and aspect ratio stay coupled: close-ups land in 1:1 / 4:5 / 3:4, wide shots in 2:3 / 9:16 / 16:9 — always at the same ~1.5 MP pixel budget, snapped to /16.
- The axes are counted, not rolled: every run takes the next step through each axis, so a series covers all framings without repeating and a given seed always produces the same session.
- Outputs are lists —
PROMPT,WIDTH,HEIGHTandSEED— so ComfyUI's list handling iterates the whole session downstream; no queue scripts needed. - Every axis can be pinned: click a row to unfold its value list and pick one — the remaining axes keep walking. Shoot one look from seven framings, or one framing in twelve poses, without editing a single text field.
- The
templatefield lets you rearrange the sentence ({framing} of {person} in {scene}, {pose}...) — all thirteen keys, including{hair},{outfit},{footwear}and{lighting}, can move or drop out.
Installation
No third-party Python dependencies — requirements.txt is intentionally empty.
Via ComfyUI-Manager (easiest)
Open Manager → Custom Nodes Manager → Install via Git URL and paste:
https://github.com/perfectmodelslab/ComfyUI-PerfectLab
Manual
cd ComfyUI/custom_nodes
git clone https://github.com/perfectmodelslab/ComfyUI-PerfectLab PerfectLab
Then restart ComfyUI and hard-refresh the browser tab.
Troubleshooting
- Node doesn't appear in the Add Node menu — fully restart ComfyUI (a running server only scans
custom_nodesat startup), then hard-refresh the browser withCtrl+F5. If it still fails, check the ComfyUI console forIMPORT FAILEDorAn error occurred while retrieving informationmessages mentioningPerfectLabAssistant. - Styles look broken / unstyled — hard-refresh with
Ctrl+F5to clear the cached stylesheet. - Folder name doesn't matter — any folder name works (
PerfectLabis just the convention).
Tutorial
1 · Add the node and shape the prompt
Add 🧪 PerfectLab - Prompt Assistant, pick the target model profile (mode — Z-Image Turbo in the shot below), and write your base prompt. Anything wrapped in {{double braces}} becomes a form field below the header: fill it with fixed text, or leave it empty when the placeholder has options ({{city|Paris|Rome|Prague}}) and every seed rolls a fresh choice.
The assembled result is always one PROMPT output away — connect it to any text preview to see exactly what the sampler receives.

2 · Light it by the clock
Turn LIGHTING on and drag the slider — or open the clock with the ◷ button. Each hour maps to a written lighting paragraph (eight named phases from deep night to golden hour), so the light in the prompt matches the time of day instead of vague keywords.

3 · Camera, film, palette
CAMERA opens a builder with five columns — device, vibe, lens, film, light — that compose one camera line. PALETTE picks swatches plus modifiers (Neon, Pastel, Metallic...) and steers the color words in the prompt.

4 · Categories: the randomizable parts
Categories are your own lists — and you don't have to start from scratch: + ADD opens the category library with pre-filled shoot-plan groups (Person, Outfit, Scene, Mood & Camera — hairstyles, footwear, locations, film looks and more). One click adds a ready category; edit its items afterwards like any other.

LCK always uses the selected item, RND rolls from the seed (deterministic — same seed, same pick), CYC advances to the next item every N seeds and walks the list in order. The ⊞ matrix gives you search, A-Z / usage sorting and per-item counters; the ⚠ badge in the header is a linter that flags overflow, duplicates and empty fields.

5 · The NEGATIVE tab
Switch to NEG to give the optional second output its own base text and categories. Leave it unconnected if your model does not use negatives.

6 · Shot Series: one person, a whole session
Describe the person once (or two versions: detailed for close shots, compact for wide ones), connect any scene text, and the Shot Series walks through nine axes on its own — framing, focus, pose, expression, hair, outfit, footwear, lighting and aspect ratio. Outputs are lists — PROMPT, WIDTH, HEIGHT, SEED — so one node queues the whole session through ComfyUI's list handling: feed WIDTH/HEIGHT into an empty latent and let it iterate.
The panel has the nine axis rows (click a row to unfold its value list and pin one — the rest keep walking), a clickable contact sheet — select a shot to see what the framing covers and which ratios it lands on — and outfit demos: click a look, the preview card shows it and copies its full structured prompt.

7 · Companion nodes
Concat merges two prompt streams element-wise (a length-1 list broadcasts across the merge — one style line for every shot), Split picks one line by index — negative indexes count from the end. Together with the main node they cover most prompt-plumbing cases without extra glue nodes.

Demo sets
The previews inside the nodes are static samples, shot on Z-Image Turbo (JW Face / Z-Detail / Z-Light community LoRAs, fixed seeds) so every user sees the same reference. The full-resolution sets live in docs/examples/ — same images as the ribbons below, one row per preview.
The framings the Shot Series walks through:

The outfit demos shipped in the panel:

And the lighting clock, one scene at four hours:



Ready-made presets
Eight starter presets are bundled in the presets/ folder — drag any of them onto the node to load it:
| Preset | Mood |
|---|---|
| cinematic_night_city | Neo-noir night streets, teal & orange, anamorphic |
| golden_hour_portrait | Sunset editorial portraits, Portra 400, Rembrandt light |
| amateur_selfie | Realistic casual smartphone snapshots, harsh flash |
| cyberpunk_street | Neon cyberpunk, vaporwave, holographic ads |
| vintage_film | 1970s analog film, Helios swirly bokeh, faded colors |
| product_studio | Clean commercial product shots on studio backdrops |
| video_shot | Video shots for Wan-class models: camera moves + motion details |
| person_studio | Person sheets for the Shot Series node: looks, hair, eyes, outfits |
A minimal schema example is also available in examples/example_preset.json.
Preset format
{
"time_of_day": 19,
"palette": ["Neon Pink", "Neon Blue"],
"camera": "Sony A7IV, Rembrandt Lighting",
"style": {
"active": true,
"mode": "RND",
"items": ["cyberpunk style", "vaporwave aesthetic"],
"selected": "cyberpunk style"
}
}
Any number of category keys is allowed (active, mode (LCK/RND), items, selected). Use "time_of_day": -1 to keep lighting off.
License
Distributed under the MIT License.