๐Ÿ Blender Python API Referenceยถ

Every public class and method listed here is reachable after from bl_ext.user_default.ppf_contact_solver.ops.api import solver. See ๐Ÿ Blender Python API for a narrative walkthrough of the same surface.

Classes:

class Solverยถ

Top-level entry point for the ZOZO Contact Solver.

Available as solver when imported via:

from bl_ext.user_default.ppf_contact_solver.ops.api import solver

Scene parameters are accessed via param (a SceneParam proxy). Groups, pins, and invisible colliders are created via the methods below.

Unrecognized attribute access falls through to bpy.ops.zozo_contact_solver.<name>(), so every operator registered under that namespace (including every MCP handler) can be called as a method on solver.

Example:

solver.param.gravity = (0, 0, -9.8)
group = solver.create_group("Sphere", type="SOLID")
group.add("Sphere")
group.param.solid_density = 1000
create_group(name: str = '', type: str = 'SOLID') Groupยถ

Create a new dynamics group.

Parameters:
  • name โ€“ Display name for the group. Empty string leaves the auto-generated name in place.

  • type โ€“ One of "SOLID", "SHELL", "ROD", "STATIC".

Returns:

A Group proxy for the newly created group.

Example:

group = solver.create_group("Shirt", type="SHELL")
group.add("Shirt")
get_group(group_uuid: str) Groupยถ

Look up a group by UUID.

Parameters:

group_uuid โ€“ UUID string of the group.

Returns:

A Group proxy.

Raises:

KeyError โ€“ If the group does not exist.

Example:

uuid = solver.get_groups()[0].uuid
group = solver.get_group(uuid)
get_groups() list[Group]ยถ

Return Group proxies for every active group.

Example:

for group in solver.get_groups():
    print(group.uuid)
delete_all_groups() Solverยถ

Delete every active group and the pins they own.

Returns:

self for chaining.

Example:

solver.delete_all_groups()
clear() Solverยถ

Reset the entire solver state to defaults.

Deletes every active group, resets scene parameters to their property defaults, clears merge pairs, invisible colliders, dynamic parameters, previously fetched frames, saved pin keyframes, and any residual MESH_CACHE modifiers on mesh objects. Call this at the top of any script that needs a clean slate.

Returns:

self for chaining.

Example:

solver.clear()
solver.param.gravity = (0, 0, -9.8)
create_curve(name: str, *, bevel_depth: float = 0.0, bevel_resolution: int = 2, resolution_u: int = 4, dimensions: str = '3D', clear_existing: bool = True) Curveยถ

Start building a multi-spline Bezier curve object.

Returns a Curve builder. Use Curve.add_spline() for each spline, optionally Curve.set_material() to color them, then Curve.finalize() to link the resulting object into the scene.

Parameters:
  • name โ€“ Object name. When clear_existing is true (the default) any existing object with this name is removed first so re-running the script starts from a clean slate.

  • bevel_depth โ€“ Tube radius for visualization (Blenderโ€™s Curve.bevel_depth). 0 leaves the curve as a wireframe.

  • bevel_resolution โ€“ Tube cross-section subdivisions (Curve.bevel_resolution).

  • resolution_u โ€“ Spline interpolation resolution (Curve.resolution_u).

  • dimensions โ€“ "3D" (default) or "2D".

  • clear_existing โ€“ Set False to skip the same-name cleanup.

Returns:

A Curve builder.

Example:

curve = solver.create_curve("Strands", bevel_depth=3e-3)
for points, closed in strands:
    curve.add_spline(points, closed=closed)
obj = curve.finalize()
snap(object_a: str, object_b: str) Solverยถ

Translate object_a so its nearest vertex lands on object_b.

Parameters:
  • object_a โ€“ Name of the mesh that moves.

  • object_b โ€“ Name of the mesh that stays in place.

Returns:

self for chaining.

Raises:

ValueError โ€“ If either object is missing, not a mesh, or validation in the underlying mutation service fails.

Example:

solver.snap("Shirt", "Mannequin")
add_merge_pair(object_a: str, object_b: str) Solverยถ

Mark two objects to be merged at their shared contact.

Parameters:
  • object_a โ€“ Name of the first mesh.

  • object_b โ€“ Name of the second mesh.

Returns:

self for chaining.

Raises:

ValueError โ€“ If either object is missing, not a mesh, or the pair is invalid.

Example:

solver.add_merge_pair("SleeveLeft", "BodyLeft")
remove_merge_pair(object_a: str, object_b: str) Solverยถ

Remove a previously added merge pair.

The ordering of object_a and object_b does not matter; the pair is matched by UUID in either direction.

Parameters:
  • object_a โ€“ Name of the first mesh.

  • object_b โ€“ Name of the second mesh.

Returns:

self for chaining.

Raises:

ValueError โ€“ If validation fails for the given pair.

Example:

solver.remove_merge_pair("SleeveLeft", "BodyLeft")
get_merge_pairs() list[tuple[str, str]]ยถ

Return every merge pair as a list of (object_a, object_b) tuples.

Example:

for a, b in solver.get_merge_pairs():
    print(f"{a} <-> {b}")
clear_merge_pairs() Solverยถ

Remove every merge pair.

Returns:

self for chaining.

Example:

solver.clear_merge_pairs()
add_wall(position, normal) Wallยถ

Add an invisible infinite-plane wall collider.

Parameters:
  • position โ€“ (x, y, z) world-space point on the plane.

  • normal โ€“ (nx, ny, nz) outward-facing plane normal. Need not be unit-length.

Returns:

A chainable Wall builder bound to the newly added collider.

Raises:

ValueError โ€“ If the position or normal fails vec3 validation.

Example:

solver.add_wall(position=(0, 0, 0), normal=(0, 0, 1))
add_sphere(position, radius) Sphereยถ

Add an invisible sphere collider.

Parameters:
  • position โ€“ (x, y, z) world-space center.

  • radius โ€“ Sphere radius.

Returns:

A chainable Sphere builder bound to the newly added collider.

Raises:

ValueError โ€“ If the position or radius fails validation.

Example:

solver.add_sphere(position=(0, 0, 1.0), radius=0.25)
get_invisible_colliders() listยถ

Return every invisible collider as a list of (type, name) tuples.

type is one of "WALL" or "SPHERE".

Example:

for kind, name in solver.get_invisible_colliders():
    print(kind, name)
clear_invisible_colliders() Solverยถ

Remove every invisible collider.

Returns:

self for chaining.

Example:

solver.clear_invisible_colliders()
class SceneParamยถ

Attribute proxy for scene and SSH/connection parameters.

Accessed as Solver.param. Supports both get and set via attribute access. Writes go through the zozo_contact_solver.set operator (with auto type coercion), reads fall through to the sceneโ€™s addon state or SSH state.

gravity is an alias for gravity_3d.

Example:

solver.param.step_size = 0.004
print(solver.param.gravity)

Dynamic (keyframed) parameters are accessed via dyn():

solver.param.dyn("gravity").time(60).hold().time(61).change((0, 0, 9.8))
dyn(key: str) DynParamยถ

Select a parameter for dynamic keyframing.

Parameters:

key โ€“ One of "gravity", "wind", "air_density", "air_friction", "vertex_air_damp".

Returns:

A chainable DynParam builder.

Raises:

ValueError โ€“ If key is not one of the valid dynamic keys.

Example:

solver.param.dyn("gravity").time(60).hold().time(61).change((0, 0, 9.8))
class DynParamยถ

Fluent builder for dynamic scene parameter keyframes.

Mirrors the frontend session.param.dyn() API but uses frames instead of seconds. Obtained from SceneParam.dyn().

Valid parameter keys: "gravity", "wind", "air_density", "air_friction", "vertex_air_damp".

Frames must be strictly increasing within a chain. Every mutating method returns self so operations chain.

Example:

solver.param.dyn("gravity").time(60).hold().time(61).change((0, 0, 9.8))
solver.param.dyn("wind").time(30).hold().time(31).change((0, 1, 0), strength=5.0)
time(frame: int) DynParamยถ

Advance the frame cursor.

Parameters:

frame โ€“ Target frame (must be strictly greater than the current cursor position).

Returns:

self for chaining.

Raises:

ValueError โ€“ If frame is not strictly increasing.

Example:

solver.param.dyn("gravity").time(60).hold().time(61).change((0, 0, 9.8))
hold() DynParamยถ

Hold the previous value at the current cursor frame (step function).

Returns:

self for chaining.

Example:

solver.param.dyn("gravity").time(60).hold().time(61).change((0, 0, 9.8))
change(value, strength=None) DynParamยถ

Set a new value at the current cursor frame.

Parameters:
  • value โ€“ For "gravity", an (x, y, z) tuple. For "wind", an (x, y, z) direction tuple. For scalar keys ("air_density", "air_friction", "vertex_air_damp"), a float.

  • strength โ€“ Wind strength (only for "wind").

Returns:

self for chaining.

Example:

solver.param.dyn("wind").time(30).hold().time(31).change((0, 1, 0), strength=5.0)
clear() DynParamยถ

Remove this dynamic parameter entirely.

Returns:

self for chaining (though no further method on this builder will do anything meaningful after clear()).

Example:

solver.param.dyn("wind").clear()
class Groupยถ

A dynamics group proxy.

Created via Solver.create_group(). Material parameters are accessed via param. Every mutating method returns self so operations chain.

Example:

group = solver.create_group("Shirt", type="SHELL")
group.add("Shirt").set_overlay_color(0.9, 0.2, 0.1)
group.param.friction = 0.5
group.param.shell_density = 1.0
property uuidยถ
Type:

str

The UUID of this group. Stable across renames.

Example:

group = solver.create_group("Shirt", type="SHELL")
same_group = solver.get_group(group.uuid)
property nameยถ
Type:

str

Display name of this group.

Example:

for g in solver.get_groups():
    if g.name == "WovenStrands":
        g.delete()
property paramยถ
Type:

GroupParam

Material and simulation parameter proxy. See GroupParam.

Example:

group.param.friction = 0.5
group.param.shell_density = 1.0
set_overlay_color(r: float, g: float, b: float, a: float = 1.0) Groupยถ

Set the viewport overlay color for this group and enable it.

Parameters:
  • r โ€“ Red channel in [0, 1].

  • g โ€“ Green channel in [0, 1].

  • b โ€“ Blue channel in [0, 1].

  • a โ€“ Alpha in [0, 1] (default 1.0).

Returns:

self for chaining.

Example:

group.set_overlay_color(0.9, 0.2, 0.1)  # red overlay
add(*object_names: str) Groupยถ

Add mesh objects to this group by name.

Parameters:

*object_names โ€“ One or more Blender object names.

Returns:

self for chaining.

Example:

group.add("Shirt", "Skirt", "Sleeve")
remove(object_name: str) Groupยถ

Remove an object from this group.

Parameters:

object_name โ€“ Name of the object to remove.

Returns:

self for chaining.

Example:

group.remove("Sleeve")
set_velocity(object_name: str, direction: tuple[float, float, float], speed: float, frame: int = 1) Groupยถ

Keyframe a velocity on an object assigned to this group.

Appends an entry to the assigned objectโ€™s velocity_keyframes collection. Call once with frame=1 for an initial-velocity launch; call again with higher frame values to build a velocity schedule.

Parameters:
  • object_name โ€“ Name of an object already added to this group via add().

  • direction โ€“ (dx, dy, dz) velocity direction; normalized by the solver before use.

  • speed โ€“ Velocity magnitude in m/s.

  • frame โ€“ Frame at which the keyframe takes effect. 1 (the default) is the initial-velocity slot.

Returns:

self for chaining.

Raises:

ValueError โ€“ If the object is not assigned to this group, or a keyframe already exists at the requested frame.

Example:

ball = solver.create_group("Ball", type="SOLID")
ball.add("Sphere")
ball.set_velocity("Sphere", direction=(1, 0, 0), speed=2.3)
create_pin(object_name: str, vertex_group_name: str, indices: list[int] | None = None) Pinยถ

Pin a vertex group (mesh) or set of control points (curve).

Parameters:
  • object_name โ€“ Name of the mesh or curve object.

  • vertex_group_name โ€“ For meshes, the name of an existing vertex group on the object. For curves, the logical name used for the curveโ€™s _pin_<vertex_group_name> custom property holding the pinned control-point indices.

  • indices โ€“ Control-point indices for curves only. When given, the curveโ€™s _pin_<vertex_group_name> property is written before the pin is registered, so the same call both defines and binds the pin. Must be None for meshes (meshes use existing vertex groups).

Returns:

A Pin proxy for the newly created pin.

Raises:

ValueError โ€“ If the object is missing, not a mesh or curve, the vertex group does not exist on a mesh, the _pin_<name> property is missing on a curve and no indices were supplied, or indices is passed for a mesh.

Example:

# Mesh: vertex group must already exist.
pin = group.create_pin("Cloth", "collar")
pin.move_by(delta=(0, 0, 0.2), frame_start=1, frame_end=60)

# Curve: pass control-point indices to define and bind in
# one call.
rod_pin = rod_group.create_pin(
    "WovenCylinder", "left", indices=[0, 7, 14, 21],
)
get_pins() list[Pin]ยถ

Return all pins in this group as Pin proxies.

Example:

for pin in group.get_pins():
    print(pin.object_name, pin.vertex_group_name)
delete() Noneยถ

Delete this group and every pin it owns.

Example:

group.delete()
class GroupParamยถ

Proxy for material and simulation parameters on a group.

Accessed via Group.param. Attribute access is whitelisted: reading or writing a name outside the whitelist raises AttributeError.

Whitelisted attributes:

  • Solver model: solid_model, shell_model

  • Density: solid_density, shell_density, rod_density

  • Youngโ€™s modulus: solid_young_modulus, shell_young_modulus, rod_young_modulus

  • Poisson ratio: solid_poisson_ratio, shell_poisson_ratio

  • Contact: friction, use_group_bounding_box_diagonal, contact_gap, contact_gap_rat, contact_offset, contact_offset_rat. When use_group_bounding_box_diagonal is True (the default), the solver consumes contact_gap_rat * bbox-diagonal and contact_offset_rat * bbox-diagonal; set it to False to consume the absolute contact_gap / contact_offset values directly.

  • Strain limit: enable_strain_limit, strain_limit

  • Inflation: enable_inflate, inflate_pressure

  • Plasticity: enable_plasticity, plasticity, plasticity_threshold

  • Bend plasticity: enable_bend_plasticity, bend_plasticity, bend_plasticity_threshold, bend_rest_angle_source

  • Shell-specific: bend, shrink, shrink_x, shrink_y, stitch_stiffness

Example:

# Solver model
group.param.solid_model = "ARAP"
group.param.shell_model = "ARAP"

# Density (kg/m^3 for solid/shell, kg/m for rod)
group.param.solid_density = 1000.0
group.param.shell_density = 0.3
group.param.rod_density = 0.05

# Young's modulus (Pa) and Poisson ratio
group.param.solid_young_modulus = 1.0e6
group.param.shell_young_modulus = 5.0e5
group.param.rod_young_modulus = 1.0e7
group.param.solid_poisson_ratio = 0.45
group.param.shell_poisson_ratio = 0.30

# Contact (absolute mode)
group.param.use_group_bounding_box_diagonal = False
group.param.friction = 0.5
group.param.contact_gap = 0.001
group.param.contact_offset = 0.002

# Contact (ratio mode -- defaults)
group.param.use_group_bounding_box_diagonal = True
group.param.contact_gap_rat = 0.1
group.param.contact_offset_rat = 0.2

# Strain limit
group.param.enable_strain_limit = True
group.param.strain_limit = 1.05

# Inflation
group.param.enable_inflate = True
group.param.inflate_pressure = 100.0

# Plasticity (shells and tets only)
group.param.enable_plasticity = True
group.param.plasticity = 0.3
group.param.plasticity_threshold = 0.2
group.param.enable_bend_plasticity = True
group.param.bend_plasticity = 0.5
group.param.bend_plasticity_threshold = 0.1
group.param.bend_rest_angle_source = "REST"

# Shell-specific
group.param.bend = 1.0e-4
group.param.shrink = 0.98
group.param.shrink_x = 0.99
group.param.shrink_y = 0.97
group.param.stitch_stiffness = 5.0e4
class Pinยถ

A pinned vertex group bound to a dynamics group.

Created via Group.create_pin(object_name, vertex_group_name). Every mutating method returns self so operations chain.

Example:

pin = group.create_pin("Cloth", "hem")
pin.move_by(delta=(0, 0, 1.0), frame_start=1, frame_end=60)
pin.unpin(frame=120)
property object_nameยถ
Type:

str

Name of the mesh object this pin belongs to.

Example:

pin = group.create_pin("Cloth", "hem")
print(pin.object_name)  # "Cloth"
property vertex_group_nameยถ
Type:

str

Name of the vertex group this pin targets.

Example:

pin = group.create_pin("Cloth", "hem")
print(pin.vertex_group_name)  # "hem"
pull(strength: float = 1.0) Pinยถ

Use pull force instead of hard pin constraint.

Pull allows the vertices to move but applies a restoring force toward their target position.

Parameters:

strength โ€“ Pull force strength (default 1.0).

Returns:

self for chaining.

Example:

group.create_pin("Cloth", "shoulder").pull(strength=2.5)
spin(axis: tuple[float, float, float] = (1, 0, 0), angular_velocity: float = 360.0, flip: bool = False, center: tuple[float, float, float] | None = None, center_mode: str | None = None, center_direction: tuple[float, float, float] | None = None, center_vertex: int | None = None, frame_start: int = 1, frame_end: int = 60, transition: str = 'LINEAR') Pinยถ

Add a spin operation to this pin.

Parameters:
  • axis โ€“ Rotation axis vector.

  • angular_velocity โ€“ Degrees per second.

  • flip โ€“ Reverse spin direction.

  • center โ€“ Center of rotation (for ABSOLUTE mode).

  • center_mode โ€“ "CENTROID", "ABSOLUTE", "MAX_TOWARDS", or "VERTEX". If None, inferred from other args (None center โ†’ "CENTROID").

  • center_direction โ€“ Direction for MAX_TOWARDS mode.

  • center_vertex โ€“ Vertex index for VERTEX mode.

  • frame_start โ€“ Start frame.

  • frame_end โ€“ End frame.

  • transition โ€“ "LINEAR" or "SMOOTH".

Returns:

self for chaining.

Example:

# Spin about the centroid at 180 deg/s for frames 1-60
pin.spin(axis=(0, 0, 1), angular_velocity=180.0)
# Spin about an absolute world-space pivot
pin.spin(axis=(0, 1, 0), center=(0, 0, 1),
         frame_start=30, frame_end=90)
scale(factor: float = 1.0, center: tuple[float, float, float] | None = None, center_mode: str | None = None, center_direction: tuple[float, float, float] | None = None, center_vertex: int | None = None, frame_start: int = 1, frame_end: int = 60, transition: str = 'LINEAR') Pinยถ

Add a scale operation to this pin.

Parameters:
  • factor โ€“ Scale factor.

  • center โ€“ Center point (for ABSOLUTE mode).

  • center_mode โ€“ "CENTROID", "ABSOLUTE", "MAX_TOWARDS", or "VERTEX". If None, inferred from other args (None center โ†’ "CENTROID").

  • center_direction โ€“ Direction for MAX_TOWARDS mode.

  • center_vertex โ€“ Vertex index for VERTEX mode.

  • frame_start โ€“ Start frame.

  • frame_end โ€“ End frame.

  • transition โ€“ "LINEAR" or "SMOOTH".

Returns:

self for chaining.

Example:

# Shrink to 50% over frames 1-60 about the centroid
pin.scale(factor=0.5, transition="SMOOTH")
torque(magnitude: float = 1.0, axis_component: str = 'PC3', flip: bool = False, frame_start: int = 1, frame_end: int = 60) Pinยถ

Add a torque operation to this pin.

Applies a rotational force around a PCA-computed axis.

Parameters:
  • magnitude โ€“ Torque in Nยทm.

  • axis_component โ€“ "PC1" (major), "PC2" (middle), or "PC3" (minor).

  • flip โ€“ Reverse torque direction.

  • frame_start โ€“ Start frame.

  • frame_end โ€“ End frame.

Returns:

self for chaining.

Example:

pin.torque(magnitude=2.0, axis_component="PC1",
           frame_start=1, frame_end=30)
move_by(delta: tuple[float, float, float] = (0, 0, 0), frame_start: int = 1, frame_end: int = 60, transition: str = 'LINEAR') Pinยถ

Ramp a translation of the pinned vertices over a frame range.

Parameters:
  • delta โ€“ (dx, dy, dz) offset.

  • frame_start โ€“ Start frame.

  • frame_end โ€“ End frame.

  • transition โ€“ "LINEAR" or "SMOOTH".

Returns:

self for chaining.

Example:

# Lift 1.0m along +Z between frames 10 and 90
pin.move_by(delta=(0, 0, 1.0),
            frame_start=10, frame_end=90,
            transition="SMOOTH")
unpin(frame: int) Pinยถ

Mark this pin to be released at the given frame.

Sets the duration on the underlying pin item so the encoder knows when to stop enforcing the pin constraint.

Parameters:

frame โ€“ Frame number at which the pin is released.

Returns:

self for chaining.

Example:

pin.move_by(delta=(0, 0, 1.0), frame_start=1, frame_end=60)
pin.unpin(frame=120)
delete() Noneยถ

Remove this pin from its group.

Raises:

ValueError โ€“ If the owning group or pin item can no longer be found (for example, after solver.clear()).

Example:

pin = group.create_pin("Cloth", "hem")
pin.delete()  # remove the pin entry from the group
class Wallยถ

Chainable builder for invisible wall colliders.

Returned by Solver.add_wall(). Keyframe frames must be strictly increasing. Every mutating method returns self.

Example:

solver.add_wall((0, 0, 0), (0, 0, 1)).param.friction = 0.5
(solver.add_wall((0, 0, 0), (0, 1, 0))
       .time(60).hold().time(61).move_to((0, 1, 0)))
property paramยถ
Type:

ColliderParam

Collider parameter proxy. See ColliderParam.

Example:

wall = solver.add_wall((0, 0, 0), (0, 0, 1))
wall.param.friction = 0.5
time(frame: int) Wallยถ

Advance the keyframe cursor.

Parameters:

frame โ€“ Target frame (must be strictly greater than the current cursor position).

Returns:

self for chaining.

Raises:

ValueError โ€“ If frame is not strictly increasing.

Example:

(solver.add_wall((0, 0, 0), (0, 0, 1))
       .time(60).move_to((0, 0, 0.5)))
hold() Wallยถ

Hold the previous position at the current cursor frame.

Returns:

self for chaining.

Example:

(solver.add_wall((0, 0, 0), (0, 0, 1))
       .time(60).hold().time(90).move_to((0, 0, 0.5)))
move_to(position) Wallยถ

Keyframe a new absolute position at the current cursor frame.

Parameters:

position โ€“ (x, y, z) world-space position.

Returns:

self for chaining.

Example:

(solver.add_wall((0, 0, 0), (0, 0, 1))
       .time(60).move_to((0, 0, 1.0)))
move_by(delta) Wallยถ

Keyframe a position offset from the previous keyframe.

Parameters:

delta โ€“ (dx, dy, dz) offset added to the previous keyframed position.

Returns:

self for chaining.

Example:

(solver.add_wall((0, 0, 0), (0, 0, 1))
       .time(60).move_by((0, 0, 0.25)))
delete() Noneยถ

Remove this wall collider from the scene.

Example:

wall = solver.add_wall((0, 0, 0), (0, 0, 1))
wall.delete()
class Sphereยถ

Chainable builder for invisible sphere colliders.

Returned by Solver.add_sphere(). Keyframe frames must be strictly increasing. Every mutating method returns self.

Example:

solver.add_sphere((0, 0, 0), 0.98).invert().hemisphere()
(solver.add_sphere((0, 0, 0), 1.0)
       .time(60).hold().time(61).radius(0.5))
property paramยถ
Type:

ColliderParam

Collider parameter proxy. See ColliderParam.

Example:

sphere = solver.add_sphere((0, 0, 0), 1.0)
sphere.param.friction = 0.3
invert() Sphereยถ

Flip the sphere inside-out so contact is on the inside surface.

Returns:

self for chaining.

Example:

solver.add_sphere((0, 0, 0), 1.0).invert()
hemisphere() Sphereยถ

Treat this collider as a hemisphere rather than a full sphere.

Returns:

self for chaining.

Example:

solver.add_sphere((0, 0, 0), 1.0).hemisphere()
time(frame: int) Sphereยถ

Advance the keyframe cursor.

Parameters:

frame โ€“ Target frame (must be strictly greater than the current cursor position).

Returns:

self for chaining.

Raises:

ValueError โ€“ If frame is not strictly increasing.

Example:

(solver.add_sphere((0, 0, 0), 1.0)
       .time(60).move_to((0, 0, 1.0)))
hold() Sphereยถ

Hold the previous position and radius at the current cursor frame.

Returns:

self for chaining.

Example:

(solver.add_sphere((0, 0, 0), 1.0)
       .time(60).hold().time(90).radius(0.5))
move_to(position) Sphereยถ

Keyframe a new absolute position at the current cursor frame.

Parameters:

position โ€“ (x, y, z) world-space position.

Returns:

self for chaining.

Example:

(solver.add_sphere((0, 0, 0), 1.0)
       .time(60).move_to((0, 0, 2.0)))
radius(r) Sphereยถ

Keyframe a new radius at the current cursor frame.

Parameters:

r โ€“ New radius.

Returns:

self for chaining.

Example:

(solver.add_sphere((0, 0, 0), 1.0)
       .time(60).radius(0.25))  # shrink over 60 frames
transform_to(position, radius) Sphereยถ

Keyframe both position and radius together.

Parameters:
  • position โ€“ (x, y, z) world-space position.

  • radius โ€“ New radius.

Returns:

self for chaining.

Example:

(solver.add_sphere((0, 0, 0), 1.0)
       .time(60).transform_to((0, 0, 1.0), 0.5))
delete() Noneยถ

Remove this sphere collider from the scene.

Example:

sphere = solver.add_sphere((0, 0, 0), 1.0)
sphere.delete()
class ColliderParamยถ

Attribute proxy for invisible-collider parameters.

Accessed via Wall.param or Sphere.param. Attribute access is whitelisted: reading or writing a name outside the whitelist raises AttributeError.

Whitelisted attributes:

  • friction: contact friction coefficient

  • contact_gap: contact gap thickness

  • thickness: wall/sphere shell thickness

  • enable_active_duration: True to limit collider lifetime

  • active_duration: number of frames the collider is active when enable_active_duration is set

Example:

wall = solver.add_wall((0, 0, 0), (0, 0, 1))
wall.param.friction = 0.5
wall.param.contact_gap = 0.002
wall.param.thickness = 0.01
wall.param.enable_active_duration = True
wall.param.active_duration = 60  # active for frames 1-60

sphere = solver.add_sphere((0, 0, 1), 0.5)
sphere.param.friction = 0.3
class Curveยถ

Builder for a multi-spline Bezier curve object.

Created via Solver.create_curve(). Each add_spline() appends one Bezier spline to the underlying curve datablock; finalize() links the resulting object into the active scene and returns it.

Pin definition is not part of this builder. Pass the control-point indices to Group.create_pin() instead, which writes the _pin_<name> custom property and registers the pin in one call.

Example:

curve = solver.create_curve("WovenCylinder", bevel_depth=3e-3)
for points, closed in strands:
    curve.add_spline(points, closed=closed)
obj = curve.finalize()

rod = solver.create_group("Strands", type="ROD")
rod.add(obj.name)
rod.create_pin(obj.name, "left", indices=left_indices)
property nameยถ
Type:

str

Object name this builder will create on finalize().

add_spline(points, *, closed: bool = False) intยถ

Append a Bezier spline with AUTO handles.

Parameters:
  • points โ€“ Iterable of (x, y, z) control-point coordinates (a NumPy array of shape (n, 3) works).

  • closed โ€“ Set True to make the spline cyclic.

Returns:

Zero-based index of the new spline within this curve. Use it with set_material().

Raises:

ValueError โ€“ If points has fewer than two coordinates.

set_material(spline_index: int, material: 'bpy.types.Material') Curveยถ

Bind a material to a spline by index.

The material is appended to the curveโ€™s slots if it isnโ€™t already present. Pre-existing slots are reused so repeated calls with the same material donโ€™t grow the slot list.

Parameters:
  • spline_index โ€“ Index returned by add_spline().

  • material โ€“ An existing bpy.types.Material. Create it with bpy.data.materials.new(...) before calling.

Returns:

self for chaining.

Raises:

IndexError โ€“ If spline_index is out of range.

finalize() 'bpy.types.Object'ยถ

Create the bpy.types.Object, link it to the scene, and return it.

Raises:

RuntimeError โ€“ If called more than once on the same builder.