Skip to content

Add native Hunyuan3D 2.1 PBR paint (mesh -> multiview -> textured GLB) - #15020

Open
jethac wants to merge 77 commits into
Comfy-Org:masterfrom
jethac:hunyuan21-paint
Open

jethac wants to merge 77 commits into
Comfy-Org:masterfrom
jethac:hunyuan21-paint

Conversation

@jethac

@jethac jethac commented Jul 22, 2026 •

Copy link
Copy Markdown

Summary

This PR supersedes the older implementation with a native Hunyuan3D 2.1 mesh-paint rewrite. It adds the torch-native multiview PBR UNet, renderer/rasterizer/baker, ComfyUI model integration, sampler/scheduler nodes, and textured GLB metallic-roughness save support. The implementation uses the standard ComfyUI sampler/core machinery; it is not an API-node path.

The optional DINO input is intentionally omitted from the tested path. The rewrite also includes PBR mesh/save fixes and is compatible with current upstream master (15eb748b).

Provenance

The rewrite was produced as a specification-only clean-room implementation without access to Tencent's source or the prior implementation. The specification was the public model/checkpoint contract and ComfyUI interfaces. Numerical fixes are recorded in PR #4, including the 33d1f4d changes; the associated review discussion is here. Reference validation is a separate engineering result and does not imply source access. Model weights remain separately licensed artifacts; this PR contains no weights.

Current validation

  • Publication commit 2d1c6623efd536e2bfc960eeeedd571ce5df68dd; production runtime is c588e42b15adf4c5f36dd7c55becde8398ee2388.
  • Focused tests: 75 passed. Ruff passed.
  • Full unit suite: 1660 passed, 17 skipped, 2 failed; the two failures are independent upstream m4a classification failures reproducible against 15eb748b.
  • Real-weight run: 52.019 s on RTX 5060 Ti, fp16, 6 views at 256 × 256 pixels, 15 sampling steps, CFG 3.0, and 512 × 512 textures, DINO omitted, with explicit unload/reload. Peak PyTorch allocation was 4,999,507,968 bytes. The run produced a 2,433,876-byte GLB (SHA-256 472c653bfb7a688d8f0737ab61efa7c6b728acb5091057b87074928242ea2ada) with finite albedo/MR and a valid two-texture PBR GLB.

The older audit's RTX 3090 result and claims belong to the superseded head and are historical only; the 33d1f4d RTX 3090 result is likewise historical. Astra accepted the code, merge, runtime, and test fixes. No new numerical reference-parity capture was performed for this rewrite. DINO, LoRA, device-retargeting, and other-hardware behavior remain unclaimed. Maintainer/CI review and merge decisions remain pending.

@github-actions

github-actions Bot commented Jul 22, 2026 •

Copy link
Copy Markdown
Contributor

✅ All contributors have signed the CLA. Thank you! This PR is ready to be merged.
Posted by the CLA Assistant Lite bot.

@jethac

jethac commented Jul 22, 2026 •

Copy link
Copy Markdown
Author

Reviewer speedkit — workflow + exhibits

API-format workflow, image → 2.1 shape → paint → textured GLB (native nodes only). Weights: hunyuan3d-paintpbr-v2-1 UNet in models/diffusion_models, its SD-2.1 VAE in models/vae, plus the already-supported 2.1 shape checkpoint and BiRefNet. sgm_uniform is a close approximation of the paint schedule; swap the paint KSampler for SamplerCustomAdvanced + Hunyuan3DPaintScheduler for exact trailing sigmas.

{
  "1": {
    "class_type": "LoadImage",
    "inputs": {
      "image": "reference.png"
    }
  },
  "2": {
    "class_type": "LoadBackgroundRemovalModel",
    "inputs": {
      "bg_removal_name": "birefnet.safetensors"
    }
  },
  "3": {
    "class_type": "RemoveBackground",
    "inputs": {
      "bg_removal_model": [
        "2",
        0
      ],
      "image": [
        "1",
        0
      ]
    }
  },
  "4": {
    "class_type": "EmptyImage",
    "inputs": {
      "width": 1024,
      "height": 1024,
      "batch_size": 1,
      "color": 16777215
    }
  },
  "5": {
    "class_type": "ImageCompositeMasked",
    "inputs": {
      "destination": [
        "4",
        0
      ],
      "source": [
        "1",
        0
      ],
      "mask": [
        "3",
        0
      ],
      "x": 0,
      "y": 0,
      "resize_source": true
    }
  },
  "6": {
    "class_type": "ImageOnlyCheckpointLoader",
    "inputs": {
      "ckpt_name": "hunyuan_3d_v2.1.safetensors"
    }
  },
  "7": {
    "class_type": "ModelSamplingAuraFlow",
    "inputs": {
      "model": [
        "6",
        0
      ],
      "shift": 1.0
    }
  },
  "8": {
    "class_type": "CLIPVisionEncode",
    "inputs": {
      "clip_vision": [
        "6",
        1
      ],
      "image": [
        "5",
        0
      ],
      "crop": "center"
    }
  },
  "9": {
    "class_type": "Hunyuan3Dv2Conditioning",
    "inputs": {
      "clip_vision_output": [
        "8",
        0
      ]
    }
  },
  "10": {
    "class_type": "EmptyLatentHunyuan3Dv2",
    "inputs": {
      "resolution": 4096,
      "batch_size": 1
    }
  },
  "11": {
    "class_type": "KSampler",
    "inputs": {
      "model": [
        "7",
        0
      ],
      "positive": [
        "9",
        0
      ],
      "negative": [
        "9",
        1
      ],
      "latent_image": [
        "10",
        0
      ],
      "seed": 42,
      "steps": 30,
      "cfg": 5.0,
      "sampler_name": "euler",
      "scheduler": "normal",
      "denoise": 1.0
    }
  },
  "12": {
    "class_type": "VAEDecodeHunyuan3D",
    "inputs": {
      "samples": [
        "11",
        0
      ],
      "vae": [
        "6",
        2
      ],
      "num_chunks": 8000,
      "octree_resolution": 256
    }
  },
  "13": {
    "class_type": "VoxelToMesh",
    "inputs": {
      "voxel": [
        "12",
        0
      ],
      "algorithm": "surface net",
      "threshold": 0.6
    }
  },
  "14": {
    "class_type": "Hunyuan3DPaintModelLoader",
    "inputs": {
      "model_name": "hunyuan3d-paintpbr-v2-1.safetensors"
    }
  },
  "15": {
    "class_type": "VAELoader",
    "inputs": {
      "vae_name": "hunyuan3d_paintpbr_v2_1_vae.safetensors"
    }
  },
  "16": {
    "class_type": "Hunyuan3DPaintConditioning",
    "inputs": {
      "model": [
        "14",
        0
      ],
      "vae": [
        "15",
        0
      ],
      "mesh": [
        "13",
        0
      ],
      "reference_image": [
        "5",
        0
      ],
      "num_views": 6,
      "resolution": 512
    }
  },
  "17": {
    "class_type": "KSampler",
    "inputs": {
      "model": [
        "16",
        0
      ],
      "positive": [
        "16",
        1
      ],
      "negative": [
        "16",
        2
      ],
      "latent_image": [
        "16",
        3
      ],
      "seed": 42,
      "steps": 20,
      "cfg": 6.0,
      "sampler_name": "euler",
      "scheduler": "sgm_uniform",
      "denoise": 1.0
    }
  },
  "18": {
    "class_type": "Hunyuan3DPaintSplitLatent",
    "inputs": {
      "model": [
        "16",
        0
      ],
      "samples": [
        "17",
        0
      ]
    }
  },
  "19": {
    "class_type": "VAEDecode",
    "inputs": {
      "samples": [
        "18",
        0
      ],
      "vae": [
        "15",
        0
      ]
    }
  },
  "20": {
    "class_type": "VAEDecode",
    "inputs": {
      "samples": [
        "18",
        1
      ],
      "vae": [
        "15",
        0
      ]
    }
  },
  "21": {
    "class_type": "Hunyuan3DBakeMultiView",
    "inputs": {
      "mesh": [
        "13",
        0
      ],
      "albedo": [
        "19",
        0
      ],
      "mr": [
        "20",
        0
      ],
      "cameras": [
        "16",
        4
      ],
      "texture_size": 2048
    }
  },
  "22": {
    "class_type": "SaveGLB",
    "inputs": {
      "mesh": [
        "21",
        0
      ],
      "filename_prefix": "3d/hunyuan3d_painted"
    }
  }
}

Exhibits (same seed 42, 6 views / 512 px / 20 steps / cfg 6.0, ~72 s and 8.6 GiB peak on an RTX 5060 Ti 16 GB) are embedded in the PR description above.

@jethac

jethac commented Jul 22, 2026

Copy link
Copy Markdown
Author

I have read and agree to the Contributor License Agreement

comfy-legal added a commit to Comfy-Org/comfy-cla that referenced this pull request Jul 22, 2026
@coderabbitai

coderabbitai Bot commented Jul 22, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds Hunyuan3D 2.1 paint support with a native 2.5D UNet, specialized attention, checkpoint loading, packed latent handling, and ComfyUI nodes. Adds torch-based multiview rendering, UV baking, hole filling, and coordinate-convention documentation. Extends mesh and GLB handling for metallic-roughness textures. Adds deterministic model, renderer, convention, sampling, and reference-parity tests with supporting bundle and comparison tools.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely describes the main change: native Hunyuan3D 2.1 PBR paint support for converting meshes into multiview textured GLBs.
Description check ✅ Passed The description is directly related to the changeset and explains the native paint UNet, rendering and baking pipeline, ComfyUI integration, GLB metallic-roughness support, validation results, and sco…
  • Fix all pre-merge checks with AI

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@comfy/ldm/hunyuan3d/paint/attention.py`:
- Line 13: Remove the einops.rearrange import and replace every rearrange use in
comfy/ldm/hunyuan3d/paint/attention.py (including the operations around lines
187-188, 208, and 219) with equivalent native tensor operations while preserving
shapes and ordering. Apply the same change in comfy/ldm/hunyuan3d/paint/unet.py
(including lines 203-205, 231-236, 649-652, and 696-697), removing its import
and using reshape, view, permute, transpose, flatten, or equivalent methods; no
direct changes are needed elsewhere.
- Around line 265-266: Remove the `@torch.no_grad`() decorators from
_mean_voxel_indices and multires_voxel_indices in
comfy/ldm/hunyuan3d/paint/attention.py and from compute_reference_bank in
comfy/ldm/hunyuan3d/paint/unet.py. Do not replace them with other inference-mode
wrappers.

In `@comfy/ldm/hunyuan3d/paint/render.py`:
- Around line 490-495: In the rendering function containing the `for vi in
range(V)` loop, add an upfront validation that the number of camera elevations
and azimuths matches `views.shape[0]` (`V`), raising a clear validation error
when counts differ. Ensure the check handles both too few and too many camera
views before indexing `cameras.elevs[vi]` and `cameras.azims[vi]`, while leaving
the existing weight fallback unchanged.
- Around line 119-131: Update view_matrix() to detect when the normalized lookat
direction is parallel or near-parallel to the fixed Z-up vector, and use a
non-parallel fallback up axis for those pole views before computing right.
Preserve the existing Z-up behavior for all other camera directions so
STANDARD_VIEW_ELEVS, including ±90°, produces finite matrices.

In `@tests-unit/comfy_test/paint_parity/bundle_format.py`:
- Around line 84-86: Update the key-processing loop in the bundle parity
comparison to validate each requested key exists in both reference and candidate
captures before indexing them. When a key is absent, raise a descriptive error
identifying the missing key and capture side, rather than allowing a raw
KeyError; preserve normal float comparison for keys present in both.

In `@tests-unit/comfy_test/paint_parity/capture_reference.py`:
- Around line 88-90: Always pass the CPU patch that removes the hard-coded
.to("cuda:0") move when loading attn_processor.py in the capture path; do not
condition it on torch.cuda.is_available(). Keep the existing load_module calls
and reference module loading unchanged.
- Around line 96-103: In the model-loading fallback around
UNet2p5DConditionModel.from_pretrained, only handle the specific TypeError
caused by unsupported private config keys. Inspect the exception details and
re-raise unrelated TypeErrors instead of entering the from_config fallback,
preserving the existing alternate construction path for the known mismatch.

In `@tests-unit/comfy_test/paint_parity/harness.py`:
- Around line 44-48: Remove locally forced no-grad execution from the parity
paths: in tests-unit/comfy_test/paint_parity/harness.py lines 44-48, initialize
parameters through detached tensors such as p.detach().copy_(...) without
changing ambient mode; in harness.py lines 92-101, let the native forward use
the caller’s execution context; and in
tests-unit/comfy_test/paint_parity/capture_reference.py lines 141-152, likewise
remove the local no-grad wrapper around reference execution.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: baaab730-b2bd-4698-890b-cff23e821f45

📥 Commits

Reviewing files that changed from the base of the PR and between 947c274 and 3ed84cf.

📒 Files selected for processing (26)
  • comfy/latent_formats.py
  • comfy/ldm/hunyuan3d/paint/CONVENTIONS.md
  • comfy/ldm/hunyuan3d/paint/__init__.py
  • comfy/ldm/hunyuan3d/paint/attention.py
  • comfy/ldm/hunyuan3d/paint/loader.py
  • comfy/ldm/hunyuan3d/paint/render.py
  • comfy/ldm/hunyuan3d/paint/unet.py
  • comfy/model_base.py
  • comfy/model_detection.py
  • comfy/supported_models.py
  • comfy_api/latest/_util/geometry_types.py
  • comfy_extras/nodes_hunyuan3d_paint.py
  • comfy_extras/nodes_save_3d.py
  • nodes.py
  • tests-unit/comfy_test/paint_parity/README.md
  • tests-unit/comfy_test/paint_parity/__init__.py
  • tests-unit/comfy_test/paint_parity/bundle_format.py
  • tests-unit/comfy_test/paint_parity/capture_reference.py
  • tests-unit/comfy_test/paint_parity/compare_reference.py
  • tests-unit/comfy_test/paint_parity/goldens/tiny_golden.safetensors
  • tests-unit/comfy_test/paint_parity/harness.py
  • tests-unit/comfy_test/paint_parity/make_goldens.py
  • tests-unit/comfy_test/test_hunyuan3d_paint.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_conventions.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_parity.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_render.py
📜 Review details
⚠️ CI failures not shown inline (2)

GitHub Actions: CLA Assistant / 0_cla-assistant.txt: Add native Hunyuan3D 2.1 PBR paint (mesh -> multiview -> textured GLB)

Conclusion: failure

View job details

##[group]Run contributor-assistant/github-action@ca4a40a7d1004f18d9960b404b97e5f30a505a08
 with:
   path-to-document: https://github.com/Comfy-Org/comfy-cla/blob/main/comfyui_icla.md
   remote-organization-name: comfy-org
   remote-repository-name: comfy-cla
   path-to-signatures: signatures/cla.json
   branch: main
   allowlist: action@github.com,actions-user,ampagent,claude,comfy-pr-bot,GitHub Action,github-actions,github-actions[bot],Glary Bot,Glary-Bot,*[bot]
   custom-notsigned-prcomment: 🎉 Thank you for your contribution, we really appreciate it! 🎉
Like many open source projects, we require contributors to sign our [Contributor License Agreement (CLA)](https://github.com/Comfy-Org/comfy-cla/blob/main/comfyui_icla.md). A CLA makes the ownership of contributions explicit, so contributors and the project share a clear understanding of how the code can be used. By signing, you:
- Confirm that you own your contribution.
- Keep the right to reuse your own code.
- Grant us a copyright license to include and share it within our projects.
CLAs are standard practice across major open source projects including those under the Apache Software Foundation and the Linux Foundation. Ours is based on the Apache Software Foundation's CLA. Most importantly, it would enable us to relicense the project under a more permissive license in the future, giving the project and its community greater flexibility.
✍ **To sign, please post a new comment on this PR with exactly the following text:** ✍
   custom-pr-sign-comment: I have read and agree to the Contributor License Agreement
   custom-allsigned-prcomment: ✅ All contributors have signed the CLA. Thank you! This PR is ready to be merged.
   use-dco-flag: false
   lock-pullrequest-aftermerge: true
   suggest-recheck: true
 env:
   GITHUB_***REDACTED***
   PERSONAL_ACCESS_***REDACTED***
 ##[endgroup]
 CLA Assistant GitHub Action bot has started the process
 (node:2138) [DEP0040] DeprecationWarning: The `punycode` module is deprec...

GitHub Actions: CLA Assistant / cla-assistant: Add native Hunyuan3D 2.1 PBR paint (mesh -> multiview -> textured GLB)

Conclusion: failure

View job details

##[group]Run contributor-assistant/github-action@ca4a40a7d1004f18d9960b404b97e5f30a505a08
 with:
   path-to-document: https://github.com/Comfy-Org/comfy-cla/blob/main/comfyui_icla.md
   remote-organization-name: comfy-org
   remote-repository-name: comfy-cla
   path-to-signatures: signatures/cla.json
   branch: main
   allowlist: action@github.com,actions-user,ampagent,claude,comfy-pr-bot,GitHub Action,github-actions,github-actions[bot],Glary Bot,Glary-Bot,*[bot]
   custom-notsigned-prcomment: 🎉 Thank you for your contribution, we really appreciate it! 🎉
Like many open source projects, we require contributors to sign our [Contributor License Agreement (CLA)](https://github.com/Comfy-Org/comfy-cla/blob/main/comfyui_icla.md). A CLA makes the ownership of contributions explicit, so contributors and the project share a clear understanding of how the code can be used. By signing, you:
- Confirm that you own your contribution.
- Keep the right to reuse your own code.
- Grant us a copyright license to include and share it within our projects.
CLAs are standard practice across major open source projects including those under the Apache Software Foundation and the Linux Foundation. Ours is based on the Apache Software Foundation's CLA. Most importantly, it would enable us to relicense the project under a more permissive license in the future, giving the project and its community greater flexibility.
✍ **To sign, please post a new comment on this PR with exactly the following text:** ✍
   custom-pr-sign-comment: I have read and agree to the Contributor License Agreement
   custom-allsigned-prcomment: ✅ All contributors have signed the CLA. Thank you! This PR is ready to be merged.
   use-dco-flag: false
   lock-pullrequest-aftermerge: true
   suggest-recheck: true
 env:
   GITHUB_***REDACTED***
   PERSONAL_ACCESS_***REDACTED***
 ##[endgroup]
 CLA Assistant GitHub Action bot has started the process
 (node:2138) [DEP0040] DeprecationWarning: The `punycode` module is deprec...
🧰 Additional context used
📓 Path-based instructions (7)
**/*

📄 CodeRabbit inference engine (AGENTS.md)

**/*: Keep changes small, direct, and limited to the narrowest code path and fewest files necessary; prefer practical fixes over broad architectural work.
Prefer fewer dependencies and do not add a ComfyUI dependency unless absolutely necessary.
Remove obsolete code, dead branches, unused options, debug prints, and unnecessary compatibility paths.
Preserve existing APIs, node names, model-loading behavior, file layout, and workflow compatibility unless replacement is explicit.
Keep architectural layers focused; do not leak UI, API, workflow, queue, persistence, telemetry, model-loading, node, or execution concerns into unrelated layers.
Shared core modules should depend only on lower-level primitives and their own domain concepts; higher-level concepts belong at callers, adapters, services, or boundaries.
Pass only the narrowest data needed across boundaries and keep identity mapping, persistence, history, telemetry, response shaping, and UI state in their owning layers.
Before touching many files, identify the smallest owner layer; use caller-side mappings, adapters, events, or narrow interfaces instead of exposing private concepts across layers.
Core ComfyUI code must not make unsolicited internet requests or add uploads, telemetry, analytics, tracking, reporting, update checks, remote configuration, licensing checks, or similar outbound paths.
Model downloading is allowed only when explicitly authorized by the user, limited to the requested artifact, and free of telemetry, tracking, unrelated metadata, or background activity.
Warning and info messages should be short and actionable; documentation and README changes should be concise, factual, and tied to changed behavior.
Use short direct commit subjects such as Fix ..., Add ..., Support ..., Remove ..., or Update ...; keep PR descriptions short and state the problem, behavior change, and tests.
Prefer one coherent behavioral change per commit and prioritize crashes, incorrect dtype/device behavior, m...

Files:

  • comfy/ldm/hunyuan3d/paint/CONVENTIONS.md
  • tests-unit/comfy_test/paint_parity/make_goldens.py
  • tests-unit/comfy_test/paint_parity/compare_reference.py
  • comfy/ldm/hunyuan3d/paint/__init__.py
  • comfy/supported_models.py
  • tests-unit/comfy_test/paint_parity/goldens/tiny_golden.safetensors
  • tests-unit/comfy_test/paint_parity/README.md
  • nodes.py
  • comfy_api/latest/_util/geometry_types.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_parity.py
  • comfy/model_detection.py
  • tests-unit/comfy_test/paint_parity/harness.py
  • comfy/model_base.py
  • comfy/ldm/hunyuan3d/paint/loader.py
  • tests-unit/comfy_test/paint_parity/capture_reference.py
  • comfy/latent_formats.py
  • tests-unit/comfy_test/paint_parity/bundle_format.py
  • comfy_extras/nodes_save_3d.py
  • comfy/ldm/hunyuan3d/paint/render.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_render.py
  • comfy/ldm/hunyuan3d/paint/attention.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_conventions.py
  • comfy_extras/nodes_hunyuan3d_paint.py
  • comfy/ldm/hunyuan3d/paint/unet.py
  • tests-unit/comfy_test/test_hunyuan3d_paint.py
**

⚙️ CodeRabbit configuration file

**: IMPORTANT: Only comment on issues directly introduced by this PR's code changes.
Treat AGENTS.md as mandatory repository policy, not optional style guidance.
Flag PR changes that violate AGENTS.md even when the code is otherwise functional.
In particular, enforce architecture boundaries, dtype/device/memory rules,
interface contracts, import style, no unnecessary try/except blocks, no inline
imports, no outbound internet paths in core ComfyUI, and narrow scoped fixes.
Prefer direct findings over suggestions when a rule is violated. Only ignore
AGENTS.md when it clearly conflicts with a newer explicit maintainer instruction
in the PR.
Do NOT flag pre-existing issues in code that was merely moved, re-indented,
de-indented, or reformatted without logic changes. If code appears in the diff
only due to whitespace or structural reformatting (e.g., removing a with: block),
treat it as unchanged. Contributors should not feel obligated to address
pre-existing issues outside the scope of their contribution.

Files:

  • comfy/ldm/hunyuan3d/paint/CONVENTIONS.md
  • tests-unit/comfy_test/paint_parity/make_goldens.py
  • tests-unit/comfy_test/paint_parity/compare_reference.py
  • comfy/ldm/hunyuan3d/paint/__init__.py
  • comfy/supported_models.py
  • tests-unit/comfy_test/paint_parity/goldens/tiny_golden.safetensors
  • tests-unit/comfy_test/paint_parity/README.md
  • nodes.py
  • comfy_api/latest/_util/geometry_types.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_parity.py
  • comfy/model_detection.py
  • tests-unit/comfy_test/paint_parity/harness.py
  • comfy/model_base.py
  • comfy/ldm/hunyuan3d/paint/loader.py
  • tests-unit/comfy_test/paint_parity/capture_reference.py
  • comfy/latent_formats.py
  • tests-unit/comfy_test/paint_parity/bundle_format.py
  • comfy_extras/nodes_save_3d.py
  • comfy/ldm/hunyuan3d/paint/render.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_render.py
  • comfy/ldm/hunyuan3d/paint/attention.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_conventions.py
  • comfy_extras/nodes_hunyuan3d_paint.py
  • comfy/ldm/hunyuan3d/paint/unet.py
  • tests-unit/comfy_test/test_hunyuan3d_paint.py
comfy/**

⚙️ CodeRabbit configuration file

comfy/**: Core ML/diffusion engine. Focus on:

  • Backward compatibility (breaking changes affect all custom nodes)
  • Memory management and GPU resource handling
  • Performance implications in hot paths
  • Thread safety for concurrent execution

Files:

  • comfy/ldm/hunyuan3d/paint/CONVENTIONS.md
  • comfy/ldm/hunyuan3d/paint/__init__.py
  • comfy/supported_models.py
  • comfy/model_detection.py
  • comfy/model_base.py
  • comfy/ldm/hunyuan3d/paint/loader.py
  • comfy/latent_formats.py
  • comfy/ldm/hunyuan3d/paint/render.py
  • comfy/ldm/hunyuan3d/paint/attention.py
  • comfy/ldm/hunyuan3d/paint/unet.py
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Keep state and capability flags on the object that owns the behavior; use explicit parent-owned fields rather than probing children with getattr for parent control flow.
Keep public methods aligned with caller contracts; preserve arguments, parameter order, return types, side effects, and error behavior unless all affected interfaces are intentionally updated.
Do not add unused compatibility parameters, flags, attributes, constructor options, or model-specific options to shared helpers.
Normalize third-party and upstream return conventions at integration boundaries so core code receives the expected type and shape.
Avoid caller-side unwrapping such as out = out[0] unless the called interface documents that return structure.
Do not add torch.no_grad, torch.inference_mode, or inference-mode wrappers; only disable a globally enabled inference mode when a training path requires gradients.
Do not add freeze, unfreeze, or trainability toggles to ComfyUI model classes.
Remove training-only behavior such as dropout from inference models while preserving checkpoint and state-dict compatibility, using nn.Identity when necessary to retain slots.
Keep imports at module scope; use inline imports only for established optional-backend probes or import-cycle avoidance.
Use try/except only for optional dependency, platform, or backend detection with a useful fallback, and prefer specific exception types.
Do not add code for unsupported pinned library versions or obsolete PyTorch workarounds; unsupported formats, quantization metadata, and bad states should fail clearly.
Match local file style and keep comments sparse, useful, and non-obvious; remove comments that merely restate code.

Files:

  • tests-unit/comfy_test/paint_parity/make_goldens.py
  • tests-unit/comfy_test/paint_parity/compare_reference.py
  • comfy/ldm/hunyuan3d/paint/__init__.py
  • comfy/supported_models.py
  • nodes.py
  • comfy_api/latest/_util/geometry_types.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_parity.py
  • comfy/model_detection.py
  • tests-unit/comfy_test/paint_parity/harness.py
  • comfy/model_base.py
  • comfy/ldm/hunyuan3d/paint/loader.py
  • tests-unit/comfy_test/paint_parity/capture_reference.py
  • comfy/latent_formats.py
  • tests-unit/comfy_test/paint_parity/bundle_format.py
  • comfy_extras/nodes_save_3d.py
  • comfy/ldm/hunyuan3d/paint/render.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_render.py
  • comfy/ldm/hunyuan3d/paint/attention.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_conventions.py
  • comfy_extras/nodes_hunyuan3d_paint.py
  • comfy/ldm/hunyuan3d/paint/unet.py
  • tests-unit/comfy_test/test_hunyuan3d_paint.py
comfy/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

comfy/**/*.py: Treat dtype, device placement, VRAM use, offloading, and memory behavior as correctness concerns; use existing ComfyUI quantization, memory, offload, and optimized-operation helpers.
Prefer shared optimized kernels, backend dispatchers, and documented interfaces over duplicate handwritten operations; treat selected backend callables as opaque.
Do not duplicate operations with custom float32-upcasting inference kernels; use generic ComfyUI operations or native PyTorch operations.
If a model constructor has an operations parameter, assume it is never None; do not add fallback torch operations.
Avoid unnecessary parameters in model, block, and operation constructors or forwards; reuse existing model classes, blocks, operations, and helpers.
Model detectors must inspect only the first dimension of linear weights, guard every dereferenced state-dict key, and order specific signatures before broad fallbacks.
Avoid einops in core inference code; use native tensor operations such as reshape, view, permute, transpose, flatten, and related methods.
Keep metadata, counters, shape calculations, indices, split boundaries, and control-flow values as Python values rather than tensors.
Avoid unnecessary casts and transfers; preserve intended compute and storage dtypes, tensor shapes, and backend result contracts.
Keep model-native latent layout handling inside the model or latent-format owner rather than reshaping it in nodes or caller-side adapters.
DiT models must pad every patchified target or reference input with comfy.ldm.common_dit.pad_to_patch_size and crop only the target output back to its original dimensions.
Do not add defensive shape, configuration, or dtype casts that merely obscure a clear tensor-operation failure; validate only at meaningful boundaries.
Raw parameters not owned by an operation should be cast at use with comfy.ops.cast_to_input or comfy.model_management.cast_to; model constructors should not contain dtype workaro...

Files:

  • comfy/ldm/hunyuan3d/paint/__init__.py
  • comfy/supported_models.py
  • comfy/model_detection.py
  • comfy/model_base.py
  • comfy/ldm/hunyuan3d/paint/loader.py
  • comfy/latent_formats.py
  • comfy/ldm/hunyuan3d/paint/render.py
  • comfy/ldm/hunyuan3d/paint/attention.py
  • comfy/ldm/hunyuan3d/paint/unet.py
nodes.py

⚙️ CodeRabbit configuration file

nodes.py: Core node definitions (2500+ lines). Focus on:

  • Backward compatibility of NODE_CLASS_MAPPINGS
  • Consistency of INPUT_TYPES return format

Files:

  • nodes.py
comfy_extras/**

⚙️ CodeRabbit configuration file

comfy_extras/**: Community-contributed extra nodes. Focus on:

  • Consistency with node patterns (INPUT_TYPES, RETURN_TYPES, FUNCTION, CATEGORY)
  • No breaking changes to existing node interfaces

Files:

  • comfy_extras/nodes_save_3d.py
  • comfy_extras/nodes_hunyuan3d_paint.py
🧠 Learnings (7)
📚 Learning: 2026-02-21T14:01:41.482Z
Learnt from: pythongosssss
Repo: Comfy-Org/ComfyUI PR: 12555
File: comfy_extras/nodes_glsl.py:719-724
Timestamp: 2026-02-21T14:01:41.482Z
Learning: In PyOpenGL, bare Python scalars can be accepted for 1-element array parameters by NumberHandler. This means you can pass an int/float directly to OpenGL texture deletion (e.g., glDeleteTextures(tex)) without wrapping in a list. Verify function-specific expectations and ensure types match what the OpenGL call expects; use explicit lists only when the API requires an array.

Applied to files:

  • tests-unit/comfy_test/paint_parity/make_goldens.py
  • tests-unit/comfy_test/paint_parity/compare_reference.py
  • comfy/ldm/hunyuan3d/paint/__init__.py
  • comfy/supported_models.py
  • nodes.py
  • comfy_api/latest/_util/geometry_types.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_parity.py
  • comfy/model_detection.py
  • tests-unit/comfy_test/paint_parity/harness.py
  • comfy/model_base.py
  • comfy/ldm/hunyuan3d/paint/loader.py
  • tests-unit/comfy_test/paint_parity/capture_reference.py
  • comfy/latent_formats.py
  • tests-unit/comfy_test/paint_parity/bundle_format.py
  • comfy_extras/nodes_save_3d.py
  • comfy/ldm/hunyuan3d/paint/render.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_render.py
  • comfy/ldm/hunyuan3d/paint/attention.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_conventions.py
  • comfy_extras/nodes_hunyuan3d_paint.py
  • comfy/ldm/hunyuan3d/paint/unet.py
  • tests-unit/comfy_test/test_hunyuan3d_paint.py
📚 Learning: 2026-05-13T12:31:45.069Z
Learnt from: rattus128
Repo: Comfy-Org/ComfyUI PR: 13802
File: comfy/pinned_memory.py:19-30
Timestamp: 2026-05-13T12:31:45.069Z
Learning: When reviewing code that uses comfy/pinned_memory.py’s `HostBuffer.extend(size=..., reallocate=...)`: by default (`reallocate` is not True / False), `extend(size=...)` is a *relative increment* that grows the buffer by `size` bytes—so slicing like `[offset:offset+size]` after `hostbuf.extend(size=size)` is correct and the argument should not be rewritten to `offset + size`. Only in the single-segment reallocation mode (`reallocate=True`, e.g., as used by `resize_pin_buffer()` in `comfy/model_management.py`) should `size` be treated as an *absolute target* and the call/arguments should be checked accordingly.

Applied to files:

  • comfy/ldm/hunyuan3d/paint/__init__.py
  • comfy/supported_models.py
  • comfy/model_detection.py
  • comfy/model_base.py
  • comfy/ldm/hunyuan3d/paint/loader.py
  • comfy/latent_formats.py
  • comfy/ldm/hunyuan3d/paint/render.py
  • comfy/ldm/hunyuan3d/paint/attention.py
  • comfy/ldm/hunyuan3d/paint/unet.py
📚 Learning: 2026-05-04T18:30:37.579Z
Learnt from: Talmaj
Repo: Comfy-Org/ComfyUI PR: 13655
File: comfy/model_detection.py:907-917
Timestamp: 2026-05-04T18:30:37.579Z
Learning: In ComfyUI’s internal supported model implementations (comfy/supported_models_base.py and comfy/supported_models/*.py), ensure model classes do not override matches() in their own class bodies. All supported models should use BASE.matches() for backward compatibility; if a future change introduces a matches() override in a subclass, treat it as a backward-compatibility risk and require additional review/testing to confirm behavior remains consistent with BASE.matches().

Applied to files:

  • comfy/supported_models.py
📚 Learning: 2026-03-04T14:05:31.426Z
Learnt from: jtydhr88
Repo: Comfy-Org/ComfyUI PR: 12757
File: comfy_extras/nodes_custom_sampler.py:1069-1089
Timestamp: 2026-03-04T14:05:31.426Z
Learning: In the ComfyUI sampling pipeline, treat percent_to_sigma(0.0) as a sentinel value (999999999.9) that means starting from pure noise. This is consistent with BasicScheduler via calculate_sigmas. The SamplingPercentToSigma node’s return_actual_sigma flag differentiates this sentinel from sigma_max. Reviewers should not flag CurveToSigmas or similar nodes that rely on percent_to_sigma as bugs; downstream samplers are expected to handle the sentinel correctly. When reviewing related sampling-related code, assume this sentinel semantics unless there is explicit handling for a real sigma_max.

Applied to files:

  • comfy_extras/nodes_save_3d.py
  • comfy_extras/nodes_hunyuan3d_paint.py
📚 Learning: 2026-04-04T13:29:15.653Z
Learnt from: kijai
Repo: Comfy-Org/ComfyUI PR: 13258
File: comfy_extras/nodes_frame_interpolation.py:151-189
Timestamp: 2026-04-04T13:29:15.653Z
Learning: In this ComfyUI codebase, node `execute()` inference is already run under a global `torch.inference_mode()` context established in the execution engine (e.g., `execution.py` around line ~732). During review, avoid recommending changes that wrap node inference loops in `torch.inference_mode()`—it is already applied, so such suggestions are likely redundant.

Applied to files:

  • comfy_extras/nodes_save_3d.py
  • comfy_extras/nodes_hunyuan3d_paint.py
📚 Learning: 2026-05-09T18:40:40.199Z
Learnt from: kijai
Repo: Comfy-Org/ComfyUI PR: 13813
File: comfy_extras/nodes_wandancer.py:868-872
Timestamp: 2026-05-09T18:40:40.199Z
Learning: When building video/temporal decoding nodes that call ComfyUI’s VAE.decode (comfy/sd.py), leverage VAE.decode’s existing VRAM-aware chunking along dim 0. Reshape or transpose the latent so the temporal dimension T is folded into dim 0 (e.g., transform a latent of shape [B, T, C, H, W] into [B*T, C, H, W] before calling vae.decode). This lets VAE.decode do chunked decoding without needing an explicit per-frame loop inside the node itself.

Applied to files:

  • comfy_extras/nodes_save_3d.py
  • comfy_extras/nodes_hunyuan3d_paint.py
📚 Learning: 2026-05-20T00:10:14.673Z
Learnt from: Pauan
Repo: Comfy-Org/ComfyUI PR: 13997
File: comfy_extras/nodes_string.py:12-25
Timestamp: 2026-05-20T00:10:14.673Z
Learning: In the ComfyUI `comfy_extras/` codebase, some nodes intentionally ship with a default input string that references parameters that may not yet be connected. If the default would raise a `KeyError` (e.g., examples like `MathExpression` default `a + b`, or `StringFormat` default `{a}` with `min=0` and autogrow inputs), treat it as an intentional “hint default” UX pattern, not a bug. During review, do not flag this behavior or recommend changing `min` to `1` or altering the default to an empty string solely to avoid the `KeyError`.

Applied to files:

  • comfy_extras/nodes_save_3d.py
  • comfy_extras/nodes_hunyuan3d_paint.py
🪛 ast-grep (0.44.1)
tests-unit/comfy_test/paint_parity/compare_reference.py

[warning] 63-63: File path is request-/variable-derived; validate and normalize to prevent path traversal.
Context: open(args.out, "w", encoding="utf-8")
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(open-filename-from-request)

tests-unit/comfy_test/paint_parity/capture_reference.py

[warning] 66-66: File path is request-/variable-derived; validate and normalize to prevent path traversal.
Context: open(path, "r", encoding="utf-8")
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(open-filename-from-request)


[warning] 92-92: File path is request-/variable-derived; validate and normalize to prevent path traversal.
Context: open(os.path.join(args.unet_dir, "config.json"), "r", encoding="utf-8")
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(open-filename-from-request)

tests-unit/comfy_test/paint_parity/bundle_format.py

[info] 67-67: use jsonify instead of json.dumps for JSON output
Context: json.dumps(v)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

tests-unit/comfy_test/test_hunyuan3d_paint_render.py

[warning] 382-382: File path is request-/variable-derived; validate and normalize to prevent path traversal.
Context: open(path, "rb")
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(open-filename-from-request)


[warning] 530-530: File path is request-/variable-derived; validate and normalize to prevent path traversal.
Context: open(path, "rb")
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(open-filename-from-request)


[warning] 619-619: File path is request-/variable-derived; validate and normalize to prevent path traversal.
Context: open(path, "rb")
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(open-filename-from-request)

🔇 Additional comments (31)
tests-unit/comfy_test/paint_parity/README.md (1)

1-58: LGTM!

tests-unit/comfy_test/paint_parity/compare_reference.py (1)

1-71: LGTM!

tests-unit/comfy_test/paint_parity/make_goldens.py (1)

1-33: LGTM!

tests-unit/comfy_test/test_hunyuan3d_paint_parity.py (1)

1-67: LGTM!

comfy/ldm/hunyuan3d/paint/attention.py (1)

59-258: LGTM!

comfy/ldm/hunyuan3d/paint/unet.py (1)

657-738: LGTM!

comfy/latent_formats.py (1)

778-787: LGTM!

comfy/ldm/hunyuan3d/paint/loader.py (1)

13-157: LGTM!

comfy/model_base.py (1)

2065-2098: LGTM!

comfy/model_detection.py (1)

727-731: LGTM!

comfy/supported_models.py (1)

1556-1588: LGTM!

Also applies to: 2447-2447

comfy/ldm/hunyuan3d/paint/__init__.py (1)

1-4: LGTM!

tests-unit/comfy_test/test_hunyuan3d_paint.py (4)

1-148: LGTM!


151-224: LGTM!


227-341: LGTM!


343-446: LGTM!

tests-unit/comfy_test/test_hunyuan3d_paint_render.py (3)

32-243: LGTM!


248-443: LGTM!


449-626: LGTM!

tests-unit/comfy_test/test_hunyuan3d_paint_conventions.py (2)

55-176: LGTM!


182-368: LGTM!

comfy/ldm/hunyuan3d/paint/CONVENTIONS.md (1)

1-102: LGTM!

comfy/ldm/hunyuan3d/paint/render.py (1)

183-303: LGTM!

comfy_api/latest/_util/geometry_types.py (1)

37-50: LGTM!

comfy_extras/nodes_hunyuan3d_paint.py (3)

50-97: LGTM!


165-294: LGTM!


333-365: LGTM!

nodes.py (1)

2450-2450: LGTM!

comfy_extras/nodes_save_3d.py (3)

79-169: LGTM!


269-289: LGTM!


413-433: LGTM!

Comment thread comfy/ldm/hunyuan3d/paint/attention.py Outdated
Comment thread comfy/ldm/hunyuan3d/paint/attention.py Outdated
Comment thread comfy/ldm/hunyuan3d/paint/render.py Outdated
Comment thread comfy/ldm/hunyuan3d/paint/render.py
Comment thread tests-unit/comfy_test/paint_parity/bundle_format.py
Comment thread tests-unit/comfy_test/paint_parity/capture_reference.py Outdated
Comment thread tests-unit/comfy_test/paint_parity/capture_reference.py
Comment thread tests-unit/comfy_test/paint_parity/harness.py Outdated
@jethac
jethac force-pushed the hunyuan21-paint branch from 3ed84cf to afc1074 Compare July 22, 2026 07:32
@jethac

jethac commented Jul 22, 2026

Copy link
Copy Markdown
Author

Addressed the review in the latest push (also rebased onto current master):

  • einops — removed entirely from both paint modules; every rearrange is now native reshape/flatten/permute. Verified semantics-exact: the committed parity goldens are untouched and the real-weight activation compare against the reference implementation is unchanged at 3.3e-6 max abs on the final noise prediction.
  • torch.no_grad wrappers — removed from core modules and from the parity harness (callers own the execution context now; the author-side CLI scripts wrap their own top-level runs).
  • Pole views (view_matrix, flagged Critical) — partially disputing this one: at the exact code in this PR the ±90° views do not produce NaNs — cos(π/2) rounds to 6.12e-17, so the cross product normalizes a tiny-but-nonzero vector, and because the reference computes the identical formula, the resulting orientation matches it (this is pinned by the convention suite's top/bottom chirality assertions, which pass). That said, orientation-by-rounding-residual is a fair robustness complaint, so the same orientation is now produced by an explicit deterministic fallback instead of the residual. No behavior change; the knife-edge is gone.
  • bake_multiview view/camera mismatch — now a clear ValueError naming both counts.
  • Missing capture keys — reported as missing in <side> capture rows in the parity report instead of a raw KeyError.
  • CPU capture on CUDA machines — the reference's hard-coded .to("cuda:0") is now always stripped in the capture path.
  • TypeError fallback in the reference loader — narrowed to the known diffusers config keyword mismatch; anything else re-raises.

81 tests pass post-rebase (paint suites + model detection), ruff clean.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@comfy/ldm/hunyuan3d/paint/CONVENTIONS.md`:
- Around line 18-22: The World frame description in normalize_mesh() incorrectly
identifies MESH_SCALE_FACTOR as the maximum vertex radius. Update it to describe
1.15 as the bounding-sphere diameter, or state the resulting maximum radius as
approximately 0.575, while preserving the existing transform and centering
details.

In `@tests-unit/comfy_test/test_hunyuan3d_paint_render.py`:
- Line 123: The test module keeps standard-library and third-party imports
inside test logic unnecessarily. Move math, BytesIO, numpy, and PIL.Image
imports to module scope, while retaining deferred comfy.* imports that depend on
args.cpu or established import-order requirements.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ae4f2476-5c75-4210-8346-994e16e8d29d

📥 Commits

Reviewing files that changed from the base of the PR and between 3ed84cf and afc1074449ef3168729489205aaeeade4d3429fc.

📒 Files selected for processing (27)
  • comfy/latent_formats.py
  • comfy/ldm/hunyuan3d/paint/CONVENTIONS.md
  • comfy/ldm/hunyuan3d/paint/__init__.py
  • comfy/ldm/hunyuan3d/paint/attention.py
  • comfy/ldm/hunyuan3d/paint/loader.py
  • comfy/ldm/hunyuan3d/paint/render.py
  • comfy/ldm/hunyuan3d/paint/unet.py
  • comfy/model_base.py
  • comfy/model_detection.py
  • comfy/supported_models.py
  • comfy_api/latest/_util/geometry_types.py
  • comfy_extras/nodes_hunyuan3d_paint.py
  • comfy_extras/nodes_save_3d.py
  • nodes.py
  • tests-unit/comfy_test/paint_parity/README.md
  • tests-unit/comfy_test/paint_parity/__init__.py
  • tests-unit/comfy_test/paint_parity/bundle_format.py
  • tests-unit/comfy_test/paint_parity/capture_reference.py
  • tests-unit/comfy_test/paint_parity/compare_reference.py
  • tests-unit/comfy_test/paint_parity/goldens/tiny_golden.safetensors
  • tests-unit/comfy_test/paint_parity/harness.py
  • tests-unit/comfy_test/paint_parity/make_goldens.py
  • tests-unit/comfy_test/parity_report.md
  • tests-unit/comfy_test/test_hunyuan3d_paint.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_conventions.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_parity.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_render.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (7)
**/*

📄 CodeRabbit inference engine (AGENTS.md)

**/*: Keep changes small, direct, and limited to the narrowest code path and fewest files necessary; prefer practical fixes over broad architectural work.
Prefer fewer dependencies and do not add a ComfyUI dependency unless absolutely necessary.
Remove obsolete code, dead branches, unused options, debug prints, and unnecessary compatibility paths.
Preserve existing APIs, node names, model-loading behavior, file layout, and workflow compatibility unless replacement is explicit.
Keep architectural layers focused; do not leak UI, API, workflow, queue, persistence, telemetry, model-loading, node, or execution concerns into unrelated layers.
Shared core modules should depend only on lower-level primitives and their own domain concepts; higher-level concepts belong at callers, adapters, services, or boundaries.
Pass only the narrowest data needed across boundaries and keep identity mapping, persistence, history, telemetry, response shaping, and UI state in their owning layers.
Before touching many files, identify the smallest owner layer; use caller-side mappings, adapters, events, or narrow interfaces instead of exposing private concepts across layers.
Core ComfyUI code must not make unsolicited internet requests or add uploads, telemetry, analytics, tracking, reporting, update checks, remote configuration, licensing checks, or similar outbound paths.
Model downloading is allowed only when explicitly authorized by the user, limited to the requested artifact, and free of telemetry, tracking, unrelated metadata, or background activity.
Warning and info messages should be short and actionable; documentation and README changes should be concise, factual, and tied to changed behavior.
Use short direct commit subjects such as Fix ..., Add ..., Support ..., Remove ..., or Update ...; keep PR descriptions short and state the problem, behavior change, and tests.
Prefer one coherent behavioral change per commit and prioritize crashes, incorrect dtype/device behavior, m...

Files:

  • tests-unit/comfy_test/parity_report.md
  • comfy/ldm/hunyuan3d/paint/__init__.py
  • tests-unit/comfy_test/paint_parity/README.md
  • nodes.py
  • tests-unit/comfy_test/paint_parity/compare_reference.py
  • comfy_api/latest/_util/geometry_types.py
  • tests-unit/comfy_test/paint_parity/make_goldens.py
  • comfy/model_detection.py
  • comfy/supported_models.py
  • comfy/ldm/hunyuan3d/paint/CONVENTIONS.md
  • tests-unit/comfy_test/paint_parity/capture_reference.py
  • tests-unit/comfy_test/paint_parity/goldens/tiny_golden.safetensors
  • comfy/latent_formats.py
  • comfy/ldm/hunyuan3d/paint/loader.py
  • comfy_extras/nodes_save_3d.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_parity.py
  • tests-unit/comfy_test/paint_parity/harness.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_render.py
  • comfy/model_base.py
  • comfy_extras/nodes_hunyuan3d_paint.py
  • comfy/ldm/hunyuan3d/paint/render.py
  • tests-unit/comfy_test/test_hunyuan3d_paint.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_conventions.py
  • comfy/ldm/hunyuan3d/paint/attention.py
  • tests-unit/comfy_test/paint_parity/bundle_format.py
  • comfy/ldm/hunyuan3d/paint/unet.py
**

⚙️ CodeRabbit configuration file

**: IMPORTANT: Only comment on issues directly introduced by this PR's code changes.
Treat AGENTS.md as mandatory repository policy, not optional style guidance.
Flag PR changes that violate AGENTS.md even when the code is otherwise functional.
In particular, enforce architecture boundaries, dtype/device/memory rules,
interface contracts, import style, no unnecessary try/except blocks, no inline
imports, no outbound internet paths in core ComfyUI, and narrow scoped fixes.
Prefer direct findings over suggestions when a rule is violated. Only ignore
AGENTS.md when it clearly conflicts with a newer explicit maintainer instruction
in the PR.
Do NOT flag pre-existing issues in code that was merely moved, re-indented,
de-indented, or reformatted without logic changes. If code appears in the diff
only due to whitespace or structural reformatting (e.g., removing a with: block),
treat it as unchanged. Contributors should not feel obligated to address
pre-existing issues outside the scope of their contribution.

Files:

  • tests-unit/comfy_test/parity_report.md
  • comfy/ldm/hunyuan3d/paint/__init__.py
  • tests-unit/comfy_test/paint_parity/README.md
  • nodes.py
  • tests-unit/comfy_test/paint_parity/compare_reference.py
  • comfy_api/latest/_util/geometry_types.py
  • tests-unit/comfy_test/paint_parity/make_goldens.py
  • comfy/model_detection.py
  • comfy/supported_models.py
  • comfy/ldm/hunyuan3d/paint/CONVENTIONS.md
  • tests-unit/comfy_test/paint_parity/capture_reference.py
  • tests-unit/comfy_test/paint_parity/goldens/tiny_golden.safetensors
  • comfy/latent_formats.py
  • comfy/ldm/hunyuan3d/paint/loader.py
  • comfy_extras/nodes_save_3d.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_parity.py
  • tests-unit/comfy_test/paint_parity/harness.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_render.py
  • comfy/model_base.py
  • comfy_extras/nodes_hunyuan3d_paint.py
  • comfy/ldm/hunyuan3d/paint/render.py
  • tests-unit/comfy_test/test_hunyuan3d_paint.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_conventions.py
  • comfy/ldm/hunyuan3d/paint/attention.py
  • tests-unit/comfy_test/paint_parity/bundle_format.py
  • comfy/ldm/hunyuan3d/paint/unet.py
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Keep state and capability flags on the object that owns the behavior; use explicit parent-owned fields rather than probing children with getattr for parent control flow.
Keep public methods aligned with caller contracts; preserve arguments, parameter order, return types, side effects, and error behavior unless all affected interfaces are intentionally updated.
Do not add unused compatibility parameters, flags, attributes, constructor options, or model-specific options to shared helpers.
Normalize third-party and upstream return conventions at integration boundaries so core code receives the expected type and shape.
Avoid caller-side unwrapping such as out = out[0] unless the called interface documents that return structure.
Do not add torch.no_grad, torch.inference_mode, or inference-mode wrappers; only disable a globally enabled inference mode when a training path requires gradients.
Do not add freeze, unfreeze, or trainability toggles to ComfyUI model classes.
Remove training-only behavior such as dropout from inference models while preserving checkpoint and state-dict compatibility, using nn.Identity when necessary to retain slots.
Keep imports at module scope; use inline imports only for established optional-backend probes or import-cycle avoidance.
Use try/except only for optional dependency, platform, or backend detection with a useful fallback, and prefer specific exception types.
Do not add code for unsupported pinned library versions or obsolete PyTorch workarounds; unsupported formats, quantization metadata, and bad states should fail clearly.
Match local file style and keep comments sparse, useful, and non-obvious; remove comments that merely restate code.

Files:

  • comfy/ldm/hunyuan3d/paint/__init__.py
  • nodes.py
  • tests-unit/comfy_test/paint_parity/compare_reference.py
  • comfy_api/latest/_util/geometry_types.py
  • tests-unit/comfy_test/paint_parity/make_goldens.py
  • comfy/model_detection.py
  • comfy/supported_models.py
  • tests-unit/comfy_test/paint_parity/capture_reference.py
  • comfy/latent_formats.py
  • comfy/ldm/hunyuan3d/paint/loader.py
  • comfy_extras/nodes_save_3d.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_parity.py
  • tests-unit/comfy_test/paint_parity/harness.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_render.py
  • comfy/model_base.py
  • comfy_extras/nodes_hunyuan3d_paint.py
  • comfy/ldm/hunyuan3d/paint/render.py
  • tests-unit/comfy_test/test_hunyuan3d_paint.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_conventions.py
  • comfy/ldm/hunyuan3d/paint/attention.py
  • tests-unit/comfy_test/paint_parity/bundle_format.py
  • comfy/ldm/hunyuan3d/paint/unet.py
comfy/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

comfy/**/*.py: Treat dtype, device placement, VRAM use, offloading, and memory behavior as correctness concerns; use existing ComfyUI quantization, memory, offload, and optimized-operation helpers.
Prefer shared optimized kernels, backend dispatchers, and documented interfaces over duplicate handwritten operations; treat selected backend callables as opaque.
Do not duplicate operations with custom float32-upcasting inference kernels; use generic ComfyUI operations or native PyTorch operations.
If a model constructor has an operations parameter, assume it is never None; do not add fallback torch operations.
Avoid unnecessary parameters in model, block, and operation constructors or forwards; reuse existing model classes, blocks, operations, and helpers.
Model detectors must inspect only the first dimension of linear weights, guard every dereferenced state-dict key, and order specific signatures before broad fallbacks.
Avoid einops in core inference code; use native tensor operations such as reshape, view, permute, transpose, flatten, and related methods.
Keep metadata, counters, shape calculations, indices, split boundaries, and control-flow values as Python values rather than tensors.
Avoid unnecessary casts and transfers; preserve intended compute and storage dtypes, tensor shapes, and backend result contracts.
Keep model-native latent layout handling inside the model or latent-format owner rather than reshaping it in nodes or caller-side adapters.
DiT models must pad every patchified target or reference input with comfy.ldm.common_dit.pad_to_patch_size and crop only the target output back to its original dimensions.
Do not add defensive shape, configuration, or dtype casts that merely obscure a clear tensor-operation failure; validate only at meaningful boundaries.
Raw parameters not owned by an operation should be cast at use with comfy.ops.cast_to_input or comfy.model_management.cast_to; model constructors should not contain dtype workaro...

Files:

  • comfy/ldm/hunyuan3d/paint/__init__.py
  • comfy/model_detection.py
  • comfy/supported_models.py
  • comfy/latent_formats.py
  • comfy/ldm/hunyuan3d/paint/loader.py
  • comfy/model_base.py
  • comfy/ldm/hunyuan3d/paint/render.py
  • comfy/ldm/hunyuan3d/paint/attention.py
  • comfy/ldm/hunyuan3d/paint/unet.py
comfy/**

⚙️ CodeRabbit configuration file

comfy/**: Core ML/diffusion engine. Focus on:

  • Backward compatibility (breaking changes affect all custom nodes)
  • Memory management and GPU resource handling
  • Performance implications in hot paths
  • Thread safety for concurrent execution

Files:

  • comfy/ldm/hunyuan3d/paint/__init__.py
  • comfy/model_detection.py
  • comfy/supported_models.py
  • comfy/ldm/hunyuan3d/paint/CONVENTIONS.md
  • comfy/latent_formats.py
  • comfy/ldm/hunyuan3d/paint/loader.py
  • comfy/model_base.py
  • comfy/ldm/hunyuan3d/paint/render.py
  • comfy/ldm/hunyuan3d/paint/attention.py
  • comfy/ldm/hunyuan3d/paint/unet.py
nodes.py

⚙️ CodeRabbit configuration file

nodes.py: Core node definitions (2500+ lines). Focus on:

  • Backward compatibility of NODE_CLASS_MAPPINGS
  • Consistency of INPUT_TYPES return format

Files:

  • nodes.py
comfy_extras/**

⚙️ CodeRabbit configuration file

comfy_extras/**: Community-contributed extra nodes. Focus on:

  • Consistency with node patterns (INPUT_TYPES, RETURN_TYPES, FUNCTION, CATEGORY)
  • No breaking changes to existing node interfaces

Files:

  • comfy_extras/nodes_save_3d.py
  • comfy_extras/nodes_hunyuan3d_paint.py
🧠 Learnings (7)
📚 Learning: 2026-02-21T14:01:41.482Z
Learnt from: pythongosssss
Repo: Comfy-Org/ComfyUI PR: 12555
File: comfy_extras/nodes_glsl.py:719-724
Timestamp: 2026-02-21T14:01:41.482Z
Learning: In PyOpenGL, bare Python scalars can be accepted for 1-element array parameters by NumberHandler. This means you can pass an int/float directly to OpenGL texture deletion (e.g., glDeleteTextures(tex)) without wrapping in a list. Verify function-specific expectations and ensure types match what the OpenGL call expects; use explicit lists only when the API requires an array.

Applied to files:

  • comfy/ldm/hunyuan3d/paint/__init__.py
  • nodes.py
  • tests-unit/comfy_test/paint_parity/compare_reference.py
  • comfy_api/latest/_util/geometry_types.py
  • tests-unit/comfy_test/paint_parity/make_goldens.py
  • comfy/model_detection.py
  • comfy/supported_models.py
  • tests-unit/comfy_test/paint_parity/capture_reference.py
  • comfy/latent_formats.py
  • comfy/ldm/hunyuan3d/paint/loader.py
  • comfy_extras/nodes_save_3d.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_parity.py
  • tests-unit/comfy_test/paint_parity/harness.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_render.py
  • comfy/model_base.py
  • comfy_extras/nodes_hunyuan3d_paint.py
  • comfy/ldm/hunyuan3d/paint/render.py
  • tests-unit/comfy_test/test_hunyuan3d_paint.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_conventions.py
  • comfy/ldm/hunyuan3d/paint/attention.py
  • tests-unit/comfy_test/paint_parity/bundle_format.py
  • comfy/ldm/hunyuan3d/paint/unet.py
📚 Learning: 2026-05-13T12:31:45.069Z
Learnt from: rattus128
Repo: Comfy-Org/ComfyUI PR: 13802
File: comfy/pinned_memory.py:19-30
Timestamp: 2026-05-13T12:31:45.069Z
Learning: When reviewing code that uses comfy/pinned_memory.py’s `HostBuffer.extend(size=..., reallocate=...)`: by default (`reallocate` is not True / False), `extend(size=...)` is a *relative increment* that grows the buffer by `size` bytes—so slicing like `[offset:offset+size]` after `hostbuf.extend(size=size)` is correct and the argument should not be rewritten to `offset + size`. Only in the single-segment reallocation mode (`reallocate=True`, e.g., as used by `resize_pin_buffer()` in `comfy/model_management.py`) should `size` be treated as an *absolute target* and the call/arguments should be checked accordingly.

Applied to files:

  • comfy/ldm/hunyuan3d/paint/__init__.py
  • comfy/model_detection.py
  • comfy/supported_models.py
  • comfy/latent_formats.py
  • comfy/ldm/hunyuan3d/paint/loader.py
  • comfy/model_base.py
  • comfy/ldm/hunyuan3d/paint/render.py
  • comfy/ldm/hunyuan3d/paint/attention.py
  • comfy/ldm/hunyuan3d/paint/unet.py
📚 Learning: 2026-05-04T18:30:37.579Z
Learnt from: Talmaj
Repo: Comfy-Org/ComfyUI PR: 13655
File: comfy/model_detection.py:907-917
Timestamp: 2026-05-04T18:30:37.579Z
Learning: In ComfyUI’s internal supported model implementations (comfy/supported_models_base.py and comfy/supported_models/*.py), ensure model classes do not override matches() in their own class bodies. All supported models should use BASE.matches() for backward compatibility; if a future change introduces a matches() override in a subclass, treat it as a backward-compatibility risk and require additional review/testing to confirm behavior remains consistent with BASE.matches().

Applied to files:

  • comfy/supported_models.py
📚 Learning: 2026-03-04T14:05:31.426Z
Learnt from: jtydhr88
Repo: Comfy-Org/ComfyUI PR: 12757
File: comfy_extras/nodes_custom_sampler.py:1069-1089
Timestamp: 2026-03-04T14:05:31.426Z
Learning: In the ComfyUI sampling pipeline, treat percent_to_sigma(0.0) as a sentinel value (999999999.9) that means starting from pure noise. This is consistent with BasicScheduler via calculate_sigmas. The SamplingPercentToSigma node’s return_actual_sigma flag differentiates this sentinel from sigma_max. Reviewers should not flag CurveToSigmas or similar nodes that rely on percent_to_sigma as bugs; downstream samplers are expected to handle the sentinel correctly. When reviewing related sampling-related code, assume this sentinel semantics unless there is explicit handling for a real sigma_max.

Applied to files:

  • comfy_extras/nodes_save_3d.py
  • comfy_extras/nodes_hunyuan3d_paint.py
📚 Learning: 2026-04-04T13:29:15.653Z
Learnt from: kijai
Repo: Comfy-Org/ComfyUI PR: 13258
File: comfy_extras/nodes_frame_interpolation.py:151-189
Timestamp: 2026-04-04T13:29:15.653Z
Learning: In this ComfyUI codebase, node `execute()` inference is already run under a global `torch.inference_mode()` context established in the execution engine (e.g., `execution.py` around line ~732). During review, avoid recommending changes that wrap node inference loops in `torch.inference_mode()`—it is already applied, so such suggestions are likely redundant.

Applied to files:

  • comfy_extras/nodes_save_3d.py
  • comfy_extras/nodes_hunyuan3d_paint.py
📚 Learning: 2026-05-09T18:40:40.199Z
Learnt from: kijai
Repo: Comfy-Org/ComfyUI PR: 13813
File: comfy_extras/nodes_wandancer.py:868-872
Timestamp: 2026-05-09T18:40:40.199Z
Learning: When building video/temporal decoding nodes that call ComfyUI’s VAE.decode (comfy/sd.py), leverage VAE.decode’s existing VRAM-aware chunking along dim 0. Reshape or transpose the latent so the temporal dimension T is folded into dim 0 (e.g., transform a latent of shape [B, T, C, H, W] into [B*T, C, H, W] before calling vae.decode). This lets VAE.decode do chunked decoding without needing an explicit per-frame loop inside the node itself.

Applied to files:

  • comfy_extras/nodes_save_3d.py
  • comfy_extras/nodes_hunyuan3d_paint.py
📚 Learning: 2026-05-20T00:10:14.673Z
Learnt from: Pauan
Repo: Comfy-Org/ComfyUI PR: 13997
File: comfy_extras/nodes_string.py:12-25
Timestamp: 2026-05-20T00:10:14.673Z
Learning: In the ComfyUI `comfy_extras/` codebase, some nodes intentionally ship with a default input string that references parameters that may not yet be connected. If the default would raise a `KeyError` (e.g., examples like `MathExpression` default `a + b`, or `StringFormat` default `{a}` with `min=0` and autogrow inputs), treat it as an intentional “hint default” UX pattern, not a bug. During review, do not flag this behavior or recommend changing `min` to `1` or altering the default to an empty string solely to avoid the `KeyError`.

Applied to files:

  • comfy_extras/nodes_save_3d.py
  • comfy_extras/nodes_hunyuan3d_paint.py
🪛 ast-grep (0.44.1)
tests-unit/comfy_test/paint_parity/compare_reference.py

[warning] 64-64: File path is request-/variable-derived; validate and normalize to prevent path traversal.
Context: open(args.out, "w", encoding="utf-8")
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(open-filename-from-request)

tests-unit/comfy_test/paint_parity/capture_reference.py

[warning] 66-66: File path is request-/variable-derived; validate and normalize to prevent path traversal.
Context: open(path, "r", encoding="utf-8")
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(open-filename-from-request)


[warning] 94-94: File path is request-/variable-derived; validate and normalize to prevent path traversal.
Context: open(os.path.join(args.unet_dir, "config.json"), "r", encoding="utf-8")
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(open-filename-from-request)

tests-unit/comfy_test/test_hunyuan3d_paint_render.py

[warning] 382-382: File path is request-/variable-derived; validate and normalize to prevent path traversal.
Context: open(path, "rb")
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(open-filename-from-request)


[warning] 530-530: File path is request-/variable-derived; validate and normalize to prevent path traversal.
Context: open(path, "rb")
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(open-filename-from-request)


[warning] 619-619: File path is request-/variable-derived; validate and normalize to prevent path traversal.
Context: open(path, "rb")
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(open-filename-from-request)

tests-unit/comfy_test/paint_parity/bundle_format.py

[info] 67-67: use jsonify instead of json.dumps for JSON output
Context: json.dumps(v)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

🔇 Additional comments (40)
tests-unit/comfy_test/paint_parity/capture_reference.py (1)

147-158: 📐 Maintainability & Code Quality | ⚡ Quick win

Remove the leftover torch.inference_mode() wrapper here too.

This exact site was already flagged for removal in a prior review round (paired with the harness.py fixes at lines 44-48/92-101, which now let the caller own the execution context). Those sibling fixes landed, but this wrapper around the reference model's forward call was left in place.

🔧 Proposed fix
-    with torch.inference_mode():
-        out = model(
-            tensors["input/sample"],
-            tensors["input/timestep"],
-            tensors["input/encoder_hidden_states"],
-            ref_latents=tensors["input/ref_latents"],
-            embeds_normal=tensors["input/embeds_normal"],
-            embeds_position=tensors["input/embeds_position"],
-            position_maps=tensors["input/position_maps"],
-            dino_hidden_states=tensors["input/dino_hidden_states"],
-            mva_scale=1.0, ref_scale=1.0, cache={},
-        )
+    out = model(
+        tensors["input/sample"],
+        tensors["input/timestep"],
+        tensors["input/encoder_hidden_states"],
+        ref_latents=tensors["input/ref_latents"],
+        embeds_normal=tensors["input/embeds_normal"],
+        embeds_position=tensors["input/embeds_position"],
+        position_maps=tensors["input/position_maps"],
+        dino_hidden_states=tensors["input/dino_hidden_states"],
+        mva_scale=1.0, ref_scale=1.0, cache={},
+    )

As per coding guidelines, "Do not add torch.no_grad, torch.inference_mode, or inference-mode wrappers; only disable a globally enabled inference mode when a training path requires gradients."

Source: Coding guidelines

tests-unit/comfy_test/paint_parity/README.md (1)

1-58: LGTM!

tests-unit/comfy_test/paint_parity/bundle_format.py (1)

1-117: LGTM!

tests-unit/comfy_test/paint_parity/compare_reference.py (1)

1-73: LGTM!

tests-unit/comfy_test/paint_parity/goldens/tiny_golden.safetensors (1)

1-218: LGTM!

tests-unit/comfy_test/paint_parity/harness.py (1)

37-125: LGTM!

tests-unit/comfy_test/paint_parity/make_goldens.py (1)

1-34: LGTM!

tests-unit/comfy_test/parity_report.md (1)

1-18: LGTM!

tests-unit/comfy_test/test_hunyuan3d_paint_parity.py (1)

1-68: LGTM!

comfy/ldm/hunyuan3d/paint/render.py (3)

119-131: LGTM!


495-499: LGTM!


188-308: LGTM!

Also applies to: 433-534

comfy_extras/nodes_hunyuan3d_paint.py (1)

78-97: LGTM!

Also applies to: 165-294, 333-365

nodes.py (1)

2450-2450: LGTM!

comfy_api/latest/_util/geometry_types.py (1)

37-37: LGTM!

Also applies to: 48-50

comfy_extras/nodes_save_3d.py (1)

79-94: LGTM!

Also applies to: 129-160, 169-169, 260-290, 413-433

comfy/ldm/hunyuan3d/paint/attention.py (1)

20-311: LGTM!

comfy/ldm/hunyuan3d/paint/unet.py (1)

22-741: LGTM!

comfy/latent_formats.py (1)

778-787: LGTM!

comfy/ldm/hunyuan3d/paint/loader.py (1)

1-157: LGTM!

comfy/model_base.py (1)

50-50: LGTM!

Also applies to: 2065-2098

comfy/model_detection.py (1)

2-2: LGTM!

Also applies to: 727-731

comfy/supported_models.py (1)

1556-1587: LGTM!

Also applies to: 2447-2447

comfy/ldm/hunyuan3d/paint/__init__.py (1)

1-4: LGTM!

tests-unit/comfy_test/test_hunyuan3d_paint_render.py (6)

32-78: LGTM!


90-132: LGTM!


156-242: LGTM!


248-376: LGTM!


403-443: LGTM!


454-626: LGTM!

tests-unit/comfy_test/test_hunyuan3d_paint.py (9)

1-42: LGTM!


44-52: 📐 Maintainability & Code Quality | ⚡ Quick win

Non-deterministic seed offset via hash().

hash(name) on a str is randomized per-process (PYTHONHASHSEED), so the per-parameter seed offset — and therefore the actual init values used by every test calling _init_weights — differs across separate pytest invocations even though seed is fixed. This undermines the reproducibility this helper is meant to provide (e.g. reproducing a numeric failure locally). Use a stable hash (e.g. zlib.crc32(name.encode())) instead of the built-in hash().

🔧 Proposed fix
+import zlib
+
 def _init_weights(model, seed=0, scale=0.03):
     """Small seeded init: disable_weight_init leaves parameters uninitialized
     (torch.empty garbage), which is fine for shape tests but overflows through a
     deep net; tests asserting finite numerics need real (small) weights."""
     with torch.no_grad():
         for name, p in sorted(model.named_parameters()):
-            g = torch.Generator().manual_seed(seed + (hash(name) % 65536))
+            g = torch.Generator().manual_seed(seed + (zlib.crc32(name.encode()) % 65536))
             p.copy_(torch.randn(p.shape, generator=g, dtype=torch.float32).to(p.dtype) * scale)
     return model

55-83: LGTM!


85-148: LGTM!


151-225: LGTM!


227-298: LGTM!


300-341: LGTM!


343-375: LGTM!


377-446: LGTM!

tests-unit/comfy_test/test_hunyuan3d_paint_conventions.py (1)

1-369: LGTM!

Comment thread comfy/ldm/hunyuan3d/paint/CONVENTIONS.md Outdated
Comment thread tests-unit/comfy_test/test_hunyuan3d_paint_render.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests-unit/comfy_test/test_hunyuan3d_paint_render.py (1)

492-497: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Keep the coverage check from becoming vacuous.

If baking produces no covered texels, all torch.allclose assertions pass on empty tensors, so this test can miss a broken bake entirely. Assert that covered contains at least one texel before validating MR channels.

Proposed fix
     covered = alb_tex[0].abs().sum(-1) > 0
+    assert bool(covered.any()), "expected baked texture coverage"
     assert torch.allclose(mr_tex[0][covered][:, 0], torch.full((int(covered.sum()),), 0.2), atol=1e-3)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests-unit/comfy_test/test_hunyuan3d_paint_render.py` around lines 492 - 497,
Update the coverage validation in the test around the covered mask to assert
that covered contains at least one texel before running the MR channel
comparisons. Keep the existing torch.allclose checks and expected channel values
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@tests-unit/comfy_test/test_hunyuan3d_paint_render.py`:
- Around line 492-497: Update the coverage validation in the test around the
covered mask to assert that covered contains at least one texel before running
the MR channel comparisons. Keep the existing torch.allclose checks and expected
channel values unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 9210662f-abe9-43ec-b237-21ae8696f55f

📥 Commits

Reviewing files that changed from the base of the PR and between afc1074449ef3168729489205aaeeade4d3429fc and 630bb7c2d77ed7fad057e25f01aa223df0e50131.

📒 Files selected for processing (2)
  • comfy/ldm/hunyuan3d/paint/CONVENTIONS.md
  • tests-unit/comfy_test/test_hunyuan3d_paint_render.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (4)
**/*

📄 CodeRabbit inference engine (AGENTS.md)

**/*: Keep changes small, direct, and limited to the narrowest code path and fewest files necessary; prefer practical fixes over broad architectural work.
Prefer fewer dependencies and do not add a ComfyUI dependency unless absolutely necessary.
Remove obsolete code, dead branches, unused options, debug prints, and unnecessary compatibility paths.
Preserve existing APIs, node names, model-loading behavior, file layout, and workflow compatibility unless replacement is explicit.
Keep architectural layers focused; do not leak UI, API, workflow, queue, persistence, telemetry, model-loading, node, or execution concerns into unrelated layers.
Shared core modules should depend only on lower-level primitives and their own domain concepts; higher-level concepts belong at callers, adapters, services, or boundaries.
Pass only the narrowest data needed across boundaries and keep identity mapping, persistence, history, telemetry, response shaping, and UI state in their owning layers.
Before touching many files, identify the smallest owner layer; use caller-side mappings, adapters, events, or narrow interfaces instead of exposing private concepts across layers.
Core ComfyUI code must not make unsolicited internet requests or add uploads, telemetry, analytics, tracking, reporting, update checks, remote configuration, licensing checks, or similar outbound paths.
Model downloading is allowed only when explicitly authorized by the user, limited to the requested artifact, and free of telemetry, tracking, unrelated metadata, or background activity.
Warning and info messages should be short and actionable; documentation and README changes should be concise, factual, and tied to changed behavior.
Use short direct commit subjects such as Fix ..., Add ..., Support ..., Remove ..., or Update ...; keep PR descriptions short and state the problem, behavior change, and tests.
Prefer one coherent behavioral change per commit and prioritize crashes, incorrect dtype/device behavior, m...

Files:

  • comfy/ldm/hunyuan3d/paint/CONVENTIONS.md
  • tests-unit/comfy_test/test_hunyuan3d_paint_render.py
**

⚙️ CodeRabbit configuration file

**: IMPORTANT: Only comment on issues directly introduced by this PR's code changes.
Treat AGENTS.md as mandatory repository policy, not optional style guidance.
Flag PR changes that violate AGENTS.md even when the code is otherwise functional.
In particular, enforce architecture boundaries, dtype/device/memory rules,
interface contracts, import style, no unnecessary try/except blocks, no inline
imports, no outbound internet paths in core ComfyUI, and narrow scoped fixes.
Prefer direct findings over suggestions when a rule is violated. Only ignore
AGENTS.md when it clearly conflicts with a newer explicit maintainer instruction
in the PR.
Do NOT flag pre-existing issues in code that was merely moved, re-indented,
de-indented, or reformatted without logic changes. If code appears in the diff
only due to whitespace or structural reformatting (e.g., removing a with: block),
treat it as unchanged. Contributors should not feel obligated to address
pre-existing issues outside the scope of their contribution.

Files:

  • comfy/ldm/hunyuan3d/paint/CONVENTIONS.md
  • tests-unit/comfy_test/test_hunyuan3d_paint_render.py
comfy/**

⚙️ CodeRabbit configuration file

comfy/**: Core ML/diffusion engine. Focus on:

  • Backward compatibility (breaking changes affect all custom nodes)
  • Memory management and GPU resource handling
  • Performance implications in hot paths
  • Thread safety for concurrent execution

Files:

  • comfy/ldm/hunyuan3d/paint/CONVENTIONS.md
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Keep state and capability flags on the object that owns the behavior; use explicit parent-owned fields rather than probing children with getattr for parent control flow.
Keep public methods aligned with caller contracts; preserve arguments, parameter order, return types, side effects, and error behavior unless all affected interfaces are intentionally updated.
Do not add unused compatibility parameters, flags, attributes, constructor options, or model-specific options to shared helpers.
Normalize third-party and upstream return conventions at integration boundaries so core code receives the expected type and shape.
Avoid caller-side unwrapping such as out = out[0] unless the called interface documents that return structure.
Do not add torch.no_grad, torch.inference_mode, or inference-mode wrappers; only disable a globally enabled inference mode when a training path requires gradients.
Do not add freeze, unfreeze, or trainability toggles to ComfyUI model classes.
Remove training-only behavior such as dropout from inference models while preserving checkpoint and state-dict compatibility, using nn.Identity when necessary to retain slots.
Keep imports at module scope; use inline imports only for established optional-backend probes or import-cycle avoidance.
Use try/except only for optional dependency, platform, or backend detection with a useful fallback, and prefer specific exception types.
Do not add code for unsupported pinned library versions or obsolete PyTorch workarounds; unsupported formats, quantization metadata, and bad states should fail clearly.
Match local file style and keep comments sparse, useful, and non-obvious; remove comments that merely restate code.

Files:

  • tests-unit/comfy_test/test_hunyuan3d_paint_render.py
🧠 Learnings (1)
📚 Learning: 2026-02-21T14:01:41.482Z
Learnt from: pythongosssss
Repo: Comfy-Org/ComfyUI PR: 12555
File: comfy_extras/nodes_glsl.py:719-724
Timestamp: 2026-02-21T14:01:41.482Z
Learning: In PyOpenGL, bare Python scalars can be accepted for 1-element array parameters by NumberHandler. This means you can pass an int/float directly to OpenGL texture deletion (e.g., glDeleteTextures(tex)) without wrapping in a list. Verify function-specific expectations and ensure types match what the OpenGL call expects; use explicit lists only when the API requires an array.

Applied to files:

  • tests-unit/comfy_test/test_hunyuan3d_paint_render.py
🔇 Additional comments (2)
tests-unit/comfy_test/test_hunyuan3d_paint_render.py (1)

16-23: LGTM!

Also applies to: 448-491, 498-540

comfy/ldm/hunyuan3d/paint/CONVENTIONS.md (1)

1-103: LGTM!

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 22, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@comfy_api/latest/_util/geometry_types.py`:
- Line 37: Move the optional texture_mr parameter to the end of the MESH
constructor signature, after all existing positional parameters such as
vertex_counts, face_counts, and unlit. Preserve the current ordering of every
pre-existing parameter so positional callers retain their established bindings,
while keeping texture_mr optional.

In `@comfy_extras/nodes_hunyuan3d_paint.py`:
- Around line 92-93: Replace the early return in the validation branch around
cond with an explicit failure when the latent is not 5D or its view dimension is
not divisible by len(azims). Preserve normal processing for valid packed
latents, but ensure this misconfiguration cannot silently fall back to scalar
CFG.
- Around line 348-351: Update the adjacent albedo and MR bake calls in the paint
rendering flow to combine their view data into one six-channel input and invoke
paint_render.bake_multiview once with the shared geometry, UVs, cameras,
texture_size, and bake_exp. Split the returned channels and corresponding masks
back into albedo_tex/mask_a and mr_tex/mask_mr while preserving channel ordering
and independent per-channel results.

In `@comfy_extras/nodes_save_3d.py`:
- Around line 274-285: Update the material export flow around the outer
texture_png_bytes/TEXCOORD_0 guard so a metallic-roughness texture without a
base-color texture is not encoded into the BIN without references. Either emit
valid MR-only material references outside that guard or skip MR texture encoding
and buffer-byte accounting when the base texture is absent.

In `@comfy/ldm/hunyuan3d/paint/render.py`:
- Around line 248-259: The sampling loop in the area/sel chunk path allows a
single face to allocate its entire bounding-box area despite the chunk budget.
Update the logic around the per-face expansion using area, local, off, and pixel
coordinates to split oversized faces into bounded scanline bands or otherwise
cap each expansion by chunk_area; preserve the resulting global face indices and
pixel coordinates while ensuring temporary tensors never scale beyond the
configured chunk budget.
- Around line 244-247: Update the chunking loop in the rendering function
containing chunk_id to exploit its monotonic contiguous ranges: compute chunk
boundaries once, then derive each chunk’s face selection by slicing the
corresponding range instead of calling torch.nonzero(chunk_id == c) for every
chunk. Preserve empty-chunk handling and the existing per-chunk processing
behavior.

In `@comfy/ldm/hunyuan3d/paint/unet.py`:
- Around line 623-628: Replace zero-initialization with uninitialized allocation
for the checkpoint-owned parameters created in the pbr_setting loop and
learned_text_clip_ref, using torch.empty with the same shape, dtype, and device.
Preserve parameter registration and rely on the checkpoint loader to populate
every value.

In `@comfy/model_base.py`:
- Around line 2095-2097: Update the ref_scale handling in the surrounding
conditioning setup to avoid constructing a fixed float32 tensor with
torch.FloatTensor; create the value without forcing a concrete dtype, or ensure
it is cast to the attention input dtype at the application site, preserving
fp16/bf16 compute in the UNet.

In `@tests-unit/comfy_test/paint_parity/capture_reference.py`:
- Around line 175-176: Update the cpu_patch description in the capture reference
metadata to remove the obsolete conditional and always use the active patch
description, since cpu_patch is now unconditional. Keep the existing “none”
fallback removed from this metadata entry.

In `@tests-unit/comfy_test/paint_parity/compare_reference.py`:
- Around line 32-36: Move the safetensors.torch load_file import from inside
_load_state_dict to module scope, then keep the existing .safetensors branch
behavior unchanged while continuing to use torch.load for other paths.

In `@tests-unit/comfy_test/test_hunyuan3d_paint.py`:
- Around line 44-52: Update _init_weights to derive each parameter’s generator
seed deterministically without using Python’s salted hash(name), such as by
using the sorted-parameter index or a stable hash of the parameter name.
Preserve distinct per-parameter seeds, the existing base seed and scale
behavior, and reproducible finite initialization for the numerical tests.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d43a6e67-35ed-445e-9eb5-b9f8c4f8685b

📥 Commits

Reviewing files that changed from the base of the PR and between c7540cfcd52c650d7c3308ab4316926b5ab834a6 and 58519ad.

📒 Files selected for processing (27)
  • comfy/latent_formats.py
  • comfy/ldm/hunyuan3d/paint/CONVENTIONS.md
  • comfy/ldm/hunyuan3d/paint/__init__.py
  • comfy/ldm/hunyuan3d/paint/attention.py
  • comfy/ldm/hunyuan3d/paint/loader.py
  • comfy/ldm/hunyuan3d/paint/render.py
  • comfy/ldm/hunyuan3d/paint/unet.py
  • comfy/model_base.py
  • comfy/model_detection.py
  • comfy/supported_models.py
  • comfy_api/latest/_util/geometry_types.py
  • comfy_extras/nodes_hunyuan3d_paint.py
  • comfy_extras/nodes_save_3d.py
  • nodes.py
  • tests-unit/comfy_test/paint_parity/README.md
  • tests-unit/comfy_test/paint_parity/__init__.py
  • tests-unit/comfy_test/paint_parity/bundle_format.py
  • tests-unit/comfy_test/paint_parity/capture_reference.py
  • tests-unit/comfy_test/paint_parity/compare_reference.py
  • tests-unit/comfy_test/paint_parity/goldens/tiny_golden.safetensors
  • tests-unit/comfy_test/paint_parity/harness.py
  • tests-unit/comfy_test/paint_parity/make_goldens.py
  • tests-unit/comfy_test/parity_report.md
  • tests-unit/comfy_test/test_hunyuan3d_paint.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_conventions.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_parity.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_render.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (7)
**/*

📄 CodeRabbit inference engine (AGENTS.md)

**/*: Keep changes small, direct, and limited to the narrowest code path and fewest files necessary; prefer practical fixes over broad architectural work.
Prefer fewer dependencies and do not add a ComfyUI dependency unless absolutely necessary.
Remove obsolete code, dead branches, unused options, debug prints, and unnecessary compatibility paths.
Preserve existing APIs, node names, model-loading behavior, file layout, and workflow compatibility unless replacement is explicit.
Keep architectural layers focused; do not leak UI, API, workflow, queue, persistence, telemetry, model-loading, node, or execution concerns into unrelated layers.
Shared core modules should depend only on lower-level primitives and their own domain concepts; higher-level concepts belong at callers, adapters, services, or boundaries.
Pass only the narrowest data needed across boundaries and keep identity mapping, persistence, history, telemetry, response shaping, and UI state in their owning layers.
Before touching many files, identify the smallest owner layer; use caller-side mappings, adapters, events, or narrow interfaces instead of exposing private concepts across layers.
Core ComfyUI code must not make unsolicited internet requests or add uploads, telemetry, analytics, tracking, reporting, update checks, remote configuration, licensing checks, or similar outbound paths.
Model downloading is allowed only when explicitly authorized by the user, limited to the requested artifact, and free of telemetry, tracking, unrelated metadata, or background activity.
Warning and info messages should be short and actionable; documentation and README changes should be concise, factual, and tied to changed behavior.
Use short direct commit subjects such as Fix ..., Add ..., Support ..., Remove ..., or Update ...; keep PR descriptions short and state the problem, behavior change, and tests.
Prefer one coherent behavioral change per commit and prioritize crashes, incorrect dtype/device behavior, m...

Files:

  • tests-unit/comfy_test/parity_report.md
  • comfy/ldm/hunyuan3d/paint/__init__.py
  • comfy_api/latest/_util/geometry_types.py
  • tests-unit/comfy_test/paint_parity/README.md
  • nodes.py
  • comfy/supported_models.py
  • tests-unit/comfy_test/paint_parity/goldens/tiny_golden.safetensors
  • comfy/model_base.py
  • comfy/model_detection.py
  • tests-unit/comfy_test/paint_parity/compare_reference.py
  • comfy/ldm/hunyuan3d/paint/loader.py
  • tests-unit/comfy_test/paint_parity/make_goldens.py
  • tests-unit/comfy_test/paint_parity/capture_reference.py
  • comfy/ldm/hunyuan3d/paint/CONVENTIONS.md
  • tests-unit/comfy_test/paint_parity/harness.py
  • comfy_extras/nodes_save_3d.py
  • comfy/latent_formats.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_parity.py
  • tests-unit/comfy_test/paint_parity/bundle_format.py
  • tests-unit/comfy_test/test_hunyuan3d_paint.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_render.py
  • comfy/ldm/hunyuan3d/paint/attention.py
  • comfy/ldm/hunyuan3d/paint/render.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_conventions.py
  • comfy_extras/nodes_hunyuan3d_paint.py
  • comfy/ldm/hunyuan3d/paint/unet.py
**

⚙️ CodeRabbit configuration file

**: IMPORTANT: Only comment on issues directly introduced by this PR's code changes.
Treat AGENTS.md as mandatory repository policy, not optional style guidance.
Flag PR changes that violate AGENTS.md even when the code is otherwise functional.
In particular, enforce architecture boundaries, dtype/device/memory rules,
interface contracts, import style, no unnecessary try/except blocks, no inline
imports, no outbound internet paths in core ComfyUI, and narrow scoped fixes.
Prefer direct findings over suggestions when a rule is violated. Only ignore
AGENTS.md when it clearly conflicts with a newer explicit maintainer instruction
in the PR.
Do NOT flag pre-existing issues in code that was merely moved, re-indented,
de-indented, or reformatted without logic changes. If code appears in the diff
only due to whitespace or structural reformatting (e.g., removing a with: block),
treat it as unchanged. Contributors should not feel obligated to address
pre-existing issues outside the scope of their contribution.

Files:

  • tests-unit/comfy_test/parity_report.md
  • comfy/ldm/hunyuan3d/paint/__init__.py
  • comfy_api/latest/_util/geometry_types.py
  • tests-unit/comfy_test/paint_parity/README.md
  • nodes.py
  • comfy/supported_models.py
  • tests-unit/comfy_test/paint_parity/goldens/tiny_golden.safetensors
  • comfy/model_base.py
  • comfy/model_detection.py
  • tests-unit/comfy_test/paint_parity/compare_reference.py
  • comfy/ldm/hunyuan3d/paint/loader.py
  • tests-unit/comfy_test/paint_parity/make_goldens.py
  • tests-unit/comfy_test/paint_parity/capture_reference.py
  • comfy/ldm/hunyuan3d/paint/CONVENTIONS.md
  • tests-unit/comfy_test/paint_parity/harness.py
  • comfy_extras/nodes_save_3d.py
  • comfy/latent_formats.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_parity.py
  • tests-unit/comfy_test/paint_parity/bundle_format.py
  • tests-unit/comfy_test/test_hunyuan3d_paint.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_render.py
  • comfy/ldm/hunyuan3d/paint/attention.py
  • comfy/ldm/hunyuan3d/paint/render.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_conventions.py
  • comfy_extras/nodes_hunyuan3d_paint.py
  • comfy/ldm/hunyuan3d/paint/unet.py
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Keep state and capability flags on the object that owns the behavior; use explicit parent-owned fields rather than probing children with getattr for parent control flow.
Keep public methods aligned with caller contracts; preserve arguments, parameter order, return types, side effects, and error behavior unless all affected interfaces are intentionally updated.
Do not add unused compatibility parameters, flags, attributes, constructor options, or model-specific options to shared helpers.
Normalize third-party and upstream return conventions at integration boundaries so core code receives the expected type and shape.
Avoid caller-side unwrapping such as out = out[0] unless the called interface documents that return structure.
Do not add torch.no_grad, torch.inference_mode, or inference-mode wrappers; only disable a globally enabled inference mode when a training path requires gradients.
Do not add freeze, unfreeze, or trainability toggles to ComfyUI model classes.
Remove training-only behavior such as dropout from inference models while preserving checkpoint and state-dict compatibility, using nn.Identity when necessary to retain slots.
Keep imports at module scope; use inline imports only for established optional-backend probes or import-cycle avoidance.
Use try/except only for optional dependency, platform, or backend detection with a useful fallback, and prefer specific exception types.
Do not add code for unsupported pinned library versions or obsolete PyTorch workarounds; unsupported formats, quantization metadata, and bad states should fail clearly.
Match local file style and keep comments sparse, useful, and non-obvious; remove comments that merely restate code.

Files:

  • comfy/ldm/hunyuan3d/paint/__init__.py
  • comfy_api/latest/_util/geometry_types.py
  • nodes.py
  • comfy/supported_models.py
  • comfy/model_base.py
  • comfy/model_detection.py
  • tests-unit/comfy_test/paint_parity/compare_reference.py
  • comfy/ldm/hunyuan3d/paint/loader.py
  • tests-unit/comfy_test/paint_parity/make_goldens.py
  • tests-unit/comfy_test/paint_parity/capture_reference.py
  • tests-unit/comfy_test/paint_parity/harness.py
  • comfy_extras/nodes_save_3d.py
  • comfy/latent_formats.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_parity.py
  • tests-unit/comfy_test/paint_parity/bundle_format.py
  • tests-unit/comfy_test/test_hunyuan3d_paint.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_render.py
  • comfy/ldm/hunyuan3d/paint/attention.py
  • comfy/ldm/hunyuan3d/paint/render.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_conventions.py
  • comfy_extras/nodes_hunyuan3d_paint.py
  • comfy/ldm/hunyuan3d/paint/unet.py
comfy/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

comfy/**/*.py: Treat dtype, device placement, VRAM use, offloading, and memory behavior as correctness concerns; use existing ComfyUI quantization, memory, offload, and optimized-operation helpers.
Prefer shared optimized kernels, backend dispatchers, and documented interfaces over duplicate handwritten operations; treat selected backend callables as opaque.
Do not duplicate operations with custom float32-upcasting inference kernels; use generic ComfyUI operations or native PyTorch operations.
If a model constructor has an operations parameter, assume it is never None; do not add fallback torch operations.
Avoid unnecessary parameters in model, block, and operation constructors or forwards; reuse existing model classes, blocks, operations, and helpers.
Model detectors must inspect only the first dimension of linear weights, guard every dereferenced state-dict key, and order specific signatures before broad fallbacks.
Avoid einops in core inference code; use native tensor operations such as reshape, view, permute, transpose, flatten, and related methods.
Keep metadata, counters, shape calculations, indices, split boundaries, and control-flow values as Python values rather than tensors.
Avoid unnecessary casts and transfers; preserve intended compute and storage dtypes, tensor shapes, and backend result contracts.
Keep model-native latent layout handling inside the model or latent-format owner rather than reshaping it in nodes or caller-side adapters.
DiT models must pad every patchified target or reference input with comfy.ldm.common_dit.pad_to_patch_size and crop only the target output back to its original dimensions.
Do not add defensive shape, configuration, or dtype casts that merely obscure a clear tensor-operation failure; validate only at meaningful boundaries.
Raw parameters not owned by an operation should be cast at use with comfy.ops.cast_to_input or comfy.model_management.cast_to; model constructors should not contain dtype workaro...

Files:

  • comfy/ldm/hunyuan3d/paint/__init__.py
  • comfy/supported_models.py
  • comfy/model_base.py
  • comfy/model_detection.py
  • comfy/ldm/hunyuan3d/paint/loader.py
  • comfy/latent_formats.py
  • comfy/ldm/hunyuan3d/paint/attention.py
  • comfy/ldm/hunyuan3d/paint/render.py
  • comfy/ldm/hunyuan3d/paint/unet.py
comfy/**

⚙️ CodeRabbit configuration file

comfy/**: Core ML/diffusion engine. Focus on:

  • Backward compatibility (breaking changes affect all custom nodes)
  • Memory management and GPU resource handling
  • Performance implications in hot paths
  • Thread safety for concurrent execution

Files:

  • comfy/ldm/hunyuan3d/paint/__init__.py
  • comfy/supported_models.py
  • comfy/model_base.py
  • comfy/model_detection.py
  • comfy/ldm/hunyuan3d/paint/loader.py
  • comfy/ldm/hunyuan3d/paint/CONVENTIONS.md
  • comfy/latent_formats.py
  • comfy/ldm/hunyuan3d/paint/attention.py
  • comfy/ldm/hunyuan3d/paint/render.py
  • comfy/ldm/hunyuan3d/paint/unet.py
nodes.py

⚙️ CodeRabbit configuration file

nodes.py: Core node definitions (2500+ lines). Focus on:

  • Backward compatibility of NODE_CLASS_MAPPINGS
  • Consistency of INPUT_TYPES return format

Files:

  • nodes.py
comfy_extras/**

⚙️ CodeRabbit configuration file

comfy_extras/**: Community-contributed extra nodes. Focus on:

  • Consistency with node patterns (INPUT_TYPES, RETURN_TYPES, FUNCTION, CATEGORY)
  • No breaking changes to existing node interfaces

Files:

  • comfy_extras/nodes_save_3d.py
  • comfy_extras/nodes_hunyuan3d_paint.py
🧠 Learnings (7)
📚 Learning: 2026-02-21T14:01:41.482Z
Learnt from: pythongosssss
Repo: Comfy-Org/ComfyUI PR: 12555
File: comfy_extras/nodes_glsl.py:719-724
Timestamp: 2026-02-21T14:01:41.482Z
Learning: In PyOpenGL, bare Python scalars can be accepted for 1-element array parameters by NumberHandler. This means you can pass an int/float directly to OpenGL texture deletion (e.g., glDeleteTextures(tex)) without wrapping in a list. Verify function-specific expectations and ensure types match what the OpenGL call expects; use explicit lists only when the API requires an array.

Applied to files:

  • comfy/ldm/hunyuan3d/paint/__init__.py
  • comfy_api/latest/_util/geometry_types.py
  • nodes.py
  • comfy/supported_models.py
  • comfy/model_base.py
  • comfy/model_detection.py
  • tests-unit/comfy_test/paint_parity/compare_reference.py
  • comfy/ldm/hunyuan3d/paint/loader.py
  • tests-unit/comfy_test/paint_parity/make_goldens.py
  • tests-unit/comfy_test/paint_parity/capture_reference.py
  • tests-unit/comfy_test/paint_parity/harness.py
  • comfy_extras/nodes_save_3d.py
  • comfy/latent_formats.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_parity.py
  • tests-unit/comfy_test/paint_parity/bundle_format.py
  • tests-unit/comfy_test/test_hunyuan3d_paint.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_render.py
  • comfy/ldm/hunyuan3d/paint/attention.py
  • comfy/ldm/hunyuan3d/paint/render.py
  • tests-unit/comfy_test/test_hunyuan3d_paint_conventions.py
  • comfy_extras/nodes_hunyuan3d_paint.py
  • comfy/ldm/hunyuan3d/paint/unet.py
📚 Learning: 2026-05-13T12:31:45.069Z
Learnt from: rattus128
Repo: Comfy-Org/ComfyUI PR: 13802
File: comfy/pinned_memory.py:19-30
Timestamp: 2026-05-13T12:31:45.069Z
Learning: When reviewing code that uses comfy/pinned_memory.py’s `HostBuffer.extend(size=..., reallocate=...)`: by default (`reallocate` is not True / False), `extend(size=...)` is a *relative increment* that grows the buffer by `size` bytes—so slicing like `[offset:offset+size]` after `hostbuf.extend(size=size)` is correct and the argument should not be rewritten to `offset + size`. Only in the single-segment reallocation mode (`reallocate=True`, e.g., as used by `resize_pin_buffer()` in `comfy/model_management.py`) should `size` be treated as an *absolute target* and the call/arguments should be checked accordingly.

Applied to files:

  • comfy/ldm/hunyuan3d/paint/__init__.py
  • comfy/supported_models.py
  • comfy/model_base.py
  • comfy/model_detection.py
  • comfy/ldm/hunyuan3d/paint/loader.py
  • comfy/latent_formats.py
  • comfy/ldm/hunyuan3d/paint/attention.py
  • comfy/ldm/hunyuan3d/paint/render.py
  • comfy/ldm/hunyuan3d/paint/unet.py
📚 Learning: 2026-05-04T18:30:37.579Z
Learnt from: Talmaj
Repo: Comfy-Org/ComfyUI PR: 13655
File: comfy/model_detection.py:907-917
Timestamp: 2026-05-04T18:30:37.579Z
Learning: In ComfyUI’s internal supported model implementations (comfy/supported_models_base.py and comfy/supported_models/*.py), ensure model classes do not override matches() in their own class bodies. All supported models should use BASE.matches() for backward compatibility; if a future change introduces a matches() override in a subclass, treat it as a backward-compatibility risk and require additional review/testing to confirm behavior remains consistent with BASE.matches().

Applied to files:

  • comfy/supported_models.py
📚 Learning: 2026-03-04T14:05:31.426Z
Learnt from: jtydhr88
Repo: Comfy-Org/ComfyUI PR: 12757
File: comfy_extras/nodes_custom_sampler.py:1069-1089
Timestamp: 2026-03-04T14:05:31.426Z
Learning: In the ComfyUI sampling pipeline, treat percent_to_sigma(0.0) as a sentinel value (999999999.9) that means starting from pure noise. This is consistent with BasicScheduler via calculate_sigmas. The SamplingPercentToSigma node’s return_actual_sigma flag differentiates this sentinel from sigma_max. Reviewers should not flag CurveToSigmas or similar nodes that rely on percent_to_sigma as bugs; downstream samplers are expected to handle the sentinel correctly. When reviewing related sampling-related code, assume this sentinel semantics unless there is explicit handling for a real sigma_max.

Applied to files:

  • comfy_extras/nodes_save_3d.py
  • comfy_extras/nodes_hunyuan3d_paint.py
📚 Learning: 2026-04-04T13:29:15.653Z
Learnt from: kijai
Repo: Comfy-Org/ComfyUI PR: 13258
File: comfy_extras/nodes_frame_interpolation.py:151-189
Timestamp: 2026-04-04T13:29:15.653Z
Learning: In this ComfyUI codebase, node `execute()` inference is already run under a global `torch.inference_mode()` context established in the execution engine (e.g., `execution.py` around line ~732). During review, avoid recommending changes that wrap node inference loops in `torch.inference_mode()`—it is already applied, so such suggestions are likely redundant.

Applied to files:

  • comfy_extras/nodes_save_3d.py
  • comfy_extras/nodes_hunyuan3d_paint.py
📚 Learning: 2026-05-09T18:40:40.199Z
Learnt from: kijai
Repo: Comfy-Org/ComfyUI PR: 13813
File: comfy_extras/nodes_wandancer.py:868-872
Timestamp: 2026-05-09T18:40:40.199Z
Learning: When building video/temporal decoding nodes that call ComfyUI’s VAE.decode (comfy/sd.py), leverage VAE.decode’s existing VRAM-aware chunking along dim 0. Reshape or transpose the latent so the temporal dimension T is folded into dim 0 (e.g., transform a latent of shape [B, T, C, H, W] into [B*T, C, H, W] before calling vae.decode). This lets VAE.decode do chunked decoding without needing an explicit per-frame loop inside the node itself.

Applied to files:

  • comfy_extras/nodes_save_3d.py
  • comfy_extras/nodes_hunyuan3d_paint.py
📚 Learning: 2026-05-20T00:10:14.673Z
Learnt from: Pauan
Repo: Comfy-Org/ComfyUI PR: 13997
File: comfy_extras/nodes_string.py:12-25
Timestamp: 2026-05-20T00:10:14.673Z
Learning: In the ComfyUI `comfy_extras/` codebase, some nodes intentionally ship with a default input string that references parameters that may not yet be connected. If the default would raise a `KeyError` (e.g., examples like `MathExpression` default `a + b`, or `StringFormat` default `{a}` with `min=0` and autogrow inputs), treat it as an intentional “hint default” UX pattern, not a bug. During review, do not flag this behavior or recommend changing `min` to `1` or altering the default to an empty string solely to avoid the `KeyError`.

Applied to files:

  • comfy_extras/nodes_save_3d.py
  • comfy_extras/nodes_hunyuan3d_paint.py
🪛 ast-grep (0.44.1)
tests-unit/comfy_test/paint_parity/compare_reference.py

[warning] 64-64: File path is request-/variable-derived; validate and normalize to prevent path traversal.
Context: open(args.out, "w", encoding="utf-8")
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(open-filename-from-request)

tests-unit/comfy_test/paint_parity/capture_reference.py

[warning] 66-66: File path is request-/variable-derived; validate and normalize to prevent path traversal.
Context: open(path, "r", encoding="utf-8")
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(open-filename-from-request)


[warning] 94-94: File path is request-/variable-derived; validate and normalize to prevent path traversal.
Context: open(os.path.join(args.unet_dir, "config.json"), "r", encoding="utf-8")
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(open-filename-from-request)

tests-unit/comfy_test/paint_parity/bundle_format.py

[info] 67-67: use jsonify instead of json.dumps for JSON output
Context: json.dumps(v)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

tests-unit/comfy_test/test_hunyuan3d_paint_render.py

[warning] 385-385: File path is request-/variable-derived; validate and normalize to prevent path traversal.
Context: open(path, "rb")
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(open-filename-from-request)


[warning] 529-529: File path is request-/variable-derived; validate and normalize to prevent path traversal.
Context: open(path, "rb")
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(open-filename-from-request)


[warning] 617-617: File path is request-/variable-derived; validate and normalize to prevent path traversal.
Context: open(path, "rb")
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(open-filename-from-request)

🔇 Additional comments (47)
comfy/ldm/hunyuan3d/paint/render.py (7)

41-100: LGTM!


107-149: LGTM!


155-178: LGTM!


311-386: LGTM!


392-427: LGTM!


433-534: LGTM!


537-598: LGTM!

comfy_extras/nodes_hunyuan3d_paint.py (5)

31-56: LGTM!


100-124: LGTM!


165-225: LGTM!


250-294: LGTM!


59-68: 🎯 Functional Correctness

No change needed

The 330 cutover matches the reference cam_mapping implementation rather than being a transcription error from a 270 boundary.

			> Likely an incorrect or invalid review comment.
nodes.py (1)

2450-2450: LGTM!

comfy_api/latest/_util/geometry_types.py (1)

48-50: LGTM!

comfy_extras/nodes_save_3d.py (2)

80-81: LGTM!

Also applies to: 93-94, 129-140, 151-159, 169-169


286-290: LGTM!

Also applies to: 413-433

comfy/ldm/hunyuan3d/paint/attention.py (1)

20-55: LGTM!

Also applies to: 58-84, 90-131, 134-258, 265-311

comfy/ldm/hunyuan3d/paint/unet.py (1)

22-131: LGTM!

Also applies to: 134-258, 261-300, 303-423, 429-521, 524-563, 569-658, 660-741

comfy/latent_formats.py (1)

778-788: LGTM!

comfy/ldm/hunyuan3d/paint/loader.py (1)

13-96: LGTM!

Also applies to: 99-121, 124-157

comfy/model_base.py (1)

50-50: LGTM!

Also applies to: 2066-2094

comfy/model_detection.py (2)

2-2: LGTM!

Also applies to: 727-732


894-900: LGTM!

comfy/supported_models.py (2)

1557-1589: LGTM!

Also applies to: 2477-2477


30-30: LGTM!

Also applies to: 1920-1948, 2488-2488

comfy/ldm/hunyuan3d/paint/__init__.py (1)

1-4: LGTM!

tests-unit/comfy_test/test_hunyuan3d_paint.py (9)

1-36: LGTM!


55-82: LGTM!


85-148: LGTM!


151-179: LGTM!


182-224: LGTM!


227-297: LGTM!


300-340: LGTM!


343-374: LGTM!


377-445: LGTM!

tests-unit/comfy_test/test_hunyuan3d_paint_render.py (1)

36-83: LGTM!

Also applies to: 94-108, 114-135, 159-245, 251-291, 297-379, 385-442, 448-624

tests-unit/comfy_test/test_hunyuan3d_paint_conventions.py (1)

55-132: LGTM!

Also applies to: 142-176, 182-304, 306-368

comfy/ldm/hunyuan3d/paint/CONVENTIONS.md (1)

1-104: LGTM!

tests-unit/comfy_test/paint_parity/README.md (1)

1-57: LGTM!

tests-unit/comfy_test/paint_parity/bundle_format.py (1)

33-62: LGTM!

Also applies to: 65-116

tests-unit/comfy_test/paint_parity/capture_reference.py (1)

36-120: LGTM!

tests-unit/comfy_test/paint_parity/compare_reference.py (1)

39-72: LGTM!

tests-unit/comfy_test/paint_parity/goldens/tiny_golden.safetensors (1)

1-1: LGTM!

tests-unit/comfy_test/paint_parity/harness.py (1)

19-49: LGTM!

Also applies to: 52-107, 110-124

tests-unit/comfy_test/paint_parity/make_goldens.py (1)

10-33: LGTM!

tests-unit/comfy_test/parity_report.md (1)

6-16: 📐 Maintainability & Code Quality | 💤 Low value

act/unet.conv_in/conv_out deltas don't line up with output/noise_pred.

output/noise_pred is conv_out's tensor in a different layout, yet its max abs diff (3.278e-06) is two orders of magnitude smaller than act/unet.conv_out (4.888e-04). That's only explainable if the hook captured a different invocation on one side (e.g. a reference/ref-latent pass firing the same module twice, with the last call winning). Worth a one-line note in the report so the per-block rows aren't read as the port's error budget.

tests-unit/comfy_test/test_hunyuan3d_paint_parity.py (1)

31-67: LGTM!

Comment thread comfy_api/latest/_util/geometry_types.py Outdated
Comment thread comfy_extras/nodes_hunyuan3d_paint.py Outdated
Comment thread comfy_extras/nodes_hunyuan3d_paint.py Outdated
Comment thread comfy_extras/nodes_save_3d.py Outdated
Comment thread comfy/ldm/hunyuan3d/paint/render.py
Comment thread comfy/ldm/hunyuan3d/paint/unet.py Outdated
Comment thread comfy/model_base.py Outdated
Comment thread tests-unit/comfy_test/paint_parity/capture_reference.py Outdated
Comment thread tests-unit/comfy_test/paint_parity/compare_reference.py
Comment thread tests-unit/comfy_test/test_hunyuan3d_paint.py
jethac and others added 14 commits August 30, 2026 04:48
MESH is public comfy_api surface that custom nodes construct directly, so
adding texture_mr before vertex_counts silently rebound every following
positional argument: an eight-positional caller landed vertex_counts in
texture_mr and unlit in face_counts, which slips past the paired-counts
assert and hands SaveGLB a count tensor to treat as a texture.

All in-tree callers already pass these by keyword, so moving the new
optional parameter to the end restores the previous positional contract
at no cost.
The MR buffer was concatenated into the BIN chunk unconditionally, but the
bufferView, image and texture that reference it are only emitted alongside
baseColor. A mesh carrying texture_mr with no texture therefore shipped a
padded PNG that nothing points at, counted in the buffer byteLength and
unreachable to any viewer.

glTF hangs metallicRoughness off the same material as baseColor, so there
is no meaningful MR-only material to emit here; not encoding it is the
honest outcome.
…guidance

Returning conds_out unchanged when the latent is not 5D, or when its view
axis is not a multiple of the camera count, quietly downgraded per-view
guidance to plain scalar CFG. The sampler still produced an image, just a
subtly wrong one, with nothing in the log to say so.
_init_weights seeded each parameter from hash(name), but str hashing is
salted per process unless PYTHONHASHSEED is pinned, so the "seeded" init
drew different weights on every run. The tests that assert finite numerics
through the deep net therefore had run-dependent inputs, and any failure
would have been unreproducible. The loop already sorts the parameters, so
its index is a stable seed source.

Also drop the now-dead `if cpu_patch` branch left by making the device-move
patch unconditional, and hoist the safetensors import in compare_reference,
which is a hard dependency there rather than an optional backend.
learned_text_clip_* and learned_text_clip_ref are always supplied by the
checkpoint - the loader rejects a file missing any diffusion_model key - so
zero-filling them only costs an initialisation pass over weights that are
about to be overwritten.
chunk_id is derived from a cumulative sum, so it is non-decreasing and each
chunk is already a contiguous range of faces. Testing chunk_id == c per chunk
walked all Fn faces n_chunks times; at the documented 1M-face envelope that
boundary search alone cost ~685 ms, against ~0.4 ms for one searchsorted.

Output is unchanged: face_id and barycentrics are bit-identical to the
previous implementation, and stay bit-identical across chunk_area 256, 4096
and 4M on a mesh mixing tiny triangles with a frame-spanning one.

Also soften the memory note above MAX_RESOLUTION. The chunk budget is applied
at face boundaries, so it bounds a typical mesh but not a single very large or
degenerate triangle, whose bounding box is still expanded in one go.
Rasterization and UV interpolation depend only on the geometry and cameras,
which both bakes share, so baking the two maps separately repeated the
expensive half of the work. bake_multiview is already generic in channel
count, so stacking the two three-channel view sets and splitting the result
needs no change to the baker itself.

The accumulators are per-channel, so this is exact rather than an
approximation: both output textures are bit-identical to the two-pass
result. The returned mask is derived from the geometric weight accumulator
alone, which is why the two passes were already producing the same mask.
Measured 1.94x on a 6-view 512px bake, at identical peak accumulator size -
the two-pass version had to hold the first baked texture while baking the
second.
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- material self-attention consumed a (B,V,M,...) interleaved layout and its
  output stack was reshaped as if material-major, scrambling views/materials
- reference attention packed concatenated value channels head-mixed instead of
  the trained head-first M*dim_head slices
- learned_text_clip_ref was used raw in compute_reference_bank, breaking on
  offloaded weights; cast at use with comfy.ops.cast_to_input

Tiny Tier-1 golden regenerated. Tier-2 vs real hunyuan3d-paintpbr-v2-1
weights now passes (noise_pred max abs diff 8.7e-06).

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Clean-room rewrite of Hunyuan3D 2.1 paint tainted surfaces
@GiusTex

GiusTex commented Sep 5, 2026 •

Copy link
Copy Markdown

I tested your commit, @jethac, it seems to work (I could have tried to get a better output, I suppose, but it was late and I just wanted to check if I understood where to take the models, how to convert them and then if they worked).

Input and output:

image image

Workflow overview (same as the link above, with added colors for me):

image

Edit:

No errors in console (I just wanted to make this known).

Console output
[INFO] got prompt
[INFO] Model Hunyuan3Dv2_1 prepared for dynamic VRAM loading. 5818MB Staged. 0 patches attached. Force pre-loaded 238 weights: 812 KB.
100%|██████████████████████████████████████████████████████████████████████████████████| 30/30 [00:53<00:00,  1.79s/it]
[INFO] Model ShapeVAE prepared for dynamic VRAM loading. 624MB Staged. 0 patches attached. Force pre-loaded 220 weights: 351 KB.
Volume Decoding: 100%|█████████████████████████████████████████████████████████████| 2122/2122 [00:37<00:00, 56.62it/s]
[INFO] model weight dtype torch.float16, manual cast: None
[INFO] model_type V_PREDICTION
[INFO] Requested to load AutoencoderKL
[INFO] Model AutoencoderKL prepared for dynamic VRAM loading. 159MB Staged. 0 patches attached. Force pre-loaded 112 weights: 91 KB.
[INFO] Model AutoencoderKL prepared for dynamic VRAM loading. 159MB Staged. 0 patches attached. Force pre-loaded 112 weights: 91 KB.
[INFO] Model AutoencoderKL prepared for dynamic VRAM loading. 159MB Staged. 0 patches attached. Force pre-loaded 112 weights: 91 KB.
[INFO] Requested to load Hunyuan3DPaint
[INFO] Model Hunyuan3DPaint prepared for dynamic VRAM loading. 3741MB Staged. 0 patches attached. Force pre-loaded 438 weights: 794 KB.
[INFO] Requested to load Hunyuan3DPaint
[INFO] 0 models unloaded.
[INFO] Model Hunyuan3DPaint prepared for dynamic VRAM loading. 3741MB Staged. 0 patches attached. Force pre-loaded 438 weights: 794 KB.
100%|██████████████████████████████████████████████████████████████████████████████████| 20/20 [00:44<00:00,  2.25s/it]
[INFO] Model AutoencoderKL prepared for dynamic VRAM loading. 159MB Staged. 0 patches attached. Force pre-loaded 112 weights: 91 KB.
[INFO] Model AutoencoderKL prepared for dynamic VRAM loading. 159MB Staged. 0 patches attached. Force pre-loaded 112 weights: 91 KB.
[INFO] Prompt executed in 212.42 seconds

Edit 2, other info:

[INFO] pytorch version: 2.11.0+cu130
[INFO] Set vram state to: NORMAL_VRAM
[INFO] Device: cuda:0 NVIDIA GeForce RTX 3060 : cudaMallocAsync
[INFO] Using pytorch attention
[INFO] aimdo: src-win/cuda-detour.c:38:INFO:aimdo_setup_hooks: installing 6 hooks
[INFO] aimdo: src/control.c:262:INFO:comfy-aimdo NVML pressure enabled
[INFO] aimdo: src-win/shmem-detect.c:80:INFO:comfy-aimdo WDDM adapter match: NVIDIA GeForce RTX 3060 runtime_luid=00000000:000131b1 dxgi_luid=00000000:000131b1
[INFO] aimdo: src/control.c:277:INFO:comfy-aimdo inited for GPU: NVIDIA GeForce RTX 3060 (VRAM: 12287 MB)
[INFO] DynamicVRAM support detected and enabled
[INFO] Python version: 3.12.13 | packaged by Anaconda, Inc. | (main, Mar 19 2026, 20:16:45) [MSC v.1942 64 bit (AMD64)]
[INFO] ComfyUI version: 0.30.0
[INFO] comfyui-frontend-package version: 1.51.9
[INFO] comfyui-workflow-templates version: 0.11.55
[INFO] comfyui-embedded-docs version: 0.5.10
[INFO] comfy-kitchen version: 0.2.31
[INFO] comfy-aimdo version: 0.5.2

Thanks for the contribution! ❤️🚀

@jethac

jethac commented Sep 5, 2026

Copy link
Copy Markdown
Author

Thanks for taking a look! I love your choice of model 😄

jethac commented Sep 6, 2026

Copy link
Copy Markdown
Author

The existing PR now carries the specification-only native rewrite at 2d1c6623 (runtime c588e42b), replacing the older implementation while retaining it only as ancestry. The rewrite was produced without access to Tencent's source or the prior implementation. Current validation: 75 focused tests passed, Ruff passed, and a real-weight RTX 5060 Ti run produced a valid two-texture PBR GLB; details and limitations are in the updated description. The optional DINO path was omitted from the tested run. Please re-review this replacement; CI and maintainer merge decisions remain pending.

@GiusTex

GiusTex commented Sep 23, 2026

Copy link
Copy Markdown

@jethac, would you consider making an extension with the same code, to use in the meantime until this pr gets merged?

@jethac

jethac commented Sep 30, 2026

Copy link
Copy Markdown
Author

@GiusTex sounds like a good idea, i'll do it!

@GiusTex

GiusTex commented Sep 30, 2026 •

Copy link
Copy Markdown

Thanks!

@alexisrolland

Copy link
Copy Markdown
Member

@jethac @GiusTex I am curious why you would want to use this model while Pixal3D is much better?

@GiusTex

GiusTex commented Oct 1, 2026

Copy link
Copy Markdown

I tried Pixal3d but for some reason I get a messed up shape, which then produces a messed up refined shape and messed up texture; I saw that hunyuan 2.1 doesn't produce detailed views, but in another extension it was used, so it was a bit for completeness.
If you don't want to turn the code in an extension it's fine.
I'm now trying to convert that extension's "trellis2 multiview shape generator" to comfyui (I'm mostly there, I need to fix some merged finger etc, some conditioning bridge issue maybe) to use comfyui lighter and quicker models, and hoping to get a good shape and refined shape, as the one I got from the extension.
As of now the shape I get from my bridge node (using pure trellis2) is already better than comfyui pixal3d (as I said, I don't know why, the views are the same), so I'll continue this way

@alexisrolland

Copy link
Copy Markdown
Member

I tried Pixal3d but for some reason I get a messed up shape, which then produces a messed up refined shape and messed up texture; I saw that hunyuan 2.1 doesn't produce detailed views, but in another extension it was used, so it was a bit for completeness. If you don't want to turn the code in an extension it's fine. I'm now trying to convert that extension's "trellis2 multiview shape generator" to comfyui (I'm mostly there, I need to fix some merged finger etc, some conditioning bridge issue maybe) to use comfyui lighter and quicker models, and hoping to get a good shape and refined shape, as the one I got from the extension. As of now the shape I get from my bridge node (using pure trellis2) is already better than comfyui pixal3d (as I said, I don't know why, the views are the same), so I'll continue this way

Interesting, I would be curious to see what results you get to see how better they are and where we would need to improve. Is there anything you could share please?

@GiusTex

GiusTex commented Oct 3, 2026 •

Copy link
Copy Markdown

Sure, I'll upload code and workflow today when I get to the computer. I want also to clarify all I did (together with Claude) was just a bridge between comfyorg trellis2 models and visualbruno trellis2 multiview custom samplers; they don't work with pixal3d (they don't pass the proj_pack) since it's already implemented by comfyui

Edit:
The bridge nodes accept only multiview since, again, trellis2 single view is already implemented by comfyui

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants