nodebpy 520.9.0__tar.gz → 520.11.0__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 (81) hide show
  1. {nodebpy-520.9.0 → nodebpy-520.11.0}/PKG-INFO +1 -1
  2. {nodebpy-520.9.0 → nodebpy-520.11.0}/pyproject.toml +1 -1
  3. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/assets/_codegen.py +42 -36
  4. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/compositor/__init__.py +6 -6
  5. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/compositor/assets.py +136 -1
  6. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/compositor/color.py +2 -2
  7. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/compositor/filter.py +5 -5
  8. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/geometry/assets.py +997 -31
  9. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/shader/__init__.py +4 -4
  10. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/shader/color.py +2 -2
  11. {nodebpy-520.9.0 → nodebpy-520.11.0}/README.md +0 -0
  12. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/__init__.py +0 -0
  13. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/assets/__init__.py +0 -0
  14. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/assets/__main__.py +0 -0
  15. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/builder/__init__.py +0 -0
  16. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/builder/_registry.py +0 -0
  17. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/builder/_utils.py +0 -0
  18. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/builder/accessor.py +0 -0
  19. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/builder/arrange.py +0 -0
  20. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/builder/asset.py +0 -0
  21. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/builder/items.py +0 -0
  22. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/builder/mixins.py +0 -0
  23. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/builder/node.py +0 -0
  24. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/builder/socket.py +0 -0
  25. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/builder/tree.py +0 -0
  26. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/export/__init__.py +0 -0
  27. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/export/codegen.py +0 -0
  28. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/export/diagram.py +0 -0
  29. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/export/web_render.py +0 -0
  30. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/lib/nodearrange/__init__.py +0 -0
  31. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/lib/nodearrange/arrange/__init__.py +0 -0
  32. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/lib/nodearrange/arrange/graph.py +0 -0
  33. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/lib/nodearrange/arrange/ordering.py +0 -0
  34. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/lib/nodearrange/arrange/ranking.py +0 -0
  35. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/lib/nodearrange/arrange/realize.py +0 -0
  36. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/lib/nodearrange/arrange/stacking.py +0 -0
  37. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/lib/nodearrange/arrange/structs.py +0 -0
  38. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/lib/nodearrange/arrange/sugiyama.py +0 -0
  39. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/lib/nodearrange/arrange/x_coords.py +0 -0
  40. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/lib/nodearrange/arrange/y_coords.py +0 -0
  41. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/lib/nodearrange/config.py +0 -0
  42. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/lib/nodearrange/utils.py +0 -0
  43. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/__init__.py +0 -0
  44. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/_mixins.py +0 -0
  45. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/compositor/converter.py +0 -0
  46. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/compositor/distort.py +0 -0
  47. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/compositor/group.py +0 -0
  48. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/compositor/input.py +0 -0
  49. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/compositor/interface.py +0 -0
  50. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/compositor/manual.py +0 -0
  51. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/compositor/matte.py +0 -0
  52. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/compositor/output.py +0 -0
  53. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/compositor/vector.py +0 -0
  54. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/geometry/__init__.py +0 -0
  55. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/geometry/attribute.py +0 -0
  56. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/geometry/color.py +0 -0
  57. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/geometry/converter.py +0 -0
  58. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/geometry/geometry.py +0 -0
  59. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/geometry/grid.py +0 -0
  60. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/geometry/group.py +0 -0
  61. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/geometry/groups.py +0 -0
  62. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/geometry/input.py +0 -0
  63. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/geometry/interface.py +0 -0
  64. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/geometry/manual.py +0 -0
  65. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/geometry/output.py +0 -0
  66. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/geometry/texture.py +0 -0
  67. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/geometry/utilities.py +0 -0
  68. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/geometry/vector.py +0 -0
  69. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/geometry/zone.py +0 -0
  70. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/shader/assets.py +0 -0
  71. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/shader/converter.py +0 -0
  72. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/shader/grid.py +0 -0
  73. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/shader/group.py +0 -0
  74. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/shader/input.py +0 -0
  75. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/shader/manual.py +0 -0
  76. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/shader/output.py +0 -0
  77. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/shader/script.py +0 -0
  78. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/shader/shader.py +0 -0
  79. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/shader/texture.py +0 -0
  80. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/nodes/shader/vector.py +0 -0
  81. {nodebpy-520.9.0 → nodebpy-520.11.0}/src/nodebpy/types.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: nodebpy
3
- Version: 520.9.0
3
+ Version: 520.11.0
4
4
  Summary: Build nodes trees in Blender more elegantly with code
5
5
  Author: Brady Johnston
6
6
  Author-email: Brady Johnston <brady.johnston@me.com>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nodebpy"
3
- version = "520.9.0"
3
+ version = "520.11.0"
4
4
  description = "Build nodes trees in Blender more elegantly with code"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -181,11 +181,10 @@ def _collect(
181
181
  group's *inputs*, whose parameters are typed from them.
182
182
  """
183
183
  descriptions = descriptions or {}
184
- raw = [
185
- s
186
- for s in sockets
187
- if s.identifier != "__extend__" and not getattr(s, "is_inactive", False)
188
- ]
184
+ # Keep inactive sockets: socket-usage inference deactivates inputs that the
185
+ # current node options (e.g. a menu selection) leave unused, but a caller
186
+ # may set those options differently, so the API must expose every input.
187
+ raw = [s for s in sockets if s.identifier != "__extend__"]
189
188
  # The accessor resolves attribute names by identifier first, then name, so a
190
189
  # group socket's readable name works as the attr/param when it's unambiguous;
191
190
  # fall back to the opaque-but-unique identifier only on a name collision.
@@ -213,6 +212,43 @@ def _collect(
213
212
  return out
214
213
 
215
214
 
215
+ def _introspect_group(group, name: str, library_source: str) -> _AssetClass:
216
+ """Introspect the node group ``group`` (a ``bpy.types.NodeTree``) into an
217
+ :class:`_AssetClass` record by instantiating it on a throwaway host node.
218
+
219
+ ``group`` is deliberately unannotated: the stubs type interface items and
220
+ ``node_groups.new`` too narrowly for the runtime attributes used here.
221
+ """
222
+ host = bpy.data.node_groups.new("_introspect_host", group.bl_idname)
223
+ try:
224
+ node_type = {
225
+ "GeometryNodeTree": "GeometryNodeGroup",
226
+ "ShaderNodeTree": "ShaderNodeGroup",
227
+ "CompositorNodeTree": "CompositorNodeGroup",
228
+ }[group.bl_idname]
229
+ node = host.nodes.new(node_type)
230
+ node.node_tree = group # ty: ignore[unresolved-attribute]
231
+ # Tooltips live on the tree *interface* items, not on the node's
232
+ # sockets — collect them by identifier so the generated docstrings
233
+ # can use the asset author's own wording.
234
+ descriptions = {
235
+ item.identifier: item.description or ""
236
+ for item in group.interface.items_tree
237
+ if item.item_type == "SOCKET"
238
+ }
239
+ return _AssetClass(
240
+ class_name=_class_name(name),
241
+ asset_name=name,
242
+ description=(group.description or name).strip(),
243
+ library_source=library_source,
244
+ tree_idname=group.bl_idname,
245
+ inputs=_collect(node.inputs, descriptions, menus=True),
246
+ outputs=_collect(node.outputs, descriptions),
247
+ )
248
+ finally:
249
+ bpy.data.node_groups.remove(host)
250
+
251
+
216
252
  def _introspect(library: AssetLibrary, names: set[str] | None) -> list[_AssetClass]:
217
253
  """Append each requested group from the library and introspect its
218
254
  interface into :class:`_AssetClass` records."""
@@ -236,37 +272,7 @@ def _introspect(library: AssetLibrary, names: set[str] | None) -> list[_AssetCla
236
272
  ):
237
273
  dst.node_groups = [name]
238
274
  group = dst.node_groups[0]
239
-
240
- host = bpy.data.node_groups.new("_introspect_host", group.bl_idname)
241
- try:
242
- node_type = {
243
- "GeometryNodeTree": "GeometryNodeGroup",
244
- "ShaderNodeTree": "ShaderNodeGroup",
245
- "CompositorNodeTree": "CompositorNodeGroup",
246
- }[group.bl_idname]
247
- node = host.nodes.new(node_type)
248
- node.node_tree = group # ty: ignore[unresolved-attribute]
249
- # Tooltips live on the tree *interface* items, not on the node's
250
- # sockets — collect them by identifier so the generated docstrings
251
- # can use the asset author's own wording.
252
- descriptions = {
253
- item.identifier: item.description or ""
254
- for item in group.interface.items_tree
255
- if item.item_type == "SOCKET"
256
- }
257
- classes.append(
258
- _AssetClass(
259
- class_name=_class_name(name),
260
- asset_name=name,
261
- description=(group.description or name).strip(),
262
- library_source=library_source,
263
- tree_idname=group.bl_idname,
264
- inputs=_collect(node.inputs, descriptions, menus=True),
265
- outputs=_collect(node.outputs, descriptions),
266
- )
267
- )
268
- finally:
269
- bpy.data.node_groups.remove(host)
275
+ classes.append(_introspect_group(group, name, library_source))
270
276
  return classes
271
277
 
272
278
 
@@ -99,13 +99,13 @@ from ..geometry.vector import (
99
99
  )
100
100
  from .color import (
101
101
  AlphaOver,
102
- Brightnesscontrast,
102
+ BrightnessContrast,
103
103
  ColorBalance,
104
104
  ColorCorrection,
105
105
  DepthCombine,
106
106
  Exposure,
107
107
  HueCorrect,
108
- Huesaturationvalue,
108
+ HueSaturationValue,
109
109
  InvertColor,
110
110
  Posterize,
111
111
  RGBCurves,
@@ -120,7 +120,7 @@ from .filter import (
120
120
  Defocus,
121
121
  Denoise,
122
122
  Despeckle,
123
- Dilateerode,
123
+ DilateErode,
124
124
  DirectionalBlur,
125
125
  Filter,
126
126
  Glare,
@@ -241,7 +241,7 @@ __all__ = (
241
241
  "Boolean",
242
242
  "BoxMask",
243
243
  "BrickTexture",
244
- "Brightnesscontrast",
244
+ "BrightnessContrast",
245
245
  "CameraInfo",
246
246
  "ChannelKey",
247
247
  "CheckerTexture",
@@ -270,7 +270,7 @@ __all__ = (
270
270
  "DepthCombine",
271
271
  "Despeckle",
272
272
  "DifferenceKey",
273
- "Dilateerode",
273
+ "DilateErode",
274
274
  "DirectionalBlur",
275
275
  "Displace",
276
276
  "DistanceKey",
@@ -297,7 +297,7 @@ __all__ = (
297
297
  "GroupInput",
298
298
  "GroupOutput",
299
299
  "HueCorrect",
300
- "Huesaturationvalue",
300
+ "HueSaturationValue",
301
301
  "IDMask",
302
302
  "Image",
303
303
  "ImageCoordinates",
@@ -35,8 +35,16 @@ class ChromaticAberration(AssetCompositorGroup):
35
35
  Image
36
36
  type : InputMenu | Literal["Offset", "Scale", "Directional Blur", "Lens Dispersion"]
37
37
  Different styles of aberrations
38
+ axis : InputMenu | Literal["Vertical", "Horizontal"]
39
+ Direction of the aberration effect
38
40
  factor : InputFloat
39
41
  The intensity of the aberration effect
42
+ center : InputVector
43
+ The position the transformations pivot around, in normalized coordinates. 0 means the lower left corner and 1 means the upper right corner of the image.
44
+ samples : InputInteger
45
+ The number of samples used to compute the blur. The more samples the smoother the result, at the expense of more compute time. The actual number of samples is two to the power of this input, so it increases exponentially.
46
+ fit : InputBoolean
47
+ Scale the image such that it fits entirely in the frame, leaving no empty spaces at the corners
40
48
 
41
49
  Inputs
42
50
  ------
@@ -44,8 +52,16 @@ class ChromaticAberration(AssetCompositorGroup):
44
52
  Image
45
53
  i.type : MenuSocket
46
54
  Different styles of aberrations
55
+ i.axis : MenuSocket
56
+ Direction of the aberration effect
47
57
  i.factor : FloatSocket
48
58
  The intensity of the aberration effect
59
+ i.center : VectorSocket
60
+ The position the transformations pivot around, in normalized coordinates. 0 means the lower left corner and 1 means the upper right corner of the image.
61
+ i.samples : IntegerSocket
62
+ The number of samples used to compute the blur. The more samples the smoother the result, at the expense of more compute time. The actual number of samples is two to the power of this input, so it increases exponentially.
63
+ i.fit : BooleanSocket
64
+ Scale the image such that it fits entirely in the frame, leaving no empty spaces at the corners
49
65
 
50
66
  Outputs
51
67
  -------
@@ -62,8 +78,16 @@ class ChromaticAberration(AssetCompositorGroup):
62
78
  """Image"""
63
79
  type: MenuSocket
64
80
  """Different styles of aberrations"""
81
+ axis: MenuSocket
82
+ """Direction of the aberration effect"""
65
83
  factor: FloatSocket
66
84
  """The intensity of the aberration effect"""
85
+ center: VectorSocket
86
+ """The position the transformations pivot around, in normalized coordinates. 0 means the lower left corner and 1 means the upper right corner of the image."""
87
+ samples: IntegerSocket
88
+ """The number of samples used to compute the blur. The more samples the smoother the result, at the expense of more compute time. The actual number of samples is two to the power of this input, so it increases exponentially."""
89
+ fit: BooleanSocket
90
+ """Scale the image such that it fits entirely in the frame, leaving no empty spaces at the corners"""
67
91
 
68
92
  class _Outputs(SocketAccessor):
69
93
  image: ColorSocket
@@ -81,9 +105,23 @@ class ChromaticAberration(AssetCompositorGroup):
81
105
  image: InputColor = None,
82
106
  type: InputMenu
83
107
  | Literal["Offset", "Scale", "Directional Blur", "Lens Dispersion"] = "Scale",
108
+ axis: InputMenu | Literal["Vertical", "Horizontal"] = "Horizontal",
84
109
  factor: InputFloat = 0.2,
110
+ center: InputVector = None,
111
+ samples: InputInteger = 3,
112
+ fit: InputBoolean = False,
85
113
  ):
86
- super().__init__(**{"Socket_1": image, "Socket_6": type, "Socket_2": factor})
114
+ super().__init__(
115
+ **{
116
+ "Socket_1": image,
117
+ "Socket_6": type,
118
+ "Socket_8": axis,
119
+ "Socket_2": factor,
120
+ "Socket_3": center,
121
+ "Socket_4": samples,
122
+ "Socket_7": fit,
123
+ }
124
+ )
87
125
 
88
126
 
89
127
  class CombineCylindrical(AssetCompositorGroup):
@@ -218,8 +256,28 @@ class FilmGrain(AssetCompositorGroup):
218
256
  Amount of mixing between the effect and original image
219
257
  preset : InputMenu | Literal["8 mm Caffenol", "8 mm Home Movie", "Super 8 mm", "16 mm Broadcast", "16 mm Indie Cinema", "35 mm Portra 400", "Super 35 mm", "70 mm Cinema", "Custom"]
220
258
  Preset
259
+ film_gauge : InputMenu | Literal["8 mm", "16 mm", "35 mm", "70 mm"]
260
+ Film Gauge
261
+ style : InputMenu | Literal["Xpro Sharp", "Cinematic Gritty", "Home Movie", "Studio Broadcast", "Pro Photography", "Cinematic Soft", "Custom Style"]
262
+ Style
221
263
  animated : InputBoolean
222
264
  Should the noise change frame to frame
265
+ iso : InputInteger
266
+ ISO
267
+ softness : InputFloat
268
+ Halation-style softening: edges "bleed" and become smoother, adds bloom and noise that is somewhat pattern-aware
269
+ acutance : InputFloat
270
+ Sharpens large details and adds a halo around objects
271
+ coarseness : InputFloat
272
+ Emulsion roughness, also adds grain clamping
273
+ patchiness : InputFloat
274
+ Smoothness of the film substrate. High values contribute to a stroboscope effect when animating.
275
+ saturation : InputFloat
276
+ Noise colorfulness
277
+ luma_bias : InputFloat
278
+ Luma bias
279
+ texture_scale : InputFloat
280
+ Texture Scale
223
281
 
224
282
  Inputs
225
283
  ------
@@ -229,8 +287,28 @@ class FilmGrain(AssetCompositorGroup):
229
287
  Amount of mixing between the effect and original image
230
288
  i.preset : MenuSocket
231
289
  Preset
290
+ i.film_gauge : MenuSocket
291
+ Film Gauge
292
+ i.style : MenuSocket
293
+ Style
232
294
  i.animated : BooleanSocket
233
295
  Should the noise change frame to frame
296
+ i.iso : IntegerSocket
297
+ ISO
298
+ i.softness : FloatSocket
299
+ Halation-style softening: edges "bleed" and become smoother, adds bloom and noise that is somewhat pattern-aware
300
+ i.acutance : FloatSocket
301
+ Sharpens large details and adds a halo around objects
302
+ i.coarseness : FloatSocket
303
+ Emulsion roughness, also adds grain clamping
304
+ i.patchiness : FloatSocket
305
+ Smoothness of the film substrate. High values contribute to a stroboscope effect when animating.
306
+ i.saturation : FloatSocket
307
+ Noise colorfulness
308
+ i.luma_bias : FloatSocket
309
+ Luma bias
310
+ i.texture_scale : FloatSocket
311
+ Texture Scale
234
312
 
235
313
  Outputs
236
314
  -------
@@ -249,8 +327,28 @@ class FilmGrain(AssetCompositorGroup):
249
327
  """Amount of mixing between the effect and original image"""
250
328
  preset: MenuSocket
251
329
  """Preset"""
330
+ film_gauge: MenuSocket
331
+ """Film Gauge"""
332
+ style: MenuSocket
333
+ """Style"""
252
334
  animated: BooleanSocket
253
335
  """Should the noise change frame to frame"""
336
+ iso: IntegerSocket
337
+ """ISO"""
338
+ softness: FloatSocket
339
+ """Halation-style softening: edges "bleed" and become smoother, adds bloom and noise that is somewhat pattern-aware"""
340
+ acutance: FloatSocket
341
+ """Sharpens large details and adds a halo around objects"""
342
+ coarseness: FloatSocket
343
+ """Emulsion roughness, also adds grain clamping"""
344
+ patchiness: FloatSocket
345
+ """Smoothness of the film substrate. High values contribute to a stroboscope effect when animating."""
346
+ saturation: FloatSocket
347
+ """Noise colorfulness"""
348
+ luma_bias: FloatSocket
349
+ """Luma bias"""
350
+ texture_scale: FloatSocket
351
+ """Texture Scale"""
254
352
 
255
353
  class _Outputs(SocketAccessor):
256
354
  result: ColorSocket
@@ -279,14 +377,43 @@ class FilmGrain(AssetCompositorGroup):
279
377
  "70 mm Cinema",
280
378
  "Custom",
281
379
  ] = "Super 8 mm",
380
+ film_gauge: InputMenu | Literal["8 mm", "16 mm", "35 mm", "70 mm"] = "16 mm",
381
+ style: InputMenu
382
+ | Literal[
383
+ "Xpro Sharp",
384
+ "Cinematic Gritty",
385
+ "Home Movie",
386
+ "Studio Broadcast",
387
+ "Pro Photography",
388
+ "Cinematic Soft",
389
+ "Custom Style",
390
+ ] = "Studio Broadcast",
282
391
  animated: InputBoolean = False,
392
+ iso: InputInteger = 400,
393
+ softness: InputFloat = 0.5,
394
+ acutance: InputFloat = 0.5,
395
+ coarseness: InputFloat = 0.5,
396
+ patchiness: InputFloat = 0.5,
397
+ saturation: InputFloat = 0.5,
398
+ luma_bias: InputFloat = 0.5,
399
+ texture_scale: InputFloat = 0.5,
283
400
  ):
284
401
  super().__init__(
285
402
  **{
286
403
  "Socket_1": input,
287
404
  "Socket_7": factor,
288
405
  "Socket_64": preset,
406
+ "Socket_46": film_gauge,
407
+ "Socket_47": style,
289
408
  "Socket_10": animated,
409
+ "Socket_56": iso,
410
+ "Socket_52": softness,
411
+ "Socket_70": acutance,
412
+ "Socket_53": coarseness,
413
+ "Socket_54": patchiness,
414
+ "Socket_55": saturation,
415
+ "Socket_65": luma_bias,
416
+ "Socket_73": texture_scale,
290
417
  }
291
418
  )
292
419
 
@@ -395,6 +522,8 @@ class Retime(AssetCompositorGroup):
395
522
  Multiply the current scene frame by this factor
396
523
  cyclic : InputBoolean
397
524
  Restart from start frame when Cycle Length is reached
525
+ cycle_length : InputInteger
526
+ Number of frames to cycle through. Not affected by Speed.
398
527
 
399
528
  Inputs
400
529
  ------
@@ -406,6 +535,8 @@ class Retime(AssetCompositorGroup):
406
535
  Multiply the current scene frame by this factor
407
536
  i.cyclic : BooleanSocket
408
537
  Restart from start frame when Cycle Length is reached
538
+ i.cycle_length : IntegerSocket
539
+ Number of frames to cycle through. Not affected by Speed.
409
540
 
410
541
  Outputs
411
542
  -------
@@ -426,6 +557,8 @@ class Retime(AssetCompositorGroup):
426
557
  """Multiply the current scene frame by this factor"""
427
558
  cyclic: BooleanSocket
428
559
  """Restart from start frame when Cycle Length is reached"""
560
+ cycle_length: IntegerSocket
561
+ """Number of frames to cycle through. Not affected by Speed."""
429
562
 
430
563
  class _Outputs(SocketAccessor):
431
564
  frame: IntegerSocket
@@ -444,6 +577,7 @@ class Retime(AssetCompositorGroup):
444
577
  step: InputInteger = 1,
445
578
  speed: InputFloat = 1.0,
446
579
  cyclic: InputBoolean = False,
580
+ cycle_length: InputInteger = 10,
447
581
  ):
448
582
  super().__init__(
449
583
  **{
@@ -451,6 +585,7 @@ class Retime(AssetCompositorGroup):
451
585
  "Socket_13": step,
452
586
  "Socket_14": speed,
453
587
  "Socket_11": cyclic,
588
+ "Socket_3": cycle_length,
454
589
  }
455
590
  )
456
591
 
@@ -156,7 +156,7 @@ class AlphaOver(BaseNode):
156
156
  )
157
157
 
158
158
 
159
- class Brightnesscontrast(BaseNode):
159
+ class BrightnessContrast(BaseNode):
160
160
  """
161
161
  Adjust brightness and contrast
162
162
 
@@ -968,7 +968,7 @@ class HueCorrect(BaseNode):
968
968
  self._establish_links(**key_args)
969
969
 
970
970
 
971
- class Huesaturationvalue(BaseNode):
971
+ class HueSaturationValue(BaseNode):
972
972
  """
973
973
  Apply a color transformation in the HSV color model
974
974
 
@@ -856,7 +856,7 @@ class Despeckle(BaseNode):
856
856
  self._establish_links(**key_args)
857
857
 
858
858
 
859
- class Dilateerode(BaseNode):
859
+ class DilateErode(BaseNode):
860
860
  """
861
861
  Expand and shrink masks
862
862
 
@@ -942,7 +942,7 @@ class Dilateerode(BaseNode):
942
942
  self._establish_links(**key_args)
943
943
 
944
944
  @classmethod
945
- def steps(cls, mask: InputFloat = 0.0, size: InputInteger = 0) -> "Dilateerode":
945
+ def steps(cls, mask: InputFloat = 0.0, size: InputInteger = 0) -> "DilateErode":
946
946
  """Create Dilate/Erode node with type 'Steps'."""
947
947
  return cls(mask=mask, size=size, type="Steps")
948
948
 
@@ -952,12 +952,12 @@ class Dilateerode(BaseNode):
952
952
  mask: InputFloat = 0.0,
953
953
  size: InputInteger = 0,
954
954
  falloff_size: InputFloat = 0.0,
955
- ) -> "Dilateerode":
955
+ ) -> "DilateErode":
956
956
  """Create Dilate/Erode node with type 'Threshold'."""
957
957
  return cls(mask=mask, size=size, falloff_size=falloff_size, type="Threshold")
958
958
 
959
959
  @classmethod
960
- def distance(cls, mask: InputFloat = 0.0, size: InputInteger = 0) -> "Dilateerode":
960
+ def distance(cls, mask: InputFloat = 0.0, size: InputInteger = 0) -> "DilateErode":
961
961
  """Create Dilate/Erode node with type 'Distance'."""
962
962
  return cls(mask=mask, size=size, type="Distance")
963
963
 
@@ -970,7 +970,7 @@ class Dilateerode(BaseNode):
970
970
  | Literal[
971
971
  "Smooth", "Sphere", "Root", "Inverse Square", "Sharp", "Linear"
972
972
  ] = "Smooth",
973
- ) -> "Dilateerode":
973
+ ) -> "DilateErode":
974
974
  """Create Dilate/Erode node with type 'Feather'."""
975
975
  return cls(mask=mask, size=size, falloff=falloff, type="Feather")
976
976