Files
Ethanfel 16f4e93a3a Initial commit: UTFCN — Use The (F***ing) Core Nodes
A ComfyUI companion that suggests core / available equivalents for custom
nodes and replaces them in a workflow.

- Backend (utfcn_core.py, __init__.py): read-only /utfcn/scan analysis that
  ranks equivalents in three tiers (curated → exact-signature → partial
  heuristic) from the live node registry.
- Frontend (web/utfcn.js): on-add mode (Off / Suggest / Force auto-replace),
  bulk "Replace with core / available…" command + Extensions menu with a
  preview-then-confirm dialog, and a right-click single-node replace. The swap
  engine only rewires losslessly.
- mappings.json: 7 hand-verified curated rules mined from installed packs
  (essentials, KJNodes, WAS); user_mappings.json for user overrides.
- Docs + branding: README, icon and social banner (SVG + PNG), GPL-3.0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 10:26:30 +02:00

85 lines
2.9 KiB
JSON

{
"_readme": [
"UTFCN curated equivalence rules (the 'verified' tier — safe to auto-apply, incl. Force mode).",
"",
"You rarely NEED rules: UTFCN already auto-detects any custom node whose input",
"name->type map and ordered output types are IDENTICAL to a core node ('exact'",
"tier), and surfaces looser 'partial' matches as suggestions. Add a rule here",
"only to (a) bless a partial match as safe to auto-apply, or (b) fix up slots",
"whose NAMES differ so the swap stays lossless.",
"",
"Schema — 'rules' maps a source node type to ONE target or an ordered list of",
"targets (first installed one wins, so put the core node first):",
"",
" \"rules\": {",
" \"SourceNodeType\": [",
" {",
" \"to\": \"TargetNodeType\",",
" \"note\": \"why this is equivalent (shown in the preview)\",",
" \"inputs\": { \"srcInputName\": \"dstInputName\" },",
" \"widgets\": { \"srcWidgetName\": \"dstWidgetName\" },",
" \"outputs\": { \"srcOutputName\": \"dstOutputName\" }",
" }",
" ]",
" }",
"",
"Any input/widget/output slot you don't list is matched by identical name, then",
"by type+order. Don't edit this file for your own rules — put those in",
"user_mappings.json (same schema); it is merged on top and survives updates.",
"",
"The rules below were mined from installed packs (ComfyUI_essentials, KJNodes,",
"was-node-suite) and verified lossless against the real core signatures. Rules",
"for nodes you don't have installed are simply ignored."
],
"rules": {
"GetImageSize+": [
{
"to": "GetImageSize",
"note": "essentials Get Image Size == core Get Image Size; 'count' is core's 'batch_size'.",
"outputs": { "count": "batch_size" }
}
],
"MaskPreview+": [
{
"to": "MaskPreview",
"note": "essentials mask preview == core MaskPreview (same single-MASK preview node)."
}
],
"BOOLConstant": [
{
"to": "PrimitiveBoolean",
"note": "KJ boolean constant == core Primitive Boolean (single BOOLEAN passthrough)."
}
],
"INTConstant": [
{
"to": "PrimitiveInt",
"note": "KJ int constant == core Primitive Int. Core adds a (fixed) control_after_generate; value is identical."
}
],
"FloatConstant": [
{
"to": "PrimitiveFloat",
"note": "KJ float constant == core Primitive Float. KJ rounds to 6 decimals; negligible for a UI constant."
}
],
"Convert Masks to Images": [
{
"to": "MaskToImage",
"note": "WAS mask->image == core MaskToImage (broadcast MASK to a 3-channel IMAGE).",
"inputs": { "masks": "mask" }
}
],
"Mask Invert": [
{
"to": "InvertMask",
"note": "WAS mask invert == core InvertMask (1.0 - mask).",
"inputs": { "masks": "mask" }
}
]
}
}