procfunc 0.33.0__tar.gz → 0.33.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. {procfunc-0.33.0/src/procfunc.egg-info → procfunc-0.33.2}/PKG-INFO +2 -2
  2. {procfunc-0.33.0 → procfunc-0.33.2}/README.md +1 -1
  3. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/__init__.py +1 -1
  4. procfunc-0.33.2/src/procfunc/cli/__init__.py +3 -0
  5. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/color.py +4 -0
  6. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/compute_graph/util.py +96 -14
  7. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/nodes/color.py +4 -4
  8. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/nodes/func.py +21 -2
  9. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/nodes/geo.py +6 -4
  10. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/nodes/math.py +70 -2
  11. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/nodes/texture.py +11 -1
  12. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/ops/attr.py +6 -3
  13. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/transforms/extract_materials.py +38 -16
  14. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/transpiler/bpy_to_computegraph.py +18 -8
  15. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/transpiler/parse_special_cases.py +13 -0
  16. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/util/bpy_info.py +19 -15
  17. {procfunc-0.33.0 → procfunc-0.33.2/src/procfunc.egg-info}/PKG-INFO +2 -2
  18. {procfunc-0.33.0 → procfunc-0.33.2}/tests/test_ops.py +28 -0
  19. procfunc-0.33.0/src/procfunc/cli/__init__.py +0 -3
  20. {procfunc-0.33.0 → procfunc-0.33.2}/LICENSE.md +0 -0
  21. {procfunc-0.33.0 → procfunc-0.33.2}/pyproject.toml +0 -0
  22. {procfunc-0.33.0 → procfunc-0.33.2}/setup.cfg +0 -0
  23. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/cli/main.py +0 -0
  24. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/codegen/__init__.py +0 -0
  25. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/codegen/codegen.py +0 -0
  26. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/codegen/identifiers.py +0 -0
  27. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/codegen/repr.py +0 -0
  28. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/compute_graph/__init__.py +0 -0
  29. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/compute_graph/compute_graph.py +0 -0
  30. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/compute_graph/node.py +0 -0
  31. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/compute_graph/operators_info.py +0 -0
  32. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/compute_graph/proxy.py +0 -0
  33. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/context.py +0 -0
  34. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/control/__init__.py +0 -0
  35. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/nodes/__init__.py +0 -0
  36. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/nodes/compositor.py +0 -0
  37. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/nodes/execute/construct_nodes.py +0 -0
  38. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/nodes/execute/construct_operator.py +0 -0
  39. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/nodes/execute/construct_special_cases.py +0 -0
  40. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/nodes/execute/construct_standard.py +0 -0
  41. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/nodes/execute/execute.py +0 -0
  42. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/nodes/execute/infer_runtime_data_type.py +0 -0
  43. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/nodes/execute/realize.py +0 -0
  44. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/nodes/execute/util.py +0 -0
  45. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/nodes/manifest.json +0 -0
  46. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/nodes/shader.py +0 -0
  47. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/nodes/types.py +0 -0
  48. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/nodes/util/__init__.py +0 -0
  49. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/nodes/util/bindings_util.py +0 -0
  50. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/nodes/util/bpy_node_info.py +0 -0
  51. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/nodes/util/node_function.py +0 -0
  52. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/ops/__init__.py +0 -0
  53. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/ops/_util.py +0 -0
  54. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/ops/addons.py +0 -0
  55. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/ops/collection.py +0 -0
  56. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/ops/curve.py +0 -0
  57. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/ops/file.py +0 -0
  58. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/ops/manifest.json +0 -0
  59. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/ops/mesh.py +0 -0
  60. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/ops/modifier.py +0 -0
  61. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/ops/object.py +0 -0
  62. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/ops/primitives/__init__.py +0 -0
  63. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/ops/primitives/camera.py +0 -0
  64. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/ops/primitives/curve.py +0 -0
  65. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/ops/primitives/light.py +0 -0
  66. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/ops/primitives/mesh.py +0 -0
  67. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/ops/uv.py +0 -0
  68. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/random.py +0 -0
  69. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/tracer/__init__.py +0 -0
  70. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/tracer/decorator.py +0 -0
  71. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/tracer/patch.py +0 -0
  72. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/tracer/proxy.py +0 -0
  73. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/tracer/trace.py +0 -0
  74. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/transforms/__init__.py +0 -0
  75. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/transforms/cleanup.py +0 -0
  76. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/transforms/convert.py +0 -0
  77. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/transforms/distribution.py +0 -0
  78. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/transforms/infer_distribution.py +0 -0
  79. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/transforms/parameters.py +0 -0
  80. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/transforms/util.py +0 -0
  81. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/transpiler/__init__.py +0 -0
  82. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/transpiler/main.py +0 -0
  83. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/transpiler/parse_default_values.py +0 -0
  84. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/types.py +0 -0
  85. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/util/__init__.py +0 -0
  86. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/util/bpy_data.py +0 -0
  87. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/util/camera.py +0 -0
  88. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/util/keyframe.py +0 -0
  89. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/util/log.py +0 -0
  90. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/util/manifest.py +0 -0
  91. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/util/pytree.py +0 -0
  92. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc/util/teardown.py +0 -0
  93. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc.egg-info/SOURCES.txt +0 -0
  94. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc.egg-info/dependency_links.txt +0 -0
  95. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc.egg-info/entry_points.txt +0 -0
  96. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc.egg-info/requires.txt +0 -0
  97. {procfunc-0.33.0 → procfunc-0.33.2}/src/procfunc.egg-info/top_level.txt +0 -0
  98. {procfunc-0.33.0 → procfunc-0.33.2}/tests/test_asset.py +0 -0
  99. {procfunc-0.33.0 → procfunc-0.33.2}/tests/test_bpy_data_cleanup.py +0 -0
  100. {procfunc-0.33.0 → procfunc-0.33.2}/tests/test_cli_transpile.py +0 -0
  101. {procfunc-0.33.0 → procfunc-0.33.2}/tests/test_codegen.py +0 -0
  102. {procfunc-0.33.0 → procfunc-0.33.2}/tests/test_codegen_matrix.py +0 -0
  103. {procfunc-0.33.0 → procfunc-0.33.2}/tests/test_compute_graph.py +0 -0
  104. {procfunc-0.33.0 → procfunc-0.33.2}/tests/test_node_function.py +0 -0
  105. {procfunc-0.33.0 → procfunc-0.33.2}/tests/test_pytree.py +0 -0
  106. {procfunc-0.33.0 → procfunc-0.33.2}/tests/test_random.py +0 -0
  107. {procfunc-0.33.0 → procfunc-0.33.2}/tests/test_trace.py +0 -0
  108. {procfunc-0.33.0 → procfunc-0.33.2}/tests/test_transforms.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: procfunc
3
- Version: 0.33.0
3
+ Version: 0.33.2
4
4
  Summary: Function-Oriented Abstractions for Procedural 3D Generation in Python
5
5
  License-Expression: BSD-3-Clause
6
6
  Project-URL: Homepage, https://github.com/princeton-vl/procfunc
@@ -24,7 +24,7 @@ Dynamic: license-file
24
24
 
25
25
  # ProcFunc: Function-Oriented Abstractions for Procedural 3D Generation in Python
26
26
 
27
- [**Documentation**](#documentation)
27
+ [**Documentation**](https://procfunc.readthedocs.io)
28
28
  | [**Research Paper**](https://arxiv.org/abs/2604.26943)
29
29
  | [**Transpiling**](#transpile-a-blender-file-to-procfunc-code)
30
30
  | [**Experiments**](#experiments)
@@ -1,6 +1,6 @@
1
1
  # ProcFunc: Function-Oriented Abstractions for Procedural 3D Generation in Python
2
2
 
3
- [**Documentation**](#documentation)
3
+ [**Documentation**](https://procfunc.readthedocs.io)
4
4
  | [**Research Paper**](https://arxiv.org/abs/2604.26943)
5
5
  | [**Transpiling**](#transpile-a-blender-file-to-procfunc-code)
6
6
  | [**Experiments**](#experiments)
@@ -2,7 +2,7 @@
2
2
  # ensure this gets imported first so that mathutils etc is available even if later modules dont import bpy
3
3
  import bpy
4
4
 
5
- __version__ = "0.33.0"
5
+ __version__ = "0.33.2"
6
6
 
7
7
  from numpy.random import Generator as RNG
8
8
 
@@ -0,0 +1,3 @@
1
+ from procfunc.cli.main import cli, get_parser
2
+
3
+ __all__ = ["cli", "get_parser"]
@@ -10,6 +10,8 @@ def hsv_color(
10
10
  saturation: float | None = None,
11
11
  value: float | None = None,
12
12
  ) -> t.Color:
13
+ if hsv is None and (hue is None or saturation is None or value is None):
14
+ raise ValueError("provide hsv=... or all of hue/saturation/value")
13
15
  color = t.Color()
14
16
  if hsv is not None:
15
17
  color.hsv = hsv
@@ -27,6 +29,8 @@ def rgb_color(
27
29
  b: float | None = None,
28
30
  rgb: np.ndarray | None = None,
29
31
  ) -> t.Color:
32
+ if rgb is None and (r is None or g is None or b is None):
33
+ raise ValueError("provide rgb=... or all of r/g/b")
30
34
  color = t.Color()
31
35
  if rgb is not None:
32
36
  color.r, color.g, color.b = rgb
@@ -3,10 +3,21 @@ import logging
3
3
  from collections import defaultdict, deque
4
4
  from typing import Any, Callable, Generator, Literal, TypeVar
5
5
 
6
+ import numpy as np
7
+
6
8
  from procfunc.util import pytree
7
9
 
8
10
  from .compute_graph import ComputeGraph
9
- from .node import Node, SubgraphCallNode
11
+ from .node import (
12
+ ConstantNode,
13
+ FunctionCallNode,
14
+ GetAttributeNode,
15
+ InputPlaceholderNode,
16
+ MethodCallNode,
17
+ Node,
18
+ ProceduralNode,
19
+ SubgraphCallNode,
20
+ )
10
21
 
11
22
  logger = logging.getLogger(__name__)
12
23
 
@@ -40,6 +51,7 @@ def traverse_breadth_first(
40
51
 
41
52
  visited = set()
42
53
  frontier = deque((None, name, node) for name, node in graph.outputs.items())
54
+ visited.update(id(node) for _, _, node in frontier)
43
55
  # logger.debug(f"{traverse_breadth_first.__name__} {graph.name} {len(frontier)=}")
44
56
 
45
57
  def res(parent, name, child):
@@ -61,10 +73,6 @@ def traverse_breadth_first(
61
73
  if not isinstance(node, Node):
62
74
  continue
63
75
 
64
- if id(node) in visited:
65
- continue
66
- visited.add(id(node))
67
-
68
76
  yield res(parent, name, node)
69
77
 
70
78
  children = list(pytree.PyTree(node.args).items()) + list(
@@ -75,6 +83,7 @@ def traverse_breadth_first(
75
83
  continue
76
84
  if id(arg) in visited:
77
85
  continue
86
+ visited.add(id(arg))
78
87
  frontier.append((node, key, arg))
79
88
 
80
89
 
@@ -201,22 +210,95 @@ def usages_per_node(
201
210
  return dict(usages)
202
211
 
203
212
 
204
- def graph_nodes_equal(graph1: ComputeGraph, graph2: ComputeGraph) -> bool:
205
- nodes1 = list(traverse_depth_first(graph1))
206
- nodes2 = list(traverse_depth_first(graph2))
207
- if len(nodes1) != len(nodes2):
213
+ def _value_equal(a: Any, b: Any) -> bool:
214
+ """Array-safe equality for non-node values (constants, attrs, defaults)."""
215
+ if a is b:
216
+ return True
217
+ if isinstance(a, np.ndarray) or isinstance(b, np.ndarray):
218
+ return np.array_equal(a, b)
219
+ if isinstance(a, dict) and isinstance(b, dict):
220
+ return a.keys() == b.keys() and all(_value_equal(a[k], b[k]) for k in a)
221
+ if isinstance(a, (list, tuple)) and isinstance(b, (list, tuple)):
222
+ return (
223
+ type(a) is type(b)
224
+ and len(a) == len(b)
225
+ and all(_value_equal(x, y) for x, y in zip(a, b))
226
+ )
227
+ try:
228
+ return bool(a == b)
229
+ except (ValueError, TypeError):
230
+ return False
231
+
232
+
233
+ def _args_equal(a: Any, b: Any, memo: dict[tuple[int, int], bool]) -> bool:
234
+ """Structural equality of an args/kwargs tree: same container shape, with
235
+ node-valued leaves compared recursively and other leaves by value."""
236
+ tree_a = pytree.PyTree(a)
237
+ tree_b = pytree.PyTree(b)
238
+ if tree_a.spec != tree_b.spec:
208
239
  return False
209
- for node1, node2 in zip(nodes1, nodes2):
210
- if type(node1) is not type(node2):
240
+ for leaf_a, leaf_b in zip(tree_a.values(), tree_b.values()):
241
+ a_is_node = isinstance(leaf_a, Node)
242
+ b_is_node = isinstance(leaf_b, Node)
243
+ if a_is_node != b_is_node:
211
244
  return False
212
- if isinstance(node1, SubgraphCallNode):
213
- if not graph_nodes_equal(node1.subgraph, node2.subgraph):
245
+ if a_is_node:
246
+ if not _nodes_equal(leaf_a, leaf_b, memo):
214
247
  return False
215
- elif node1.args != node2.args or node1.kwargs != node2.kwargs:
248
+ elif not _value_equal(leaf_a, leaf_b):
216
249
  return False
217
250
  return True
218
251
 
219
252
 
253
+ def _nodes_equal(node1: Node, node2: Node, memo: dict[tuple[int, int], bool]) -> bool:
254
+ if node1 is node2:
255
+ return True
256
+ if type(node1) is not type(node2):
257
+ return False
258
+
259
+ key = (id(node1), id(node2))
260
+ cached = memo.get(key)
261
+ if cached is not None:
262
+ return cached
263
+ memo[key] = True # optimistic, breaks cycles in shared DAGs
264
+
265
+ result = True
266
+ if isinstance(node1, SubgraphCallNode):
267
+ result = graph_nodes_equal(node1.subgraph, node2.subgraph)
268
+ if result and isinstance(node1, FunctionCallNode):
269
+ result = node1.func is node2.func
270
+ if result and isinstance(node1, MethodCallNode):
271
+ result = node1.method_name == node2.method_name
272
+ if result and isinstance(node1, GetAttributeNode):
273
+ result = node1.attribute_name == node2.attribute_name
274
+ if result and isinstance(node1, ProceduralNode):
275
+ result = node1.node_type == node2.node_type and _value_equal(
276
+ node1.attrs, node2.attrs
277
+ )
278
+ if result and isinstance(node1, ConstantNode):
279
+ result = _value_equal(node1.value, node2.value)
280
+ if result and isinstance(node1, InputPlaceholderNode):
281
+ result = node1.input_name == node2.input_name and _value_equal(
282
+ node1.default_value, node2.default_value
283
+ )
284
+ if result:
285
+ result = _args_equal(node1.args, node2.args, memo) and _args_equal(
286
+ node1.kwargs, node2.kwargs, memo
287
+ )
288
+
289
+ memo[key] = result
290
+ return result
291
+
292
+
293
+ def graph_nodes_equal(graph1: ComputeGraph, graph2: ComputeGraph) -> bool:
294
+ nodes1 = list(traverse_depth_first(graph1))
295
+ nodes2 = list(traverse_depth_first(graph2))
296
+ if len(nodes1) != len(nodes2):
297
+ return False
298
+ memo: dict[tuple[int, int], bool] = {}
299
+ return all(_nodes_equal(node1, node2, memo) for node1, node2 in zip(nodes1, nodes2))
300
+
301
+
220
302
  def transform_nodetree(
221
303
  root: Node,
222
304
  transform_fn: Callable[[Node], Any],
@@ -39,7 +39,7 @@ def mix_rgb(
39
39
  clamp_factor: bool = True,
40
40
  ) -> nt.ProcNode[pt.Color]:
41
41
  """
42
- Uses a Mix Node with datatype Color
42
+ Uses a Mix Shader Node with data_type='RGBA'.
43
43
 
44
44
  NOTE: separated from float/vector mix() due to extra arguments
45
45
 
@@ -80,7 +80,7 @@ def combine_rgb(
80
80
  blue: nt.SocketOrVal[float] = 0.0,
81
81
  ) -> nt.ProcNode[pt.Color]:
82
82
  """
83
- Uses a CombineColor Shader Node.
83
+ Uses a CombineColor Shader Node in RGB mode.
84
84
 
85
85
  See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/converter/combine_color.html
86
86
  """
@@ -97,7 +97,7 @@ def combine_hsv(
97
97
  value: nt.SocketOrVal[float] = 0.0,
98
98
  ) -> nt.ProcNode[pt.Color]:
99
99
  """
100
- Uses a CombineColor Shader Node.
100
+ Uses a CombineColor Shader Node in HSV mode.
101
101
 
102
102
  See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/converter/combine_color.html
103
103
  """
@@ -115,7 +115,7 @@ def combine_hsl(
115
115
  lightness: nt.SocketOrVal[float] = 0.0,
116
116
  ) -> nt.ProcNode[pt.Color]:
117
117
  """
118
- Uses a CombineHSV Shader Node.
118
+ Uses a CombineColor Shader Node in HSL mode.
119
119
 
120
120
  See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/converter/combine_color.html
121
121
  """
@@ -92,6 +92,7 @@ def boolean_or(
92
92
  a: nt.SocketOrVal[bool],
93
93
  b: nt.SocketOrVal[bool],
94
94
  ) -> nt.ProcNode[bool]:
95
+ """Uses a BooleanMath Function Node with operation='OR'."""
95
96
  return nt.ProcNode.from_nodetype(
96
97
  node_type="FunctionNodeBooleanMath",
97
98
  inputs={("Boolean", 0): a, ("Boolean", 1): b},
@@ -103,6 +104,7 @@ def boolean_and(
103
104
  a: nt.SocketOrVal[bool],
104
105
  b: nt.SocketOrVal[bool],
105
106
  ) -> nt.ProcNode[bool]:
107
+ """Uses a BooleanMath Function Node with operation='AND'."""
106
108
  return nt.ProcNode.from_nodetype(
107
109
  node_type="FunctionNodeBooleanMath",
108
110
  inputs={("Boolean", 0): a, ("Boolean", 1): b},
@@ -114,6 +116,7 @@ def boolean_xor(
114
116
  a: nt.SocketOrVal[bool],
115
117
  b: nt.SocketOrVal[bool],
116
118
  ) -> nt.ProcNode[bool]:
119
+ """Uses a BooleanMath Function Node with operation='XOR'."""
117
120
  return nt.ProcNode.from_nodetype(
118
121
  node_type="FunctionNodeBooleanMath",
119
122
  inputs={("Boolean", 0): a, ("Boolean", 1): b},
@@ -125,7 +128,7 @@ def boolean_not(
125
128
  a: nt.SocketOrVal[bool],
126
129
  ) -> nt.ProcNode[bool]:
127
130
  """
128
- Uses a BooleanNot Function Node.
131
+ Uses a BooleanMath Function Node with operation='NOT'.
129
132
 
130
133
  See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/utilities/math/boolean_math.html
131
134
  """
@@ -275,6 +278,7 @@ def less_than(
275
278
  a: TCompareNumeric,
276
279
  b: TCompareNumeric,
277
280
  ) -> nt.ProcNode[bool]:
281
+ """Uses a Compare Function Node with operation='LESS_THAN'."""
278
282
  return _compare(a, b, operation="LESS_THAN")
279
283
 
280
284
 
@@ -282,6 +286,7 @@ def less_equal(
282
286
  a: TCompareNumeric,
283
287
  b: TCompareNumeric,
284
288
  ) -> nt.ProcNode[bool]:
289
+ """Uses a Compare Function Node with operation='LESS_EQUAL'."""
285
290
  return _compare(a, b, operation="LESS_EQUAL")
286
291
 
287
292
 
@@ -289,6 +294,7 @@ def greater_than(
289
294
  a: TCompareNumeric,
290
295
  b: TCompareNumeric,
291
296
  ) -> nt.ProcNode[bool]:
297
+ """Uses a Compare Function Node with operation='GREATER_THAN'."""
292
298
  return _compare(a, b, operation="GREATER_THAN")
293
299
 
294
300
 
@@ -296,6 +302,7 @@ def greater_equal(
296
302
  a: TCompareNumeric,
297
303
  b: TCompareNumeric,
298
304
  ) -> nt.ProcNode[bool]:
305
+ """Uses a Compare Function Node with operation='GREATER_EQUAL'."""
299
306
  return _compare(a, b, operation="GREATER_EQUAL")
300
307
 
301
308
 
@@ -311,6 +318,7 @@ def equal(
311
318
  b: TCompareEqual,
312
319
  epsilon: nt.SocketOrVal[float] = COMPARE_EPSILON_DEFAULT,
313
320
  ) -> nt.ProcNode[bool]:
321
+ """Uses a Compare Function Node with operation='EQUAL'."""
314
322
  return _compare(a, b, epsilon, operation="EQUAL")
315
323
 
316
324
 
@@ -319,6 +327,7 @@ def not_equal(
319
327
  b: TCompareEqual,
320
328
  epsilon: nt.SocketOrVal[float] = COMPARE_EPSILON_DEFAULT,
321
329
  ) -> nt.ProcNode[bool]:
330
+ """Uses a Compare Function Node with operation='NOT_EQUAL'."""
322
331
  return _compare(a, b, epsilon, operation="NOT_EQUAL")
323
332
 
324
333
 
@@ -332,6 +341,7 @@ def vector_elementwise_less_than(
332
341
  a: nt.SocketOrVal[pt.Vector],
333
342
  b: nt.SocketOrVal[pt.Vector],
334
343
  ) -> nt.ProcNode[bool]:
344
+ """Uses a Compare Function Node with data_type='VECTOR', mode='ELEMENT', operation='LESS_THAN'."""
335
345
  return _compare(a, b, operation="LESS_THAN", data_type=NodeDataType.FLOAT_VECTOR)
336
346
 
337
347
 
@@ -339,6 +349,7 @@ def vector_elementwise_less_equal(
339
349
  a: nt.SocketOrVal[pt.Vector],
340
350
  b: nt.SocketOrVal[pt.Vector],
341
351
  ) -> nt.ProcNode[bool]:
352
+ """Uses a Compare Function Node with data_type='VECTOR', mode='ELEMENT', operation='LESS_EQUAL'."""
342
353
  return _compare(a, b, operation="LESS_EQUAL", data_type=NodeDataType.FLOAT_VECTOR)
343
354
 
344
355
 
@@ -346,6 +357,7 @@ def vector_elementwise_greater_than(
346
357
  a: nt.SocketOrVal[pt.Vector],
347
358
  b: nt.SocketOrVal[pt.Vector],
348
359
  ) -> nt.ProcNode[bool]:
360
+ """Uses a Compare Function Node with data_type='VECTOR', mode='ELEMENT', operation='GREATER_THAN'."""
349
361
  return _compare(a, b, operation="GREATER_THAN", data_type=NodeDataType.FLOAT_VECTOR)
350
362
 
351
363
 
@@ -353,6 +365,7 @@ def vector_elementwise_greater_equal(
353
365
  a: nt.SocketOrVal[pt.Vector],
354
366
  b: nt.SocketOrVal[pt.Vector],
355
367
  ) -> nt.ProcNode[bool]:
368
+ """Uses a Compare Function Node with data_type='VECTOR', mode='ELEMENT', operation='GREATER_EQUAL'."""
356
369
  return _compare(
357
370
  a, b, operation="GREATER_EQUAL", data_type=NodeDataType.FLOAT_VECTOR
358
371
  )
@@ -363,6 +376,7 @@ def vector_elementwise_equal(
363
376
  b: nt.SocketOrVal[pt.Vector],
364
377
  epsilon: nt.SocketOrVal[float] = COMPARE_EPSILON_DEFAULT,
365
378
  ) -> nt.ProcNode[bool]:
379
+ """Uses a Compare Function Node with data_type='VECTOR', mode='ELEMENT', operation='EQUAL'."""
366
380
  return _compare(
367
381
  a, b, epsilon, operation="EQUAL", data_type=NodeDataType.FLOAT_VECTOR
368
382
  )
@@ -373,6 +387,7 @@ def vector_elementwise_not_equal(
373
387
  b: nt.SocketOrVal[pt.Vector],
374
388
  epsilon: nt.SocketOrVal[float] = COMPARE_EPSILON_DEFAULT,
375
389
  ) -> nt.ProcNode[bool]:
390
+ """Uses a Compare Function Node with data_type='VECTOR', mode='ELEMENT', operation='NOT_EQUAL'."""
376
391
  return _compare(
377
392
  a, b, epsilon, operation="NOT_EQUAL", data_type=NodeDataType.FLOAT_VECTOR
378
393
  )
@@ -383,6 +398,7 @@ def color_equal(
383
398
  b: nt.SocketOrVal[pt.Color],
384
399
  epsilon: nt.SocketOrVal[float] = COMPARE_EPSILON_DEFAULT,
385
400
  ) -> nt.ProcNode[bool]:
401
+ """Uses a Compare Function Node with data_type='RGBA', operation='EQUAL'."""
386
402
  return _compare(a, b, epsilon, operation="EQUAL", data_type=NodeDataType.RGBA)
387
403
 
388
404
 
@@ -391,6 +407,7 @@ def color_not_equal(
391
407
  b: nt.SocketOrVal[pt.Color],
392
408
  epsilon: nt.SocketOrVal[float] = COMPARE_EPSILON_DEFAULT,
393
409
  ) -> nt.ProcNode[bool]:
410
+ """Uses a Compare Function Node with data_type='RGBA', operation='NOT_EQUAL'."""
394
411
  return _compare(a, b, epsilon, operation="NOT_EQUAL", data_type=NodeDataType.RGBA)
395
412
 
396
413
 
@@ -398,6 +415,7 @@ def color_brighter(
398
415
  a: nt.SocketOrVal[pt.Color],
399
416
  b: nt.SocketOrVal[pt.Color],
400
417
  ) -> nt.ProcNode[bool]:
418
+ """Uses a Compare Function Node with data_type='RGBA', operation='BRIGHTER'."""
401
419
  return _compare(a, b, operation="BRIGHTER", data_type=NodeDataType.RGBA)
402
420
 
403
421
 
@@ -405,6 +423,7 @@ def color_darker(
405
423
  a: nt.SocketOrVal[pt.Color],
406
424
  b: nt.SocketOrVal[pt.Color],
407
425
  ) -> nt.ProcNode[bool]:
426
+ """Uses a Compare Function Node with data_type='RGBA', operation='DARKER'."""
408
427
  return _compare(a, b, operation="DARKER", data_type=NodeDataType.RGBA)
409
428
 
410
429
 
@@ -693,7 +712,7 @@ def random_boolean(
693
712
  seed: nt.SocketOrVal[int] = 0,
694
713
  ) -> nt.ProcNode[bool]:
695
714
  """
696
- Uses a RandomBoolean Function Node.
715
+ Uses a RandomValue Function Node with data_type='BOOLEAN'.
697
716
  """
698
717
  return nt.ProcNode.from_nodetype(
699
718
  node_type="FunctionNodeRandomValue",
@@ -622,7 +622,7 @@ def curve_line(
622
622
  end: nt.SocketOrVal[nt.pt.Vector],
623
623
  ) -> nt.ProcNode[pt.CurveObject]:
624
624
  """
625
- Uses a CurvePrimitiveLine Geometry Node.
625
+ Uses a CurvePrimitiveLine Geometry Node in POINTS mode.
626
626
 
627
627
  See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/primitives/curve_line.html
628
628
  """
@@ -639,7 +639,7 @@ def curve_line_from_direction(
639
639
  length: nt.SocketOrVal[float] = 1.0,
640
640
  ) -> nt.ProcNode[pt.CurveObject]:
641
641
  """
642
- Uses a CurveLineFromDirection Geometry Node.
642
+ Uses a CurvePrimitiveLine Geometry Node in DIRECTION mode.
643
643
 
644
644
  See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/primitives/curve_line.html
645
645
  """
@@ -2633,6 +2633,7 @@ def mesh_line_from_endpoints(
2633
2633
  count: nt.SocketOrVal[int] = 10,
2634
2634
  count_mode: Literal["TOTAL", "RESOLUTION"] = "TOTAL",
2635
2635
  ) -> nt.ProcNode[pt.MeshObject]:
2636
+ """Uses a MeshLine Geometry Node with mode='END_POINTS'."""
2636
2637
  return nt.ProcNode.from_nodetype(
2637
2638
  node_type="GeometryNodeMeshLine",
2638
2639
  inputs={
@@ -3227,7 +3228,7 @@ def sample_curve(
3227
3228
  data_type: NodeDataType | RuntimeResolveDataType | None = None,
3228
3229
  ) -> SampleCurveResult:
3229
3230
  """
3230
- Uses a SampleCurve Geometry Node.
3231
+ Uses a SampleCurve Geometry Node with FACTOR mode.
3231
3232
 
3232
3233
  See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/curve/sample/sample_curve.html
3233
3234
  """
@@ -4306,7 +4307,7 @@ def transform(
4306
4307
  scale: nt.SocketOrVal[pt.Vector] = (1, 1, 1),
4307
4308
  ) -> nt.ProcNode[TMeshOrCurve]:
4308
4309
  """
4309
- Uses a Transform Geometry Node.
4310
+ Uses a Transform Geometry Node with mode='COMPONENTS'.
4310
4311
 
4311
4312
  See: https://docs.blender.org/manual/en/4.2/modeling/geometry_nodes/geometry/operations/transform_geometry.html
4312
4313
  """
@@ -4326,6 +4327,7 @@ def transform_by_matrix(
4326
4327
  geometry: nt.ProcNode[TMeshOrCurve],
4327
4328
  matrix: nt.SocketOrVal[pt.Matrix],
4328
4329
  ):
4330
+ """Uses a Transform Geometry Node with mode='MATRIX'."""
4329
4331
  return nt.ProcNode.from_nodetype(
4330
4332
  node_type="GeometryNodeTransform",
4331
4333
  inputs={