NormalCrafter - Load
Two dropdowns, and the folder layout they actually want
- model
NormalCrafter answers a question the older normal-map tools never asked: what if the normals were temporally stable? DSINE, Marigold and the ControlNet aux preprocessors all work one frame at a time, so you run them over a clip and get a surface that shimmers as each frame makes its own decision. NormalCrafter (April 2025) instead runs a video diffusion prior - it's built on Stability's SVD-XT spatio-temporal UNet, adapted so it takes one CLIP embedding per frame. Depth got DepthCrafter for exactly this reason; normals got this.
The annoyance is that the model isn't one download. It's a UNet plus a VAE from Yanrui95/NormalCrafter, and then a CLIP image encoder, a feature extractor and a scheduler borrowed from stabilityai/stable-video-diffusion-img2vid-xt. This node exists to glue those two halves into one wire.
What it actually does
It registers ComfyUI's model category normalcrafter, which means everything it looks at goes through folder_paths - the standard <ComfyUI>/models/normalcrafter/ and anything you've added to extra_model_paths.yaml. No hardcoded drive letters.
Each of the two dropdowns lists the Hugging Face default first, then every compatible local folder it can find. Compatibility is strict and folder-name based: a NormalCrafter candidate must contain unet/ and vae/; an SVD candidate must contain image_encoder/, feature_extractor/ and scheduler/. Half a model doesn't show up, which is the point - the dropdown only offers things that will actually load.
Pick an HF: entry and it downloads only the subfolders it needs into a registered normalcrafter root, using snapshot_download with allow-patterns. That's a real difference from "download the SVD repo": you get the image encoder and scheduler, not several gigabytes of img2vid UNet you'll never touch. Already-downloaded copies are found first (they land in a folder named Yanrui95--NormalCrafter, slash becomes double-dash), and after that first download everything runs with local_files_only, so it can't quietly re-fetch mid-workflow.
Loading happens on CPU on purpose. UNet and CLIP go to fp16 on CUDA, fp32 on CPU, and the temporal VAE is loaded fp32 from the start to match its force-upcast behaviour.
Inputs and output
Two required dropdowns, one output.
normalcrafter_model defaults to HF: Yanrui95/NormalCrafter - the UNet and VAE. base_model defaults to HF: stabilityai/stable-video-diffusion-img2vid-xt - the CLIP encoder, feature extractor and scheduler. If you've already got an SVD img2vid folder sitting on disk, point the second dropdown at it and save the download.
model (type NORMALCRAFTER_MODEL) is the bundle you feed into NormalCrafter - Generate Normals. That's the whole graph for this node: Load once, Generate, done. The heavy components stay on CPU after loading and get pulled onto the GPU stage by stage during inference.
Install
ComfyUI Manager, search Better NormalCrafter Wrapper, or by hand:
cd ComfyUI/custom_nodes
git clone https://github.com/kaski23/BetterNormalCrafterWrapper
cd BetterNormalCrafterWrapper
pip install -r requirements.txt
Restart ComfyUI. The dependencies are the usual diffusers stack - diffusers>=0.30.0,<1.0, transformers>=4.39, accelerate, huggingface_hub, safetensors. No exotic video libraries, no CUDA build step. Models download on first use; if you'd rather keep them somewhere else:
my_models:
base_path: D:/AI/
normalcrafter: models/normalcrafter/
Where people get stuck
Your local folder isn't in the dropdown. Nine times out of ten it's the subfolder names. A folder containing unet/ but no vae/ is invisible, and the same folder one level too deep (i.e. not a direct child of a registered root) is invisible too. Add the path, restart, and look again - the dropdown is built at ComfyUI start.
"No writable ComfyUI 'normalcrafter' model path is available." You registered only read-only roots. Either make the default models/normalcrafter/ writable or point extra paths at a drive you can write to.
A diffusers bump breaks another pack. diffusers>=0.30,<1.0 is what this needs for UNetSpatioTemporalConditionModel, and custom nodes all share one Python environment - so if an older pack pinned diffusers below 0.30, installing this one moves the version out from under it. This is the standard ComfyUI dependency situation, not a bug in this pack, but it's the failure you're most likely to actually hit. Pin deliberately if you have a fragile install.
Python version gripes from Manager. The pack's pyproject.toml declares requires-python = ">=3.13", so an older interpreter can produce install-time complaints. The manual clone plus pip install -r requirements.txt path sidesteps that.
One honest caveat: this wrapper's first commit landed in September 2026 and it's a small (roughly 1,100-line) clean-room rewrite of an older NormalCrafter wrapper, so there's very little community track record to lean on yet. Model behaviour is well documented by the original project; this packaging is new.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| normalcrafter_model | COMBO | HF: Yanrui95/NormalCrafter | NormalCrafter model containing the UNet and VAE. Local models are discovered from every ComfyUI 'normalcrafter' model path, including paths from extra_model_paths.yaml. Selecting an HF entry downloads the required files into a registered normalcrafter path. |
| base_model | COMBO | HF: stabilityai/stable-video-diffusion-img2vid-xt | Stable Video Diffusion base components used by NormalCrafter: CLIP image encoder, feature extractor and scheduler. Local models are discovered from the same registered ComfyUI 'normalcrafter' paths. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| model | NORMALCRAFTER_MODEL | Loaded NormalCrafter model bundle. Heavy components stay on CPU until inference needs them. |