LucidNFT Sampler
A Sampler With Three Real Settings, Because It Doesn't Do CFG
- model
- positive
- latent
- noise
- LATENT
What it's for
This is the node you'd be tempted to replace with a stock KSampler and then wonder why your results don't match the paper. It exists for one specific reason: LucidNFT's official code builds its own noise schedule, and comfy's default schedule isn't it.
It's also, refreshingly, a sampler with almost nothing to tune: no negative input, no sampler-name dropdown, no scheduler dropdown. That's not laziness - it's what the model needs.
How it works
The node replicates the official get_schedule step for step: a linear timestep ramp from 1 to 0 over steps, then Flux's time-shift, where mu comes from a linear fit over the image sequence length - computed here as latent_h × latent_w / 256, the algebraically equivalent form of the official (w//8)*(h//8)//(16*16). A sigma table that matches the reference implementation rather than approximating it.
That table goes to comfy's own euler via sample_custom. No custom solver, no second-order anything: known schedule, native euler, done. The changelog says the rewrite was about speed and memory over the old diffusers wrapper, and this is the shape of that decision.
cfg exists as a widget and defaults to 1.0, and that's not a coincidence. Flux dev is guidance-distilled - no traditional CFG, no negative pass, you move a guidance scale instead - and the guidance value lives in the conditioning, set by LucidNFT Condition, consumed inside the control branches. Crank cfg and you aren't sharpening anything; you're running a second model evaluation from an empty negative. Slower, and in practice worse. There's no negative input here for exactly that reason: it passes an empty list where a negative would go.
The fields you set
- model -
UNETLoader(flux1-dev, fp8 is what the example uses) throughLoraLoaderModelOnlywithLucidNFT_lora_dit.safetensors. That LoRA is the preference-optimised half of the model and it is not optional; the base Flux isn't LucidNFT. - positive - the output of LucidNFT Condition. Nothing else fits.
- latent -
EmptySD3LatentImage, sized for a /8 VAE. The bit people get wrong: with the UltraFlux F16 VAE and the patch node, a 1024 latent decodes at 2048, so size the latent at half your target. - steps - the official default is 24 for flux-dev. With a turbo LoRA stacked in front of the LucidNFT LoRA the author's own note says 4, and the shipped 2K example runs 8; somewhere in that range is what most people will actually want.
- seed - the usual.
- cfg - leave at 1.0.
- shift - on for flux-dev, off for flux-schnell. It's the same time-shift knob as everywhere else in the Flux ecosystem, just applied to the official schedule instead of comfy's.
The optional noise input takes a LATENT. Only useful when you're bit-comparing against the official implementation with hand-supplied noise. Ignore it otherwise.
Output is a single LATENT → VAEDecode.
Installing it
Manager → search LucidNFT → install → restart. Manual:
cd ComfyUI/custom_nodes
git clone https://github.com/smthemex/ComfyUI_LucidNFT
Dependencies are torch and einops only - the pack deliberately avoids diffusers, transformers, peft and accelerate, so no environment surgery and no version conflicts with whatever else you run.
It needs one weight, plus the pipeline around it:
ComfyUI/models/
├── diffusion_models/flux1-dev-fp8.safetensors
├── loras/LucidNFT_lora_dit.safetensors # already converted, from smthemex/UltraFlux-v1-gguf
└── LucidFlux/ # lucidflux.pth, prompt_embeddings.pt,
# lucid_connector.pth, general_swinir_v1.ckpt, lora_condition/
If you only have the raw PEFT lora_dit adapter directory, convert it once with the pack's own tool, using ComfyUI's Python:
cd ComfyUI/custom_nodes/ComfyUI_LucidNFT
python tools/convert_dit_lora.py # writes models/loras/LucidNFT_lora_dit.safetensors
Where people get burned
Swapping in a KSampler. It will run - comfy's Flux model reads the control tensor on the conditioning regardless of who drives the loop. But comfy applies its own shift and its own sigma table, so the same seed and step count give you a different-looking image. Fine for experimenting; just know you've left the reference path.
Steps and turbo. 24 without a turbo LoRA, 4–8 with one - the two numbers are a pair. 24 steps with turbo loaded is wasted time; 8 without it gets you mush.
OOM that isn't VRAM. The most common story around this author's packs: an instant out-of-memory on a 32GB card that turns out to be system RAM, because models were staging on CPU. If it dies as sampling starts rather than partway through, check host memory before you blame the card - RAM doesn't substitute for VRAM, and the shuffle penalty is enormous.
Re-queueing with a new seed reuses the conditioning. Intentional, and a real convenience - the multi-gigabyte control model is cached, so seed-hunting doesn't re-read it from disk. It also means a stale lq/ldr pair gets reused happily: change the source image and force the Condition node to re-execute too.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | — | |
| positive | CONDITIONING | — | |
| latent | LATENT | — | |
| steps | INT | 201–200 | — |
| seed | INT | 00–18446744073709550000 | — |
| cfg | FLOAT | 1.000–100 | — |
| shift | BOOLEAN | true | 官方 get_schedule 的 shift;flux-dev 开,flux-schnell 关 |
| noiseopt | LATENT | 仅在需要与官方逐位对拍时接入手工噪声 |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| LATENT | LATENT | — |