🤖 MCP Tool Reference#
Every tool listed here is callable over the MCP Streamable HTTP server (POST /mcp with tools/call), and equivalently via bpy.ops.zozo_contact_solver.<tool_name>() inside Blender.
See 🤖 MCP Server for protocol, transport, and security notes.
Categories:
Connection (15)
Group (25)
Object operations (41)
Mesh cleaning (9)
Simulation (18)
Scene (16)
Remote (8)
Console (3)
Debug (8)
Blender (10)
Material Maps (6)
Presets (10)
Statistics (3)
Connection#
- connect_ssh(host: str, username: str, key_path: str, remote_path: str, port: int = 22, container: str | None = None, proxy_jump: str | None = None)#
Establish SSH connection to remote server for contact solver.
- Parameters:
host – SSH hostname or IP address
username – SSH username
key_path – Path to SSH private key
remote_path – Remote working directory path
port – SSH port
container – Docker container name (optional)
proxy_jump – Jump host(s) to tunnel through, as ssh -J takes them, “[user@]host[:port]” comma separated (optional). Left unset, the ProxyJump entry in ~/.ssh/config for the host applies.
- connect_docker(container: str, path: str, port: int = DEFAULT_SERVER_PORT)#
Establish Docker connection for contact solver.
- Parameters:
container – Docker container name
path – Working directory path in container
port – Port the solver server listens on inside the container. Must be within the range the port field itself accepts.
- connect_local(path: str)#
Establish local connection for contact solver.
- Parameters:
path – Local working directory path
- connect_win_native(path: str, port: int = DEFAULT_SERVER_PORT)#
Establish Windows native connection for contact solver.
- Parameters:
path – Path to the Windows native build or distribution directory
port – Port for the solver server
- disconnect()#
Disconnect from the solver host, or cancel a connection still in progress.
- connect()#
Connect using current connection settings, mimicking the connect button press.
- start_remote_server()#
Start the remote server process.
- stop_remote_server()#
Stop the remote server process.
- is_remote_server_running()#
Check if remote server is running.
- get_remote_status()#
Get detailed remote server status.
- update_remote_status()#
Update remote server status.
- get_connection_info()#
Get detailed connection information.
- list_solver_gpus()#
List the GPUs on the solver host, and which one is selected.
The list is a cache filled by refresh_solver_gpus, which reads it from the solver host over the active connection. Before the first refresh the list is empty, which reports as probed: false rather than as a host with no GPUs.
A selection is stored as both an index and a stable UUID, and the UUID wins: a .blend saved against one host and opened against another must not silently resolve to a different physical device.
- refresh_solver_gpus()#
Re-read the GPU list from the solver host.
Requires an active connection: the list is produced by a command run on the host, so there is nowhere to read it from otherwise. The refreshed list is available from list_solver_gpus.
- set_solver_gpu(uuid: str | None = None, index: int | None = None)#
Choose which GPU on the solver host runs the simulation.
Pass uuid to name a device stably, which is what the add-on stores and prefers. index alone selects by CUDA index and is only reliable while the host’s device set does not change. Passing neither clears the selection back to automatic.
The selection is validated against the cached device list when one has been probed; with no list there is no evidence to contradict the request, so it is honored as given.
- Parameters:
uuid – Stable device UUID, from list_solver_gpus
index – CUDA device index, used when no uuid is given
Group#
- create_group(name: str = '', type: str = 'SOLID')#
Create a new dynamics group.
- Parameters:
name – Display name for the new group (optional)
type – Group type (SOLID, SHELL, ROD, STATIC, PDRD, SAND)
- delete_group(group_uuid: str)#
Delete a specific group by UUID.
- Parameters:
group_uuid – UUID of group to delete
- delete_all_groups()#
Delete all active groups.
- duplicate_group(group_uuid: str)#
Duplicate a dynamics group (material params only, no objects or pins).
- Parameters:
group_uuid – UUID of the source group to duplicate
- rename_group(group_uuid: str, name: str)#
Rename a dynamics group.
- Parameters:
group_uuid – UUID of group to rename
name – New display name (empty string falls back to ‘Group N’)
- bake_group_animation(group_uuid: str, object_name: str)#
Bake simulated animation for one object in a group to Blender keyframes.
The object is removed from the group and keeps its baked animation.
- Parameters:
group_uuid – UUID of group containing the object
object_name – Name of the object to bake
- bake_group_single_frame(group_uuid: str, object_name: str)#
Bake the current frame as frame 1 for one object and drop it from the group.
- Parameters:
group_uuid – UUID of group containing the object
object_name – Name of the object to bake
- set_object_included(group_uuid: str, object_name: str, included: bool)#
Toggle whether an assigned object is included in the simulation.
- Parameters:
group_uuid – UUID of the group
object_name – Name of the assigned object
included – True to include, False to mute
- get_group(group_uuid: str)#
Get one active group by UUID.
- Parameters:
group_uuid – UUID of group
- get_active_groups()#
Get list of all active groups with their properties.
- add_objects_to_group(group_uuid: str, object_names: list[str])#
Add objects to a dynamics group.
- Parameters:
group_uuid – UUID of target group
object_names – List of object names to add
- remove_object_from_group(group_uuid: str, object_name: str)#
Remove an object from a dynamics group.
- Parameters:
group_uuid – UUID of group
object_name – Name of object to remove
- remove_all_objects_from_group(group_uuid: str)#
Remove all objects from a dynamics group.
- Parameters:
group_uuid – UUID of group to clear
- get_group_objects(group_uuid: str)#
Get the objects assigned to a dynamics group, with their own state.
Every per-object field the object tools write is reported: “included” from set_object_included, “locks” from set_object_locks, “pdrd_hinge” from set_pdrd_hinge, and “tet” from set_object_tet_settings. The three counts say how many rows each per-object list holds; read the rows with list_static_ops, list_velocity_keyframes and list_collision_windows.
Material parameters are per GROUP, not per object, and are reported by get_group_material_properties instead.
A field is stored on every assigned object whatever the group type, and the scene build reads it only where it applies: a hinge on PDRD, a tetrahedralizer setting on SOLID, a bending reference on SHELL and ROD. So a value reported for a type that does not use it is stored and unread.
“bend_reference” is this object’s own bending rest angle source, which replaces the group’s for that object, and which the scene build reads only while the group’s bend_rest_from_reference is on. Its object is stored by UUID: “object_name” is what that UUID resolves to in the scene now, and is null when it resolves to nothing, which is a reference whose object has left the scene.
- Parameters:
group_uuid – UUID of group
- set_group_type(group_uuid: str, type: str)#
Set the type of a dynamics group.
- Parameters:
group_uuid – UUID of group
type – Group type (SOLID, SHELL, ROD, STATIC, PDRD, SAND)
- list_vertex_groups(object_name: str)#
List a mesh’s vertex groups and how many vertices each one holds.
A mesh pin names a vertex group that already exists on the object, so this reports the names add_pin_vertex_group accepts and create_vertex_group will refuse as duplicates.
vertex_countcounts the vertices assigned to the group at any weight; a group holding zero vertices pins nothing.Only a MESH carries vertex groups. A curve’s pinned control points live on the curve object and are reported by list_pins once they are pinned.
Refuses an object that is in Edit Mode. That session holds the geometry and the weights in a BMesh the mesh datablock does not receive until the mode is left, so the counts would describe the mesh as it stood before the session. Leave Edit Mode and call again.
- Parameters:
object_name – Name of the mesh object to inspect.
- create_vertex_group(object_name: str, name: str, indices: list[int], weight: float = 1.0)#
Create a vertex group on a mesh and assign the given vertices to it.
This is the membership a mesh pin names: create the group here, then pass “object_name::name” to add_pin_vertex_group to pin it. Call list_vertex_groups first to see which names the object already carries.
The object does not have to be the active one and Blender can be in any mode. An object in Edit Mode is taken to Object Mode for the write and put back, which also writes the edit session to the mesh, so the indices below address the geometry the caller can see.
Fails before creating anything, leaving Blender as it was found, when the object is not a MESH, when it is library-linked, when indices is empty, when any index is outside the mesh, or when the object already carries a group of that name. An existing group can be driven by an armature or a modifier, so it is never overwritten.
- Parameters:
object_name – Name of the mesh object to create the vertex group on.
name – Name for the new vertex group; must not already exist on the object.
indices – Vertex indices to assign, each in 0 to vertex_count - 1. Repeated indices are assigned once.
weight – Weight for every assigned vertex, in [0, 1]. Defaults to 1.0, which is what the panel’s Create button assigns.
- add_pin_vertex_group(group_uuid: str, vertex_group_identifier: str, indices: list[int] | None = None)#
Add a vertex group to the pin list of a dynamics group.
For a MESH, the vertex group the identifier names has to exist on the object already: create it with create_vertex_group, or read what the object carries with list_vertex_groups. Passing ‘indices’ for a mesh is refused, because the vertex group holds the membership, not this call.
For a CURVE, which has no vertex groups, ‘indices’ is how the pinned control points are defined: they are written onto the curve as “_pin_<vertex_group_name>” and pinned in the same call.
- Parameters:
group_uuid – UUID of group
vertex_group_identifier – Identifier in format “object_name::vertex_group_name”
indices – Curve control-point indices, for CURVE objects only
- remove_pin_vertex_group(group_uuid: str, vertex_group_identifier: str)#
Remove a vertex group from the pin list of a dynamics group.
- Parameters:
group_uuid – UUID of group
vertex_group_identifier – Identifier in format “object_name::vertex_group_name”
- list_pins(group_uuid: str)#
List all pins in a dynamics group.
- Parameters:
group_uuid – UUID of group
- rename_pin_vertex_group(group_uuid: str, vertex_group_identifier: str, new_name: str)#
Rename the vertex group a pin names, on the object and in the pin list.
This renames the membership as well as the pin entry: on a mesh the object’s vertex group is renamed, and on a curve the “_pin_<name>” property holding the pinned control points is. Anything else that names that vertex group, an armature or a modifier for instance, refers to it by name and stops finding it, so rename a group only the solver pin uses.
The object keeps its name; only the vertex group half of the identifier changes. Refused before anything is renamed when the new name is empty, when it is the name the pin already has, when the object already carries a vertex group (on a curve, a pin property) under that name, or when the name is longer in UTF-8 bytes than a mesh vertex group name field holds, since Blender would in the last two cases store a name other than the one asked for.
- Parameters:
group_uuid – UUID of the group holding the pin.
vertex_group_identifier – The pin to rename, in the format “object_name::vertex_group_name”.
new_name – New name for the vertex group half of the identifier.
- move_pin_vertex_group(group_uuid: str, vertex_group_identifier: str, direction: str)#
Move a pin one place up or down its group’s pin list.
Pin order decides what two pins of one group do where they hold the same vertex: the scene build writes each pin’s settings in list order, so for a shared vertex the pin lower in the list is the one whose duration, pull and operations that vertex takes. Order says nothing about pins that share no vertex.
One place per call. list_pins reports the pins in list order, so the position of a pin in that array is the position this moves it from. A pin already at the top cannot move up and one already at the bottom cannot move down; either is refused rather than reported as a move that did nothing.
- Parameters:
group_uuid – UUID of the group holding the pin.
vertex_group_identifier – The pin to move, in the format “object_name::vertex_group_name”.
direction – “UP” to move it one place toward the start of the list, “DOWN” to move it one place toward the end.
- set_group_overlay_color(group_uuid: str, r: float, g: float, b: float, a: float = 1.0)#
Set the viewport overlay color for a dynamics group.
- Parameters:
group_uuid – UUID of group
r – Red channel in [0, 1]
g – Green channel in [0, 1]
b – Blue channel in [0, 1]
a – Alpha channel in [0, 1]
- get_group_material_properties(group_uuid: str)#
Report every material parameter a group accepts, with its value.
Which parameters a group carries is decided by its object_type, and the set reported here is exactly the set set_group_material_properties accepts for this group, so a name absent from this report is refused by that tool. A parameter another type carries is reachable only by retyping the group with set_group_type first.
Each entry carries the current value, the add-on default, the description the panel shows for it (or, where the property carries none, the descriptions its own options carry), and the limits the property enforces: min and max for a number, the accepted identifiers for an enum. set_group_material_properties refuses a value outside those limits instead of storing a clamp of it, so a value within them is one that tool stores as written.
An enum reports only the identifiers its picker offers. A group loaded from a .blend holding a withdrawn identifier reports it as the value, with “value_withdrawn”: true and the identifier absent from “options”; the scene build substitutes a supported identifier for it, so set the parameter to one of the offered identifiers to decide what the solver runs.
The values are the authored ones, not what the solver derives from them. Contact distances in particular are stored as an absolute pair (contact_gap, contact_offset) and a relative pair (contact_gap_rat, contact_offset_rat), and both pairs are reported whichever one use_group_bounding_box_diagonal currently selects.
Per-object state (inclusion, locks, hinge, bending reference, tetrahedralizer) is reported by get_group_objects, and a parameter driven across the surface by a weight map is reported by list_material_maps.
- Parameters:
group_uuid – UUID of the group to report.
- set_group_material_properties(group_uuid: str, properties: dict)#
Set material properties for a dynamics group.
A value the property itself cannot hold is refused, and nothing is written when one is: a number past the property’s own minimum or maximum, or an enum identifier its picker does not offer. Blender stores the nearest limit for the first and keeps the second for the scene build to substitute for, so either would leave the group holding something other than what was asked for while this call reported success. get_group_material_properties reports the range and the accepted identifiers of every parameter this tool takes.
- Parameters:
group_uuid – UUID of target group
properties – Dict of property_name -> value mappings
Supported properties by group type:
SHELL: enable_strain_limit, strain_limit_percent, shell_density, shell_young_modulus, shell_poisson_ratio, shell_model, bend, bend_warp, bend_weft, shrink_x, shrink_y, deformation_damping, bending_damping, young_mod_density_normalized, friction, enable_inflate, inflate_pressure, stitch_stiffness
SOLID: solid_density, solid_young_modulus, solid_poisson_ratio, solid_model, shrink, deformation_damping, young_mod_density_normalized, friction, stitch_stiffness
ROD: rod_density, rod_young_modulus, rod_model, deformation_damping, bending_damping, young_mod_density_normalized, friction, bend, length_factor, enable_strain_limit, strain_limit_percent, stitch_stiffness
PDRD: pdrd_density, friction, stitch_stiffness (the hinge joint is per-object; use the set_pdrd_hinge tool)
SAND: sand_grain_radius, sand_particle_mass, sand_friction (faceless granular body of loose grain-center vertices)
STATIC: friction, enable_soft_constraint, soft_constraint_stiffness (a collider tracks its animation exactly unless soft constraints are on, which holds it with springs of that stiffness so contact can push it off its path)
Rayleigh damping (deformation_damping on Solid/Shell/Rod, bending_damping on Shell/Rod only) and young_mod_density_normalized (interpret Young’s modulus as true pascals when False) are per-group. Solid has no bending term, so bending_damping is rejected for Solid. PDRD groups carry only density, friction, contact, and stitch settings.
length_factor (Rod only) multiplies every rod edge’s rest length, so below 1.0 it tensions a pinned rod and above 1.0 it slackens it; mass is taken from the drawn length and does not move with it. Rod bending stiffness is normalized against that same rest length and varies as its inverse square, so halving length_factor also makes the rod about four times stiffer in bending.
Intersection allowances (accepted on every group type: SOLID, SHELL, ROD, PDRD, SAND, STATIC). The value is applied to every object assigned to the group, and self versus inter-object is decided per Blender object, not per group:
allow_self_intersection: an overlap of one object with itself is simulated instead of reported, so a run starts and keeps going through a pose that object is tangled in. An overlap between two objects assigned to the same group is an inter-object pair, which this key does not cover.
allow_inter_object_intersection: the same for an overlap between two different objects, including two objects of this group. Either side is enough, so setting it on a garment also covers the body it is fitted to.
On a STATIC group both keys reach the solver whenever the collider is part of the solved scene, which covers an animated collider, a soft-constrained one, and one named as a cross-stitch endpoint: each of those decodes to a pin shell whose vertices carry the policy. A collider that is none of them stays a contact-only collision mesh, its vertices carry no object id and an empty policy, and a pair involving it is tolerated only when the opposing dynamic side opts in. Contact and CCD are unaffected; only the report is suppressed.
Contact properties (mutually exclusive modes):
Absolute mode: contact_gap, contact_offset (sets use_group_bounding_box_diagonal=False)
Relative mode: contact_gap_rat, contact_offset_rat (sets use_group_bounding_box_diagonal=True)
- Returns:
Dict with success message and properties set
Object operations#
- set_pin_settings(group_uuid: str, vertex_group_identifier: str, included: bool | None = None, use_pin_duration: bool | None = None, pin_duration: int | None = None, use_pull: bool | None = None, pull_strength: float | None = None, fix_weight_threshold: float | None = None, track_rest_pose_deformation: bool | None = None, allow_intersection: bool | None = None)#
Set per-pin runtime settings: inclusion, duration, pull, and three conditional fields.
Every argument is optional and an omitted one leaves that field as it is.
Three of the fields are read only under a condition, and the handler refuses a write that would land where nothing reads it:
fix_weight_thresholdis SOLID only, and splits a hard pin’s diffused weights into a hard kinematic shell and a soft-pulled skirt. A non-SOLID group is refused. A pull pin ignores it (the pin holds only as hard as its own force), so setting it alongsideuse_pullis accepted and takes effect if the pin is switched off pull later.track_rest_pose_deformationneeds a SOLID group, a pin covering every vertex of its mesh, and a captured deformation on that pin. Turning it on without all three is refused, naming the one that is missing. Turning it off is always accepted.allow_intersectionsuppresses the overlap REPORT for geometry this pin holds entirely (every corner of a face, both ends of a rod segment). Contact, CCD and the line search are unchanged, so an overlap is tolerated, not resolved.
- Parameters:
group_uuid – UUID of group
vertex_group_identifier – Pin id in ‘object::vertex_group’ form
included – Include this pin in the simulation
use_pin_duration – Enable per-pin active duration
pin_duration – Number of frames the pin is active
use_pull – Use pull force instead of hard constraint
pull_strength – Pull force strength
fix_weight_threshold – SOLID hard pin only, 0.0 to 1.0. Tet vertices whose diffused pin weight reaches this are held as hard kinematic fixes and lower-weight ones stay soft-pulled, so a lower value holds more of the pinned region rigidly
track_rest_pose_deformation – Drive a time-varying rest pose from the captured deformation, so the body settles into the captured shape instead of straining against it
allow_intersection – Accept an overlap of the geometry this pin holds instead of stopping the simulation
- add_pin_operation(group_uuid: str, vertex_group_identifier: str, op_type: str, frame_start: int | None = None, frame_end: int | None = None, transition: str | None = None, delta: list[float] | None = None, spin_axis: list[float] | None = None, spin_angular_velocity: float | None = None, spin_flip: bool | None = None, spin_center: list[float] | None = None, spin_center_mode: str | None = None, spin_center_vertex: int | None = None, spin_center_direction: list[float] | None = None, scale_factor: float | None = None, scale_center: list[float] | None = None, scale_center_mode: str | None = None, scale_center_vertex: int | None = None, scale_center_direction: list[float] | None = None, torque_axis_component: str | None = None, torque_magnitude: float | None = None, torque_flip: bool | None = None)#
Append an operation to a pin’s operation list.
TORQUE cannot coexist with other op types on the same pin.
- Parameters:
group_uuid – UUID of group
vertex_group_identifier – Pin id in ‘object::vertex_group’ form
op_type – One of MOVE_BY, SPIN, SCALE, TORQUE
frame_start – First frame the op is active
frame_end – Last frame the op is active
transition – LINEAR or SMOOTH
delta – [x, y, z] translation for MOVE_BY (meters)
spin_axis – [x, y, z] rotation axis for SPIN
spin_angular_velocity – Degrees per second (SPIN)
spin_flip – Reverse spin direction
spin_center – [x, y, z] fixed center for SPIN (ABSOLUTE mode only)
spin_center_mode – CENTROID, ABSOLUTE, MAX_TOWARDS, or VERTEX
spin_center_vertex – Vertex index for SPIN VERTEX mode
spin_center_direction – [x, y, z] direction vector for SPIN MAX_TOWARDS mode
scale_factor – Scale multiplier for SCALE
scale_center – [x, y, z] fixed center for SCALE (ABSOLUTE mode only)
scale_center_mode – CENTROID, ABSOLUTE, MAX_TOWARDS, or VERTEX
scale_center_vertex – Vertex index for SCALE VERTEX mode
scale_center_direction – [x, y, z] direction vector for SCALE MAX_TOWARDS mode
torque_axis_component – PC1, PC2, or PC3 (principal axis)
torque_magnitude – Torque in newton-meters
torque_flip – Reverse torque direction
- remove_pin_operation(group_uuid: str, vertex_group_identifier: str, index: int)#
Remove a pin operation by index.
- Parameters:
group_uuid – UUID of group
vertex_group_identifier – Pin id in ‘object::vertex_group’ form
index – Zero-based index into the pin’s operations list
- set_pin_operation(group_uuid: str, vertex_group_identifier: str, index: int, frame_start: int | None = None, frame_end: int | None = None, transition: str | None = None, delta: list[float] | None = None, spin_axis: list[float] | None = None, spin_angular_velocity: float | None = None, spin_flip: bool | None = None, spin_center: list[float] | None = None, spin_center_mode: str | None = None, spin_center_vertex: int | None = None, spin_center_direction: list[float] | None = None, scale_factor: float | None = None, scale_center: list[float] | None = None, scale_center_mode: str | None = None, scale_center_vertex: int | None = None, scale_center_direction: list[float] | None = None, torque_axis_component: str | None = None, torque_magnitude: float | None = None, torque_flip: bool | None = None)#
Change fields on one operation a pin already carries, addressed by its index.
Every field argument is optional and an omitted one is left as it is, so one number can be changed without restating the rest of the entry. Editing in place is also what preserves the LIST ORDER: the operations are shipped to the solver in list order and compose in that order, while adding one puts it at the head, so removing an entry and adding it back to change a field moves it to the front and changes the motion the pin performs.
The op type is fixed when the entry is added. A field belonging to another op type is refused rather than written where nothing reads it, so turn a MOVE_BY into a SPIN by removing it and adding the SPIN in its place. An entry on a keyframed pin holds no editable field and is refused as well.
Every named field is checked before any of them is written, so a call answered with an error leaves the entry holding what it held before.
- Parameters:
group_uuid – UUID of group
vertex_group_identifier – Pin id in ‘object::vertex_group’ form
index – Zero-based index into the pin’s operations list, in the order list_pin_operations reports
frame_start – First frame the op is active
frame_end – Last frame the op is active
transition – LINEAR or SMOOTH
delta – [x, y, z] translation for MOVE_BY (meters)
spin_axis – [x, y, z] rotation axis for SPIN
spin_angular_velocity – Degrees per second (SPIN)
spin_flip – Reverse spin direction
spin_center – [x, y, z] fixed center for SPIN (ABSOLUTE mode only)
spin_center_mode – CENTROID, ABSOLUTE, MAX_TOWARDS, or VERTEX
spin_center_vertex – Vertex index for SPIN VERTEX mode
spin_center_direction – [x, y, z] direction vector for SPIN MAX_TOWARDS mode
scale_factor – Scale multiplier for SCALE
scale_center – [x, y, z] fixed center for SCALE (ABSOLUTE mode only)
scale_center_mode – CENTROID, ABSOLUTE, MAX_TOWARDS, or VERTEX
scale_center_vertex – Vertex index for SCALE VERTEX mode
scale_center_direction – [x, y, z] direction vector for SCALE MAX_TOWARDS mode
torque_axis_component – PC1, PC2, or PC3 (principal axis)
torque_magnitude – Torque in newton-meters
torque_flip – Reverse torque direction
- move_pin_operation(group_uuid: str, vertex_group_identifier: str, index: int, new_index: int)#
Move one of a pin’s operations to another position in its list.
The order is semantic rather than presentational: the operations are shipped to the solver in list order and compose in that order, so moving an entry changes the motion the pin performs. Index 0 is the head of the list, and the entry that follows composes on top of what precedes it.
Both positions must address an entry that exists, and they must differ.
- Parameters:
group_uuid – UUID of group
vertex_group_identifier – Pin id in ‘object::vertex_group’ form
index – Zero-based index of the operation to move
new_index – Zero-based position to move it to
- list_pin_operations(group_uuid: str, vertex_group_identifier: str)#
List operations attached to a pin.
- Parameters:
group_uuid – UUID of group
vertex_group_identifier – Pin id in ‘object::vertex_group’ form
- clear_pin_operations(group_uuid: str, vertex_group_identifier: str)#
Remove every operation from a pin.
- Parameters:
group_uuid – UUID of group
vertex_group_identifier – Pin id in ‘object::vertex_group’ form
- add_pin_keyframe(group_uuid: str, vertex_group_identifier: str)#
Key the positions of a pin’s vertices at the scene’s current frame.
The key records the positions the mesh holds right now, at the frame the scene is on, so move the timeline and pose the mesh before calling; the frame that was keyed comes back in the result. That frame must be 1 or later, since a key below frame 1 is dropped when the pin track is read. Call it once per pose to build the track. The keys are ordinary Blender keyframes on the mesh, set to LINEAR interpolation to match how the solver reads a sparse pin track, and the Dope Sheet retimes or deletes them like any other key.
A pin takes its motion from EITHER the parametric operations (add_pin_operation) OR keyframes, never both. A pin that already carries Move/Spin/Scale/Torque operations is therefore refused here, the mirror of add_pin_operation refusing a keyframed pin. A pin holding a captured deformation is refused too: the capture wins at encode time, so keys written on top of it would never be read.
- Parameters:
group_uuid – UUID of the group containing the pin
vertex_group_identifier – Pin id in ‘object::vertex_group’ form
- delete_pin_keyframes(group_uuid: str, vertex_group_identifier: str)#
Remove the keyframed motion of a pin, at every frame it was keyed on.
This deletes the vertex position curves add_pin_keyframe wrote and drops the marker that records the pin as keyframed, which is what frees the pin to take parametric operations again. There is no per-frame form: the whole track goes, so retime or delete single keys in the Dope Sheet instead when that is what you want.
The curves are addressed by mesh, not by pin, so a second pin on the same OBJECT loses its keys in the same call.
A pin holding a captured deformation is refused. The marker op this drops is the same one a capture relies on to be encoded at all, so removing it would leave the capture stored on the pin and no longer driving it. clear_pin_deformation drops the cache and the marker together, which is how a captured pin is freed.
- Parameters:
group_uuid – UUID of the group containing the pin
vertex_group_identifier – Pin id in ‘object::vertex_group’ form
- add_static_op(group_uuid: str, object_name: str, op_type: str, frame_start: int | None = None, frame_end: int | None = None, transition: str | None = None, delta: list[float] | None = None, spin_axis: list[float] | None = None, spin_angular_velocity: float | None = None, scale_factor: float | None = None)#
Add a move/spin/scale op to a static-moving object.
Only valid on groups of type STATIC.
- Parameters:
group_uuid – UUID of STATIC group
object_name – Name of the assigned object
op_type – One of MOVE_BY, SPIN, SCALE
frame_start – First frame the op is active
frame_end – Last frame the op is active
transition – LINEAR or SMOOTH
delta – [x, y, z] translation (MOVE_BY)
spin_axis – [x, y, z] rotation axis (SPIN)
spin_angular_velocity – Degrees per second (SPIN)
scale_factor – Scale multiplier (SCALE)
- remove_static_op(group_uuid: str, object_name: str, index: int)#
Remove a static op by index.
- Parameters:
group_uuid – UUID of STATIC group
object_name – Name of the assigned object
index – Zero-based index into the object’s static_ops list
- set_static_op(group_uuid: str, object_name: str, index: int, frame_start: int | None = None, frame_end: int | None = None, transition: str | None = None, delta: list[float] | None = None, spin_axis: list[float] | None = None, spin_angular_velocity: float | None = None, scale_factor: float | None = None)#
Change fields on one static op an object already carries, addressed by its index.
Every field argument is optional and an omitted one is left as it is, so one number can be changed without restating the rest of the entry. Editing in place is also what preserves the LIST ORDER: the ops are shipped to the solver in list order and compose in that order, while adding one puts it at the head, so removing an entry and adding it back to change a field moves it to the front and changes the motion of the object.
The op type is fixed when the entry is added, and a field belonging to another op type is refused rather than written where nothing reads it. Every named field is checked before any of them is written, so a call answered with an error leaves the entry holding what it held before.
- Parameters:
group_uuid – UUID of STATIC group
object_name – Name of the assigned object
index – Zero-based index into the object’s static_ops list, in the order list_static_ops reports
frame_start – First frame the op is active
frame_end – Last frame the op is active
transition – LINEAR or SMOOTH
delta – [x, y, z] translation (MOVE_BY)
spin_axis – [x, y, z] rotation axis (SPIN)
spin_angular_velocity – Degrees per second (SPIN)
scale_factor – Scale multiplier (SCALE)
- move_static_op(group_uuid: str, object_name: str, index: int, new_index: int)#
Move one of an object’s static ops to another position in its list.
The order is semantic rather than presentational: the ops are shipped to the solver in list order and compose in that order, so moving an entry changes the motion the object performs. Index 0 is the head of the list, and the entry that follows composes on top of what precedes it.
Both positions must address an entry that exists, and they must differ.
- Parameters:
group_uuid – UUID of STATIC group
object_name – Name of the assigned object
index – Zero-based index of the static op to move
new_index – Zero-based position to move it to
- list_static_ops(group_uuid: str, object_name: str)#
List static ops attached to an assigned object.
- Parameters:
group_uuid – UUID of STATIC group
object_name – Name of the assigned object
- clear_static_ops(group_uuid: str, object_name: str)#
Remove all static ops from an assigned object.
- Parameters:
group_uuid – UUID of STATIC group
object_name – Name of the assigned object
- set_pdrd_hinge(group_uuid: str, object_name: str, enable: bool = True, pca_axis: int = 2)#
Pin a PDRD body as a hinge (per object).
Locks the body’s position and restricts its rotation to one principal (PCA) axis of its rest shape, the building block for gears. The group must be of type PDRD. Per-object, so each body in a group can be hinged on its own axle.
- Parameters:
group_uuid – UUID of the PDRD group
object_name – Name of the assigned object
enable – Pin the body (True) or release it so it moves freely (False)
pca_axis – Free axle: 0 (largest extent), 1 (middle), 2 (thinnest, the usual axle for a flat gear or disk)
- set_object_locks(group_uuid: str, object_name: str, lock_translation_enable: bool | None = None, lock_translation_all: bool | None = None, lock_translation_axis: list[float] | None = None, lock_rotation_enable: bool | None = None, lock_rotation_all: bool | None = None, lock_rotation_axis: list[float] | None = None, lock_rotation_prohibit_axis: bool | None = None)#
Lock an object’s rigid translation, its rigid rotation, or both.
Lock Translation constrains the object’s mass-weighted center of mass to a fixed world-space line through its initial position; Lock Rotation restricts its mass-weighted best-fit rigid rotation to a fixed world-space axis. Deformation stays free under either, and the two are independent booleans on the same object: either, both or neither may be enabled. Both are exact constraints on the Newton direction rather than penalty springs, so there is no stiffness to tune.
Per object, and available on the dynamic group types (SOLID, SHELL, ROD, PDRD, SAND). A STATIC group is refused, since the encoder ships no lock for one. A lock also reaches the solver only for an object that is included in its group.
Every argument is optional and an omitted one leaves that field as it is. The MODE carries the enable bit, not the axis: lock_translation_all and lock_rotation_all saturate their lock to all three axes and stop the axis being read, so a zero axis is correct under either. For the per-axis mode the axis must be non-zero and finite, and a call that would leave an enabled per-axis lock with a zero axis is refused. That is decided on the state the call results in, so an axis and its mode can be set together in one call in either order.
- Parameters:
group_uuid – UUID of the group containing the object
object_name – Name of the assigned object in the group
lock_translation_enable – Constrain the center of mass (True) or let it move freely (False)
lock_translation_all – Pin the center of mass to its initial point instead of letting it slide along the translation axis
lock_translation_axis – World-space direction [x, y, z] of the line the center of mass may move along. Direction only, normalized by the encoder
lock_rotation_enable – Restrict the best-fit rigid rotation (True) or leave it free (False)
lock_rotation_all – Forbid net rotation about every axis instead of about the rotation axis alone
lock_rotation_axis – World-space rotation axis [x, y, z]. Direction only, normalized by the encoder
lock_rotation_prohibit_axis – False: rotation about the rotation axis is the object’s only rotational freedom. True: rotation about that axis is the one thing forbidden, and the perpendicular plane stays free
- set_bend_reference(group_uuid: str, object_name: str, reference_object_name: str, enable: bool | None = None)#
Point one assigned object’s bending rest angle at a reference object.
A reference is a topological COPY of the object whose vertices were moved: the same vertex count and the same connectivity (faces for a SHELL, edges for a ROD), with only positions differing. Its modifiers and geometry nodes are evaluated before the comparison, so a copy shaped by a modifier is a valid reference. A curve rod is compared at control-point level instead, which is how a curve rod is shipped, and a curve modifier is not sampled there. Anything that fails the comparison is refused here, naming the mismatch, rather than at scene build.
The group’s own bend_rest_from_reference flag is what makes the group read a reference at all, so it has to be on before a reference can be set; turn it on with set_group_material_properties. Only SHELL and ROD groups carry that flag.
Pass an empty reference_object_name to clear the reference, which also stops this object reading one. Clearing is accepted whatever the group flag holds, so a stale reference can always be taken off.
- Parameters:
group_uuid – UUID of the SHELL or ROD group
object_name – Name of the assigned object whose rest angle comes from the reference
reference_object_name – Name of the reference object, or “” to clear the reference this object holds
enable – Whether this object reads its reference. Defaults to True when a reference is given and False when one is cleared, so it is worth naming only to record a reference without using it yet
- add_velocity_keyframe(group_uuid: str, object_name: str, frame: int, direction: list[float], speed: float, angular_axis: 'int | str' = 'PC3', angular_speed: float = 0.0, angular_axis_custom: list[float] | None = None, enable_translational: bool = True, enable_angular: bool | None = None)#
Add a velocity keyframe at the given frame for an assigned object.
- Parameters:
group_uuid – UUID of group
object_name – Name of the assigned object
frame – Blender frame number (>= 1)
direction – [x, y, z] direction vector (normalized at runtime)
speed – Velocity magnitude (m/s)
angular_axis – Axis to spin about (solid/shell/PDRD). One of “PC1”/”PC2”/”PC3” (principal axes, resolved dynamically from the geometry), “X”/”Y”/”Z” (fixed world axes), or “CUSTOM” (the angular_axis_custom vector). Ints 0/1/2 map to PC1/PC2/PC3. Ignored when angular_speed == 0.
angular_speed – Signed spin speed in degrees per second (0 = no spin).
angular_axis_custom – World [x, y, z] axis used when angular_axis == “CUSTOM” (normalized before use). Defaults to [0, 0, 1].
enable_translational – Overwrite the translational velocity at this frame (False = leave translation alone, e.g. a pure spin).
enable_angular – Overwrite the angular velocity at this frame. Defaults to True when angular_speed is non-zero, else False.
- remove_velocity_keyframe(group_uuid: str, object_name: str, frame: int)#
Remove the velocity keyframe at the given frame.
- Parameters:
group_uuid – UUID of group
object_name – Name of the assigned object
frame – Frame number of the keyframe to remove
- set_velocity_keyframe(group_uuid: str, object_name: str, index: int, frame: int | None = None, direction: list[float] | None = None, speed: float | None = None, angular_axis: 'int | str | None' = None, angular_speed: float | None = None, angular_axis_custom: list[float] | None = None, enable_translational: bool | None = None, enable_angular: bool | None = None)#
Change fields on one velocity keyframe an object already carries, addressed by its index.
Every field argument is optional and an omitted one is left as it is, so a keyframe’s speed can be changed without restating its direction and its two enable gates.
The frame may be changed as well, which retimes the keyframe in place. The list is held in frame order, so the entry can land at a different index, and the index it ends up at comes back as new_index. A frame another keyframe on the same object already occupies is refused, since a frame carries at most one velocity keyframe.
- Parameters:
group_uuid – UUID of group
object_name – Name of the assigned object
index – Zero-based index into the object’s velocity keyframe list, in the frame order list_velocity_keyframes reports
frame – Blender frame number (>= 1) to retime this keyframe to
direction – [x, y, z] direction vector (normalized at runtime)
speed – Velocity magnitude in m/s, zero or greater
angular_axis – Axis to spin about (solid/shell/PDRD). One of “PC1”/”PC2”/”PC3” (principal axes, resolved dynamically from the geometry), “X”/”Y”/”Z” (fixed world axes), or “CUSTOM” (the angular_axis_custom vector). Ints 0/1/2 map to PC1/PC2/PC3
angular_speed – Signed spin speed in degrees per second (0 = no spin)
angular_axis_custom – World [x, y, z] axis used when angular_axis is “CUSTOM” (normalized before use)
enable_translational – Overwrite the translational velocity at this frame (False leaves translation alone, for a pure spin)
enable_angular – Overwrite the angular velocity at this frame
- list_velocity_keyframes(group_uuid: str, object_name: str)#
List velocity keyframes for an assigned object.
- Parameters:
group_uuid – UUID of group
object_name – Name of the assigned object
- clear_velocity_keyframes(group_uuid: str, object_name: str)#
Clear all velocity keyframes on an assigned object.
- Parameters:
group_uuid – UUID of group
object_name – Name of the assigned object
- set_use_collision_windows(group_uuid: str, enable: bool)#
Toggle the per-object collision-window feature for a group.
- Parameters:
group_uuid – UUID of group
enable – True to enable, False to disable
- add_collision_window(group_uuid: str, object_name: str, frame_start: int, frame_end: int)#
Add a collision-active window on an assigned object.
- Parameters:
group_uuid – UUID of group
object_name – Name of the assigned object
frame_start – First frame of the window
frame_end – Last frame of the window
- remove_collision_window(group_uuid: str, object_name: str, index: int)#
Remove a collision window by index.
- Parameters:
group_uuid – UUID of group
object_name – Name of the assigned object
index – Zero-based index into the object’s collision_windows list
- set_collision_window(group_uuid: str, object_name: str, index: int, frame_start: int | None = None, frame_end: int | None = None)#
Change the bounds of one collision window an object already carries, addressed by its index.
Either bound may be given on its own and the other is left as it is. The window that results is what gets validated, so moving frame_start past the frame_end already stored is refused instead of being kept as an inverted window that turns contact off for the whole run.
Editing in place also keeps the window at its index, which is how list_collision_windows and remove_collision_window address it.
- Parameters:
group_uuid – UUID of group
object_name – Name of the assigned object
index – Zero-based index into the object’s collision_windows list
frame_start – First frame of the window (>= 1)
frame_end – Last frame of the window (>= frame_start)
- list_collision_windows(group_uuid: str, object_name: str)#
List collision windows on an assigned object.
- Parameters:
group_uuid – UUID of group
object_name – Name of the assigned object
- clear_collision_windows(group_uuid: str, object_name: str)#
Clear every collision window on an assigned object.
- Parameters:
group_uuid – UUID of group
object_name – Name of the assigned object
- capture_static_deformation(group_uuid: str, object_name: str)#
Record the per-frame shape of an animated STATIC mesh onto the collider.
Use this for STATIC objects whose vertices move because of an Armature modifier, a Lattice or Mesh Deform cage, animated Shape Keys, or a driver that pokes vertex coordinates. The recording runs as a modal operator and continues after this call returns; poll
get_static_deformation_statusto detect completion.Press again any time the underlying animation changes (a new pose, edited action keyframes, a modifier swap). The recording does NOT update on its own.
- Parameters:
group_uuid – UUID of STATIC group containing the object
object_name – Name of the assigned mesh to capture
- clear_static_deformation(group_uuid: str, object_name: str)#
Discard the recorded deformation cache for one STATIC object.
The object returns to the pre-capture state: Capture Deformation becomes the only enabled button on the row, and the next Transfer will refuse to upload the object until a fresh capture is taken.
- Parameters:
group_uuid – UUID of STATIC group containing the object
object_name – Name of the assigned mesh
- get_static_deformation_status(group_uuid: str, object_name: str)#
Report the deformation-capture state of one STATIC object.
Returns three fields:
is_deforming: True if the object’s modifier stack or shape-key animation actually moves vertices over the timeline. When False, Capture Deformation is not needed and the button is grayed out.has_cache: True if a deformation cache exists for the object.frame_count: Number of frames in the cache, or 0 when absent.
- Parameters:
group_uuid – UUID of STATIC group containing the object
object_name – Name of the assigned mesh
- capture_pin_deformation(group_uuid: str, vertex_group_identifier: str)#
Record the per-frame shape of a deformable pin onto the cloth mesh.
Use this for pins whose vertices ride along with an Armature, Lattice, Mesh Deform cage, animated Shape Keys, or a driver. The recording runs as a modal operator and continues after this call returns; poll
get_pin_deformation_statusuntilframe_countis non-zero.Press again any time the underlying animation changes. The recording does NOT update on its own. Refuses to start if the pin already carries manual Make-Keyframe vertex-co fcurves; clear those first.
- Parameters:
group_uuid – UUID of the SHELL/SOLID/ROD group containing the pin
vertex_group_identifier – Pin id in ‘object::vertex_group’ form
- clear_pin_deformation(group_uuid: str, vertex_group_identifier: str)#
Discard the captured deformation cache for one pin.
The pin returns to whatever motion source it had before (none, or manual Make-Keyframe fcurves if any). If no manual fcurves exist the EMBEDDED_MOVE sentinel is also removed so the pin no longer appears animated.
- Parameters:
group_uuid – UUID of the group containing the pin
vertex_group_identifier – Pin id in ‘object::vertex_group’ form
- get_pin_deformation_status(group_uuid: str, vertex_group_identifier: str)#
Report the captured-deformation state of one pin.
Returns four fields:
is_deforming: True if the pin object’s modifier stack will move vertices over the timeline (Armature, Lattice, …).has_cache: True if a captured-deformation cache exists for the pin (in memory or on disk).frame_count: Number of frames in the cache, or 0 when absent.has_captured_anim_flag: The pin item’shas_captured_animbool; should matchhas_cacheafter the load_post reconciler runs.
- Parameters:
group_uuid – UUID of the group containing the pin
vertex_group_identifier – Pin id in ‘object::vertex_group’ form
- set_object_tet_settings(group_uuid: str, object_name: str, tet_backend: str | None = None, ftetwild_edge_length_fac: float | None = None, ftetwild_epsilon: float | None = None, ftetwild_stop_energy: float | None = None, ftetwild_num_opt_iter: int | None = None, ftetwild_optimize: bool | None = None, ftetwild_simplify: bool | None = None, ftetwild_coarsen: bool | None = None, tetgen_min_ratio: float | None = None, tetgen_max_volume: float | None = None, clear_overrides: list[str] | None = None)#
Set the per-object tetrahedralizer backend and overrides.
SOLID meshes are tetrahedralized at build time, and each object in a group picks its backend and overrides independently (ignored for non-SOLID objects). Passing any override value also enables that override, and an override the call does not mention keeps whatever it already holds.
An enabled override stays enabled until it is cleared: name it in
clear_overridesto switch it off and hand the field back to the backend default. Clearing needs its own argument because a value argument left out already means “leave this one alone”, so it has no spelling to spare for “turn this one off”. A field named inclear_overridesand given a value in the same call is refused rather than resolved by argument order.- Parameters:
group_uuid – UUID of the group containing the object.
object_name – Name of the assigned object in the group.
tet_backend – “FTETWILD” (tolerant remesher, default) or “TETGEN” (preserves the input surface exactly, needs a clean closed manifold).
ftetwild_edge_length_fac – fTetWild ideal tet edge length as a fraction of the bounding-box diagonal.
ftetwild_epsilon – fTetWild envelope size as a fraction of the bbox diagonal.
ftetwild_stop_energy – fTetWild AMIPS energy threshold (larger is faster).
ftetwild_num_opt_iter – fTetWild maximum optimization passes.
ftetwild_optimize – Improve cell quality (slower).
ftetwild_simplify – Simplify the input surface before tetrahedralization.
ftetwild_coarsen – Coarsen the input surface.
tetgen_min_ratio – TetGen minimum radius-edge ratio.
tetgen_max_volume – TetGen maximum tet volume (0 = uncapped).
clear_overrides – Override fields to switch back off, so the backend default applies again, for example [“ftetwild_epsilon”]. Any name that is not an override field is refused.
- detect_isolated_static_vertices()#
Report stray faceless vertices on active STATIC colliders that block Transfer.
Scans every included, active STATIC collider mesh for vertices that belong to no triangle (no face). The solver build aborts on these, and Transfer reports a ValueError naming the object and the vertex indices. Read-only; pair with remove_isolated_static_vertices to delete them.
- remove_isolated_static_vertices()#
Delete stray faceless vertices from active STATIC colliders so the scene transfers.
Removes only vertices that belong to no triangle (with their loose edges); faces are untouched. Mirrors the Remove Isolated Vertices panel button and scans every included, active STATIC collider. Run detect_isolated_static_vertices first to preview what will be deleted.
- convert_to_particle_mesh(object_name: str, grain_radius: float, extra_spacing: float = 0.0, rng_seed: int = 0)#
Replace a solid mesh with a cloud of grain centers for a Sand group.
Destructive: the faces are discarded and the object becomes a faceless mesh of loose vertices carrying a render-only Particle Mesh modifier. The grain count is not chosen, it is whatever fills the volume at the given separation, and it comes back in the result.
grain_radius is locked after conversion, since the non-overlapping spacing is derived from it, so pick it before converting rather than adjusting it afterward. A radius or spacing that fits no grain at all is refused with the object untouched.
- Parameters:
object_name – Solid mesh object with faces, not already a particle mesh
grain_radius – Physical grain radius, which is also the contact skin
extra_spacing – Gap added between grains beyond touching. 0 packs them as densely as non-overlap allows
rng_seed – Seed for the Poisson-disk seeding, for a repeatable cloud
- recapture_all_deformations()#
Re-capture every deforming STATIC collider and every animated pin.
One pass over the whole scene, instead of calling capture_static_deformation and capture_pin_deformation per object. The statics are captured first and the pins after, since the two share the depsgraph and cannot run at once.
The captures run in the background after this returns; poll get_static_deformation_status and get_pin_deformation_status until they report the frame counts you expect.
- clear_all_deformations()#
Delete every captured deformation cache in the scene.
Covers all STATIC-collider deform caches and all animated-pin captures across the active groups, plus any cache orphaned by an object that was deleted or taken out of its group. The objects keep their deformers, so recapture_all_deformations rebuilds what this removes.
Mesh cleaning#
- scan_meshes(object_names: list[str], merge_threshold: float = 0.0001, area_eps: float = 0.0)#
Scan meshes for geometry the solver rejects, without modifying anything.
Reports per object, split into errors (near-coincident vertices, isolated and hanging vertices, duplicate and degenerate faces, linked duplicates, inconsistent winding) and notes (boundary edges, non-manifold edges, re-splittable quads). Notes are normal for cloth: an open quad panel is not a defect. Each report also carries
dependents, what a vertex-count change on that object would invalidate.- Parameters:
object_names – Mesh objects to scan
merge_threshold – Vertices closer than this (local units) count as near-coincident. Matches Blender’s Merge by Distance default
area_eps – Faces at or below this area (local units squared) count as degenerate. Zero reports only exactly zero-area faces
- merge_by_distance(object_names: list[str], merge_threshold: float = 0.0001, acknowledge: bool = False, clear_stale_caches: bool = True)#
Weld near-coincident vertices. Changes the vertex count.
A pair of vertices separated by a tiny gap drives the contact barrier’s mass/gap^2 stiffness through the conditioning of the solver’s fp32 Newton matrix, so welding them is what makes such a mesh simulable.
- Parameters:
object_names – Mesh objects to repair
merge_threshold – Weld vertices closer together than this, local units
acknowledge – Must be true. Confirms the vertex-count change and the caches it invalidates, which scan_meshes reports as dependents
clear_stale_caches – Delete the capture and display caches the change invalidates, which the result reports as cleared_caches. True by default, the same value the panel’s dialog opens with. Pass false to keep them, and expect the viewport overlay to read data sized for the old vertex count until Transfer rewrites it
- remove_loose_vertices(object_names: list[str], acknowledge: bool = False, clear_stale_caches: bool = True)#
Delete vertices that belong to no face. Changes the vertex count.
A faceless vertex carries no elastic energy, so the solver has nothing to hold it with. Pinned vertices are exempt and are never removed.
- Parameters:
object_names – Mesh objects to repair
acknowledge – Must be true. Confirms the vertex-count change and the caches it invalidates, which scan_meshes reports as dependents
clear_stale_caches – Delete the capture and display caches the change invalidates, which the result reports as cleared_caches. True by default, the same value the panel’s dialog opens with. Pass false to keep them, and expect the viewport overlay to read data sized for the old vertex count until Transfer rewrites it
- dissolve_degenerate_faces(object_names: list[str], merge_threshold: float = 0.0001, acknowledge: bool = False, clear_stale_caches: bool = True)#
Collapse zero-area and slivered faces. Changes the vertex count.
A face with no area has no well-defined normal, which is what the contact and bending terms are built on.
- Parameters:
object_names – Mesh objects to repair
merge_threshold – Edges shorter than this (local units) are collapsed
acknowledge – Must be true. Confirms the vertex-count change and the caches it invalidates, which scan_meshes reports as dependents
clear_stale_caches – Delete the capture and display caches the change invalidates, which the result reports as cleared_caches. True by default, the same value the panel’s dialog opens with. Pass false to keep them, and expect the viewport overlay to read data sized for the old vertex count until Transfer rewrites it
- delete_duplicate_faces(object_names: list[str])#
Delete faces that repeat an existing face’s vertex set.
Two faces on the same vertices contribute their contact and elastic terms twice. The vertex count is unchanged, so no cache is invalidated.
- Parameters:
object_names – Mesh objects to repair
- triangulate_for_solver(object_names: list[str])#
Triangulate n-gons and quads with a single diagonal per face.
The vertex count is unchanged, so no cache is invalidated. Transfer triangulates on its own at encode time; use this when the triangulation has to be visible and stable in the viewport. For a mesh whose symmetry matters under bending, prefer symmetric_triangulate.
- Parameters:
object_names – Mesh objects to triangulate
- recalculate_normals_outside(object_names: list[str])#
Make face winding consistent and outward.
Inconsistent winding flips the normal a face contributes, which the contact and inflate terms read. The vertex count is unchanged, so no cache is invalidated, and the repair is reported as the
bad_winding_before/bad_winding_afteredge counts rather than as an element delta.- Parameters:
object_names – Mesh objects to repair
- symmetric_triangulate(object_names: list[str])#
Triangulate by poking each face, keeping the mesh mirror-symmetric.
A single-diagonal triangulation breaks a symmetric mesh’s symmetry, which shows up as a lopsided drape under bending. Poking inserts a center vertex and fans the face into triangles instead, so it ADDS one vertex per face and therefore invalidates a captured deformation and the display cache, exactly as the count-changing repairs do. It is a Utility Tools operation rather than a repair, so it takes no acknowledgement and deletes nothing it invalidates: the vertex deltas come back in the result, and Transfer and Capture Deformation are what re-take the stale caches.
- Parameters:
object_names – Mesh objects to triangulate
- triangulate_degenerate_faces()#
Re-split only the faces whose tessellation leaves the solver no rest shape.
This is the targeted repair the Transfer refusal names. Blender splits a quad along one of its two diagonals, and on a quad whose corner sits on, or very near, the straight edge between its neighbors that diagonal produces a triangle of three nearly collinear vertices. The solver inverts each rest triangle once at scene build and the elastic Hessian is quadratic in that inverse. An exactly zero-area triangle aborts the build on a degenerate-face assertion; a merely near-collinear one clears that assertion, inverts to a finite but enormous rest matrix, and reaches the linear solve as a non-finite Hessian that names no geometry. The test is the conditioning of the rest matrix against sqrt(float32 eps), not an area threshold, so a thin triangle above that ratio is legitimate geometry and is left alone.
Only flagged faces are split, and only those whose replacement fill is measured sound before the split. Every other face keeps its shape, which is what separates this from triangulate_for_solver and symmetric_triangulate: each of those rewrites every quad and n-gon of the mesh. The vertex count does not change, so no cache is invalidated; the face count grows by one face per split quad and by more for a wider n-gon.
There is no object argument, because the operator underneath offers no property to narrow its scope: it repairs every included mesh assigned to an active object group other than SAND, STATIC collider groups included, and judges each one on its BASE cage. Each mesh datablock is repaired once, so two objects sharing a mesh are reported under a single name, and each entry of the result names the group object types that datablock is assigned under.
That set is not the one Transfer refuses over, and it differs in both directions. It is WIDER: the encoder applies this conditioning test only to a SHELL and to a SOLID meshed by TetGen, and gives every other tessellation a positive-area test instead, so a STATIC, ROD, PDRD or fTetWild-SOLID mesh can be rewritten here although Transfer accepts it as authored. Read
group_object_typesin the result to see which meshes that covers. A STATIC group promoted into the solved namespace, by soft constraints, a captured deformation, static ops, an unpin time or a stitch endpoint, does invert its rest shape in the solver, so a repair on a collider mesh is not always unnecessary and nothing here separates the two cases before the run. It is also NARROWER: the encoder judges the starting frame’s deform-evaluated pose, and this repair judges the base cage, because a re-split of the base mesh is all it can change. A corner that a shape key, an armature or another deforming modifier moves onto the line between its neighbors is therefore invisible here, and a refusal from this tool does not mean the Transfer complaint was spurious.The result carries, per object, how many flagged faces the repair cleared and how many faces the mesh gained. A face no split can rescue is left exactly as it is and comes back under
still_degenerate: a face that is already a triangle is its own only triangulation, and one with no area or a zero-length boundary edge forces a degenerate triangle into every triangulation. Those need the offending vertex moved, merge_by_distance to weld coincident vertices, or dissolve_degenerate_faces. A call that finds nothing flagged, or nothing triangulating can repair, is refused rather than reported as a success. Run Transfer again afterward.
Simulation#
- transfer_data()#
Transfer data to the solver.
- run_simulation()#
Start simulation.
- resume_simulation()#
Resume paused simulation.
- terminate_simulation()#
Force terminate simulation.
- save_and_quit_simulation()#
Save and quit simulation gracefully.
- update_params()#
Update the parameters of the solver.
- delete_remote_data()#
Delete data on the remote server.
- fetch_animation()#
Fetch simulation results from server.
- clear_local_animation()#
Clear local animation data and keyframes.
- list_checkpoint_frames()#
List resumable checkpoint frames saved on the server.
Returns the saved-state frames (Blender 1-based) a resume can continue from, read from the latest solver status response. Empty until at least one checkpoint has been saved (via Save Checkpoints, Auto Save, or Save State on Finish). Use resume_simulation to continue from the latest one.
- resume_simulation_from(frame: int)#
Resume the simulation from a specific saved checkpoint frame.
Continues the run already on the server from the chosen checkpoint (Blender 1-based) without re-uploading or rebuilding: frames before the checkpoint are kept, the rest are overwritten. Refuses if the geometry has drifted (transfer_data + run_simulation instead) or the parameters have changed (update_params first). Use list_checkpoint_frames to see the available frames; resume_simulation continues from the latest one.
- Parameters:
frame – Saved checkpoint frame to resume from (Blender 1-based).
- export_usd(filepath: str)#
Export the simulated mesh sequence as a USD cache.
A lighter alternative to baking shape keys: the deformation is sampled per frame from the solver cache into a file other DCC tools can play back. Requires every frame to be fetched first; call fetch_animation and wait for it to finish. Rod and curve objects are not carried by this format.
- Parameters:
filepath – Destination path, used as given once a leading “//” blend-relative prefix is resolved. The suffix is what picks the USD flavor and it is never rewritten, so pass one of .usdc (crate), .usda (ASCII), .usd or .usdz (package). The parent directory must already exist.
- export_alembic(filepath: str)#
Export the simulated mesh sequence as an Alembic (ABC) cache.
A lighter alternative to baking shape keys: the deformation is sampled per frame from the solver cache into a file other DCC tools can play back. Requires every frame to be fetched first; call fetch_animation and wait for it to finish. Rod and curve objects are not carried by this format.
- Parameters:
filepath – Destination .abc path, used as given once a leading “//” blend-relative prefix is resolved. The parent directory must already exist.
- get_fetch_status()#
Report which simulated frames have been fetched back into Blender.
Fetching is a modal operation: fetch_animation returns as soon as it has started, so a caller needs a separate way to see how far it got. The export tools refuse while any frame is still unfetched, and bpy.ops hands back only a canceled status without the reason, so this reports the export preflight verdict alongside the frame list.
fetched_frames is what landed locally, which is a different question from list_checkpoint_frames (frames saved on the remote), from get_remote_status (how the run itself is doing), and from get_modal_job_status (whether a bake or a deformation capture is still running inside Blender).
- abort_bake()#
Stop a running keyframe bake and undo what it has written so far.
Baking an animation runs as a modal job that keeps going after bake_group_animation or bake_all_animation returns. This raises that job’s abort flag. The job stops on its next timer tick and rolls back what it wrote: the shape keys and F-curves it added are removed and the curve handle types it changed are restored, leaving the PC2 caches, the ContactSolverCache modifiers and group membership as they were before the bake started.
bake_group_single_frame and bake_all_single_frame start no such job. Each bakes its one frame inline and is complete when its own tool call returns, so a single-frame bake is never in flight, there is nothing to poll for and nothing here to abort.
Refused when no bake is running, and refused again while an abort of the same bake is already in flight. Call get_modal_job_status for the jobs running now, and poll it afterwards until the bake reports running false.
This stops the bake inside Blender. abort_operation stops an operation on the solver server, which is a different job.
- abort_static_deformation_capture()#
Stop a running STATIC collider deformation capture.
capture_static_deformation and recapture_all_deformations start a modal job that steps the timeline and samples the shape of each deforming STATIC collider. This raises the job’s abort flag. The job stops on its next timer tick, restores the frame it started from, and re-enables the ContactSolverCache modifiers it suspended for the sampling.
A capture writes an object’s result only once every frame of that object is sampled, so the frames taken before the abort are discarded and each object keeps the deformation cache it already had. get_static_deformation_status reports what is on an object; run the capture again to record it.
Inside a recapture_all_deformations run the static phase runs first and the pin phase is queued behind it, so aborting here cancels the whole run: the pin phase never starts and those pins keep the captures they already had. Capture them with capture_pin_deformation, or start recapture_all_deformations again.
Refused when no static capture is running, and refused again while an abort of it is already in flight. Call get_modal_job_status for the jobs running now, and poll it afterwards until this job reports running false.
- abort_pin_deformation_capture()#
Stop a running pin deformation capture.
capture_pin_deformation and recapture_all_deformations start a modal job that steps the timeline and samples the moving pin vertices of each animated pin. This raises the job’s abort flag. The job stops on its next timer tick, restores the frame it started from, and re-enables the ContactSolverCache modifiers it suspended for the sampling.
A capture writes a pin’s result only once every frame of that pin is sampled, so the frames taken before the abort are discarded and each pin keeps the capture it already had. get_pin_deformation_status reports what is on a pin; run the capture again to record it.
Refused when no pin capture is running, and refused again while an abort of it is already in flight. Call get_modal_job_status for the jobs running now, and poll it afterwards until this job reports running false.
- get_modal_job_status()#
Report which long-running bake or capture job is running right now.
Three jobs run on a timer inside Blender and outlive the tool call that started them, so a caller that starts one has no other way to tell whether it is still going: the keyframe bake, the STATIC collider deformation capture, and the pin deformation capture. This reports all three in one call, each with the frames it has processed and the tool that stops it.
jobscarries one entry per job.bakeis started by bake_group_animation or bake_all_animation and stopped by abort_bake.static_deformation_captureis started by capture_static_deformation or recapture_all_deformations and stopped by abort_static_deformation_capture.pin_deformation_captureis started by capture_pin_deformation or recapture_all_deformations and stopped by abort_pin_deformation_capture.bake_group_single_frame and bake_all_single_frame start none of the three. Each bakes its one frame inline and is complete when its own tool call returns, so
bakestays running false throughout and there is nothing to poll for after one of them.abort_requestedis true once the job is unwinding, whether an abort tool asked for it or the job hit an internal failure: the two deformation captures raise the same flag on a frame they could not sample. Either way the job has not yet reached the tick that stops it.frames_done,frames_total,item_count(objects for the bake and the STATIC capture, pins for the pin capture) andstatus_lineare null while a job is not running, because those counters are cleared when a job ends.This covers the jobs running inside Blender. get_fetch_status reports how much of a solve has been fetched back into Blender and whether an export would be accepted, and get_remote_status reports the run on the server.
Scene#
- clear_solver()#
Reset the entire solver state to defaults.
- add_invisible_wall(position: list[float], normal: list[float])#
Add an invisible wall collider at a given position and normal.
- Parameters:
position – Wall origin in Blender world space [x, y, z].
normal – Outward-facing normal vector [x, y, z].
- add_invisible_sphere(position: list[float], radius: float, invert: bool = False, hemisphere: bool = False)#
Add an invisible sphere collider.
- Parameters:
position – Center in Blender world space [x, y, z].
radius – Sphere radius.
invert – If true, acts as an inverted sphere (contact from inside).
hemisphere – If true, only the upper half acts as a collider.
- list_invisible_colliders()#
Return a list of all invisible colliders currently in the scene.
- remove_invisible_collider(index: int)#
Remove an invisible collider by its index in the scene list.
- Parameters:
index – Zero-based index as reported by list_invisible_colliders.
- clear_invisible_colliders()#
Remove every invisible collider from the scene.
- add_merge_pair(object_a: str, object_b: str)#
Stitch two objects together along their nearest overlapping vertices.
- Parameters:
object_a – Name of the source object.
object_b – Name of the target object.
- remove_merge_pair(object_a: str, object_b: str)#
Remove a merge pair by the two object names.
- Parameters:
object_a – Name of the source object.
object_b – Name of the target object.
- list_merge_pairs()#
Return every stored merge pair with its names, UUIDs and stitch state.
stitch_row_countis how many stitch anchors the pair currently carries. A pair reporting 0 contributes no stitch to the solve whatever itsstitch_stiffness, and resnap_merge_pair rebuilds the anchors. Anchors invalidated by a later mesh edit are dropped when the scene is encoded, so a nonzero count reports what is stored rather than a fresh check against the current topology.
- clear_merge_pairs()#
Remove every merge pair from the scene.
- snap_to_vertices(object_a: str, object_b: str)#
Move object A so its nearest vertex matches object B’s nearest vertex.
- Parameters:
object_a – Name of the object that will move.
object_b – Name of the target object (stays put).
- bake_all_animation()#
Bake simulated animation for every dynamic group to Blender keyframes.
- bake_all_single_frame()#
Bake the current frame as frame 1 for every dynamic group.
- get_scene_info()#
Enumerate the current Blender scene: objects, frame range, and groups.
This is the starting point for an agent that did not create the scene: it reports what is in the file and which objects are already assigned to a dynamics group, so the caller can tell setup work that remains from work already done.
Returns the scene’s frame range as Blender holds it, alongside the simulation frame count and fps the solver will actually use, which are separate values and are resolved differently.
- set_merge_pair_properties(object_a: str, object_b: str, stitch_stiffness: float | None = None, show_stitch: bool | None = None)#
Set one merge pair’s own stitch stiffness and stitch visualization.
This
stitch_stiffnessbelongs to the PAIR and is a separate solver input from the group parameter of the same name that set_group_material_properties writes: the solver scales this pair’s stitch gradient and Hessian by it directly, with no mass or dt normalization, so raise it to hold this one seam harder.The value reaches the solver only through the stitch anchors captured at snap time, so it stays inert on a pair whose
stitch_row_count(see list_merge_pairs) is 0; call resnap_merge_pair to build the anchors. An argument left out is not written.- Parameters:
object_a – Name of one object in the pair.
object_b – Name of the other object in the pair, in either order.
stitch_stiffness – Stiffness of this pair’s stitch, 0 or greater.
show_stitch – Draw this pair’s stitch in the viewport.
- resnap_merge_pair(object_a: str, object_b: str)#
Re-run the snap on an existing merge pair to rebuild its stitch.
The two objects must already form a merge pair (add_merge_pair or snap_to_vertices). The snap MOVES one of them: object A of the STORED pair, unless that side is in a STATIC group, in which case the other side moves instead. Which object moves therefore follows the stored pair, not the argument order used here. The two are left a small gap apart, sized from their contact offsets, rather than coincident.
This is what makes a pair’s stitch anchors current after either mesh was edited, and what gives a pair anchors at all when it was created without a snap. A pair whose
stitch_row_countstays 0 forms no stitch at solve time.- Parameters:
object_a – Name of one object in the pair.
object_b – Name of the other object in the pair, in either order.
Dynamic parameters#
- add_dynamic_param(param_type: str)#
Add a dynamic (time-varying) scene parameter.
Creates an initial keyframe at frame 1 seeded from the current static scene value.
- Parameters:
param_type – One of GRAVITY, WIND, AIR_DENSITY, AIR_FRICTION, VERTEX_AIR_DAMP
- remove_dynamic_param(param_type: str)#
Remove a dynamic scene parameter entry.
- Parameters:
param_type – One of GRAVITY, WIND, AIR_DENSITY, AIR_FRICTION, VERTEX_AIR_DAMP
- list_dynamic_params()#
List all dynamic scene parameters and their keyframes.
- add_dynamic_param_keyframe(param_type: str, frame: int, gravity: list[float] | None = None, wind_direction: list[float] | None = None, wind_strength: float | None = None, value: float | None = None, use_hold: bool | None = None)#
Add a keyframe to a dynamic scene parameter.
Supply the field matching the param_type (gravity for GRAVITY; wind_direction + wind_strength for WIND; value for the scalar params).
- Parameters:
param_type – GRAVITY, WIND, AIR_DENSITY, AIR_FRICTION, or VERTEX_AIR_DAMP
frame – Blender frame (>= 1)
gravity – [x, y, z] for GRAVITY param
wind_direction – [x, y, z] for WIND param
wind_strength – Scalar speed (m/s) for WIND param
value – Scalar for AIR_DENSITY, AIR_FRICTION, or VERTEX_AIR_DAMP
use_hold – Hold previous keyframe value (step function)
- remove_dynamic_param_keyframe(param_type: str, frame: int)#
Remove a keyframe from a dynamic scene parameter.
The initial keyframe (frame 1) cannot be removed.
- Parameters:
param_type – GRAVITY, WIND, AIR_DENSITY, AIR_FRICTION, or VERTEX_AIR_DAMP
frame – Frame number of the keyframe to remove
- set_collider_properties(index: int, name: str | None = None, position: list[float] | None = None, normal: list[float] | None = None, radius: float | None = None, contact_gap: float | None = None, friction: float | None = None, thickness: float | None = None, invert: bool | None = None, hemisphere: bool | None = None, enable_active_duration: bool | None = None, active_duration: int | None = None)#
Update properties on an invisible collider.
Pass only the fields you want to change. normal is wall-only; radius/invert/hemisphere are sphere-only.
- Parameters:
index – Zero-based collider index as reported by list_invisible_colliders
name – Display name
position – [x, y, z] origin
normal – [x, y, z] outward normal (WALL only)
radius – Sphere radius (SPHERE only)
contact_gap – Contact gap tolerance
friction – Friction coefficient [0, 1]
thickness – Max penetration depth (> 0)
invert – Flip contact direction (SPHERE only)
hemisphere – Restrict to upper half (SPHERE only)
enable_active_duration – Enable per-collider active-until frame
active_duration – First frame the collider is no longer active
- add_collider_keyframe(index: int, frame: int, position: list[float] | None = None, radius: float | None = None, use_hold: bool | None = None)#
Add a keyframe to an invisible collider.
- Parameters:
index – Zero-based collider index
frame – Blender frame (>= 1)
position – [x, y, z] at this keyframe
radius – Sphere radius at this keyframe (SPHERE only)
use_hold – Hold the previous keyframe value (step function)
- remove_collider_keyframe(index: int, frame: int)#
Remove a keyframe from an invisible collider.
- Parameters:
index – Zero-based collider index
frame – Frame number of the keyframe to remove
- list_collider_keyframes(index: int)#
List keyframes on an invisible collider.
- Parameters:
index – Zero-based collider index
Remote#
- abort_operation()#
Abort the current in-progress operation.
- install_paramiko()#
Install the Paramiko library.
- install_docker()#
Install the Docker library.
- set_scene_parameters(step_size: float | None = None, min_newton_steps: int | None = None, frame_count: int | None = None, frame_start: int | None = None, use_scene_frame_start: bool | None = None, frame_rate: int | None = None, gravity: list[float] | None = None, wind_direction: list[float] | None = None, wind_strength: float | None = None, air_density: float | None = None, air_friction: float | None = None, world_scaling: float | None = None, vertex_air_damp: float | None = None, fix_xz: float | None = None, inactive_momentum_frames: int | None = None, contact_nnz: int | None = None, line_search_max_t: float | None = None, constraint_ghat: float | None = None, cg_max_iter: int | None = None, cg_tol: float | None = None, include_face_mass: bool | None = None, friction_mode: str | None = None, disable_contact: bool | None = None, auto_save: bool | None = None, auto_save_interval: int | None = None, save_state_on_finish: bool | None = None, keep_states: int | None = None, precond: str | None = None, schwarz_levels: int | None = None, use_scene_fps: bool | None = None, time_scale: float | None = None, post_snap_exactly: bool | None = None, project_name: str | None = None)#
Set global scene parameters for physics simulation.
Only the parameters passed are written; the rest keep their current value. Two of them are enums that reject anything else: friction_mode accepts “MIN”, “MAX” or “MEAN”, and precond accepts “BLOCK_JACOBI” or “SCHWARZ”. post_snap_exactly is the one parameter here that is not sent to the solver: it controls how already-simulated frames are written back on fetch, so changing it takes effect on the next fetch and needs no new run.
- Parameters:
step_size – Simulation step size (seconds)
min_newton_steps – Minimum Newton iterations per step
frame_count – Number of simulation frames
frame_start – Blender frame the simulation starts on (simulated time zero). Ignored while use_scene_frame_start is True
use_scene_frame_start – Take the starting frame from the Blender scene’s start frame instead of the frame_start field
frame_rate – Frame rate for simulation
gravity – Gravity acceleration vector [x, y, z] m/s^2
wind_direction – Wind direction vector [x, y, z]
wind_strength – Wind speed magnitude (m/s)
air_density – Air density (kg/m^3)
air_friction – Tangential/normal air friction ratio
world_scaling – Uniform scale applied to all geometry before simulating; results are scaled back so the scene keeps its authored size. Must be within [0.001, 1000.0], and 1.0 disables it. Gravity and material stiffness do not scale
vertex_air_damp – Vertex-level air damping factor
fix_xz – Height threshold (m) above which lateral motion (XY in Blender, XZ in the solver’s Y-up frame) is constrained. Must be 0 or greater, and 0 disables it. The threshold is scaled by world_scaling along with the geometry
inactive_momentum_frames – Inactive momentum frame count
contact_nnz – Max contact non-zero entries
line_search_max_t – CCD TOI extension factor
constraint_ghat – Boundary constraint gap distance
cg_max_iter – PCG max iterations
cg_tol – PCG relative tolerance
include_face_mass – Include shell face mass for solids’ surface elements
friction_mode – How the friction coefficients of two contacting elements combine: “MIN” (min(a, b), the default), “MAX” (max(a, b)) or “MEAN” (0.5 * (a + b))
disable_contact – Disable all contact detection
auto_save – Enable auto-save
auto_save_interval – Auto-save interval (frames)
save_state_on_finish – Save a resumable state when the simulation finishes
keep_states – Number of most-recent saved states to retain (0 = keep all)
precond – PCG preconditioner, “BLOCK_JACOBI” (default) or “SCHWARZ”
schwarz_levels – Number of additive Schwarz levels, 1 (single-level smoother) or 2 (two-level coarse correction, default). Only used when precond is “SCHWARZ”.
use_scene_fps – Run the simulation at the Blender scene’s frame rate instead of the frame_rate field
time_scale – Playback speed of the Blender animation in simulated time (1.0 real time, 0.5 half speed); the solver’s time mapping runs at effective_fps * time_scale
post_snap_exactly – On fetch, move every stitched vertex exactly onto its stitch target so seams appear joined. Applies to all stitch pairs; turn it off to keep the raw simulated gap between stitched parts
project_name – Project name used for remote session directory
- get_scene_parameters()#
Get current scene parameters.
- set_save_checkpoint_frames(frames: list[int])#
Set the explicit frames at which to save a resumable checkpoint.
Replaces the current Save Checkpoints list. Frames are de-duplicated, clamped to Blender’s 1-based minimum, and sorted ascending. These are the frames the Resume dialog offers, in addition to Auto Save and Save State on Finish.
- Parameters:
frames – Frame indices (1-based) to save checkpoints at.
- clear_save_checkpoint_frames()#
Clear all explicit Save Checkpoints frames.
- list_save_checkpoint_frames()#
List the explicit Save Checkpoints frames configured for the next run.
Console#
- get_console_lines()#
Get current console text lines.
- get_latest_error()#
Get latest error from both local and remote.
- show_console()#
Show console window.
Debug#
- debug_data_send(data_size_mb: int = 1)#
Send test data to remote server for debugging data transfer.
- Parameters:
data_size_mb – Size of test data in megabytes (default: 1MB)
- debug_data_receive()#
Receive test data from remote server and verify integrity.
This function should be called after debug_data_send to test the complete round-trip data transfer functionality.
- execute_server_command(server_script: str)#
Execute a server command/script.
- Parameters:
server_script – Server script command to execute
- execute_shell_command(shell_command: str, use_shell: bool = True)#
Execute a shell command on remote server.
- Parameters:
shell_command – Shell command to execute
use_shell – Whether to use shell execution
- git_pull_remote()#
Pull the latest changes from the Git repository on remote server.
- compile_project()#
Compile the project on remote server.
- delete_log_file(log_file_path: str)#
Delete the specified log file.
- Parameters:
log_file_path – Path to the log file to delete
- git_pull_local()#
Pull the latest changes from the local Git repository.
Blender#
- run_python_script(code: str)#
Execute arbitrary Python code in Blender with access to bpy, bmesh, and mathutils modules.
- Parameters:
code – Python code to execute in Blender context
- capture_viewport_image(filepath: str, max_size: int = 800)#
Capture a screenshot of the current 3D viewport and save it to specified file path.
- Parameters:
filepath – File path where to save the screenshot
max_size – Maximum size in pixels for the largest dimension
- create_curve(name: str, bevel_depth: float = 0.0, bevel_resolution: int = 2, resolution_u: int = 4, dimensions: str = '3D', clear_existing: bool = True)#
Create a pending curve builder for ROD-scene authoring.
- Parameters:
name – Object name for the curve to be finalized later
bevel_depth – Tube radius for viewport visualization
bevel_resolution – Tube cross-section subdivisions
resolution_u – Spline interpolation resolution
dimensions – Curve dimensions (“3D” or “2D”)
clear_existing – Remove an existing same-name object before finalize
- add_curve_spline(name: str, points: list[list[float]], closed: bool = False)#
Append a Bezier spline to a pending curve builder.
- Parameters:
name – Curve builder name passed to create_curve
points – List of [x, y, z] control-point coordinates
closed – Whether to make the spline cyclic
- set_curve_material(name: str, spline_index: int, material_name: str, create_if_missing: bool = False)#
Bind a Blender material to a spline on a pending curve builder.
- Parameters:
name – Curve builder name passed to create_curve
spline_index – Spline index returned by add_curve_spline
material_name – Existing Blender material name
create_if_missing – Create the material when it does not exist
- finalize_curve(name: str)#
Finalize a pending curve builder, link it to the scene, and return the object.
- Parameters:
name – Curve builder name passed to create_curve
- get_ui_element_status(element_type: str = 'all', element_name: str | None = None, category: str | None = None)#
Get status of Blender addon UI elements - poll results for operators, values for properties.
- Parameters:
element_type – Type of elements to check (“operator”, “property”, “all”)
element_name – Specific element name to check (optional)
category – Filter by category (“solver”, “dynamics”, “client”, “debug”)
- get_average_edge_length(object_name: str)#
Compute the average edge length of a mesh object.
- Parameters:
object_name – Name of the mesh object to analyze
- get_object_bounding_box_diagonal(object_name: str)#
Compute the bounding box of an object and return the largest diagonal distance.
- Parameters:
object_name – Name of the object to analyze
- refresh_ui()#
Refresh all UI areas in Blender to reflect recent changes.
This is useful when programmatic changes need to be reflected in the UI, such as after starting/stopping servers or updating addon state.
Material Maps#
- add_material_map(group_uuid: str, parameter: str, source_type: str, source_name: str, target_value: float, enabled: bool = True)#
Add a spatial material map, varying one parameter across the surface.
The value at a vertex is lerp(base, target, weight), where base is the group’s own slider for that parameter and weight is read per vertex from the named source, clamped to [0, 1]. A weight of 0 therefore reproduces the unmapped result exactly. Each element takes the mean of its own vertices’ weights.
Only SHELL and SOLID groups carry the element tables a map is reduced over, and each object type reads a different set of parameters, so ‘parameter’ is checked against this group’s type. ‘pressure’ is never mappable. A group takes at most one enabled map per parameter.
The source is resolved when the scene is built, so the vertex group or attribute does not have to exist yet. A vertex group is read by name from the object; an attribute is read from the evaluated mesh on the POINT domain, which is where a Store Named Attribute node writes one.
- Parameters:
group_uuid – UUID of the group to add the map to.
parameter – Solver key to vary. One of young-mod, bend, friction, deformation-damping, bending-damping, strain-limit, plasticity, bend-plasticity, bend-warp, bend-weft.
source_type – VERTEX_GROUP to read weight paint, ATTRIBUTE to read a float attribute off the evaluated mesh.
source_name – Name of the vertex group or float attribute holding the weights at the start frame.
target_value – Value reached where the weight is 1, in the same units as the group’s own slider for this parameter.
enabled – Whether the map is included in the simulation.
- set_material_map(group_uuid: str, index: int, parameter: str | None = None, source_type: str | None = None, source_name: str | None = None, target_value: float | None = None, enabled: bool | None = None)#
Edit fields of an existing spatial material map.
Every field left out keeps its current value. The whole resulting row is validated before anything is written, so a refusal leaves the map exactly as it was. That means changing ‘parameter’ alone can be refused because the target already stored is below the new parameter’s own minimum; pass both in one call.
- Parameters:
group_uuid – UUID of the group that owns the map.
index – Zero-based index as reported by list_material_maps.
parameter – New solver key to vary, or omit to keep the current one.
source_type – VERTEX_GROUP or ATTRIBUTE, or omit to keep the current one.
source_name – New vertex group or attribute name, or omit to keep it.
target_value – New value reached where the weight is 1, or omit to keep it.
enabled – Whether the map is included in the simulation, or omit to keep the current setting.
- remove_material_map(group_uuid: str, index: int)#
Remove a spatial material map and every weight source on it.
- Parameters:
group_uuid – UUID of the group that owns the map.
index – Zero-based index as reported by list_material_maps. Removing a map renumbers the ones after it.
- list_material_maps(group_uuid: str)#
List a group’s spatial material maps and its mappable parameters.
Each map reports the slider it blends away from as ‘base_property’, and ‘gate_closed_reason’ whenever the parameter is switched off for the whole solve, in which case the build refuses the map: a map target cannot reintroduce a value the group turned off.
‘available_parameters’ is what this group’s object type can map, which is what add_material_map accepts. ‘start_frame’ is the frame the map’s own source describes, and every weight sample has to sit after it.
- Parameters:
group_uuid – UUID of the group to report.
- add_material_map_sample(group_uuid: str, index: int, frame: int, source_name: str, source_type: str | None = None)#
Add a later weight source to a spatial material map.
The map’s own source is the weights at the simulation start frame, and each sample names a different source reached at its own frame. Between two consecutive samples the weights are the linear interpolation of the two, so a constant hold is two samples naming one source.
A frame at or before the start frame is refused, because the map’s own source already describes that frame. Only a SHELL group carries a per-element material schedule, so a map on any other type takes a single source and no samples.
- Parameters:
group_uuid – UUID of the group that owns the map.
index – Zero-based index of the map, as reported by list_material_maps.
frame – Blender frame at which the weights are exactly this source.
source_name – Vertex group or float attribute holding this sample’s weights.
source_type – VERTEX_GROUP or ATTRIBUTE. Omit to use the map’s own source type.
- remove_material_map_sample(group_uuid: str, index: int, frame: int)#
Remove the weight source at a given frame from a material map.
The map’s own source is not a sample and cannot be removed here; change it with set_material_map instead.
- Parameters:
group_uuid – UUID of the group that owns the map.
index – Zero-based index of the map, as reported by list_material_maps.
frame – Frame of the sample to remove, as reported by list_material_maps.
Presets#
- list_material_presets(object_type: str | None = None)#
List the bundled material presets and the parameters each one writes.
A preset carries an object_type that decides which groups may take it: a SHELL group is offered the fabrics and a SOLID group the soft solids, and apply_material_preset refuses a mismatch. A Type the library ships no preset for gives an empty list rather than an error, so an empty result is an answer and not a failure.
‘parameters’ is what applying the preset writes, keyed by group property name. ‘unknown_keys’ names any key in the preset table that matches no group property; those are written by nothing, and a non-empty list is a defect in the bundled file rather than something a caller can act on.
- Parameters:
object_type – Group Type to filter by, one of SOLID, SHELL, ROD, STATIC, PDRD, SAND. Omit to list every preset.
- apply_material_preset(group_uuid: str, preset_name: str)#
Write a bundled material preset’s parameters onto a dynamics group.
The preset’s object_type has to match the group’s Type. Applying one never changes the Type, so a fabric preset on a SOLID group would write shell parameters that group’s elements never read, and it is refused instead. Use set_group_type first, or pick a preset for the Type the group has.
A parameter the group has locked keeps its value, which is what the padlock beside it promises against the tools that overwrite a whole group at once. Locked parameters are reported under ‘kept_locked’.
‘written’ reports every parameter that now carries the preset’s value, including any that already did. A parameter whose property did not take the preset’s value leaves the group holding part of the preset and raises, naming the value asked for and the value the group now holds.
- Parameters:
group_uuid – UUID of the group to write the preset onto.
preset_name – Preset name as reported by list_material_presets.
- list_profiles(kind: str, group_uuid: str | None = None, path: str | None = None)#
List the entries of a profile file, for one of the four profile kinds.
A profile file holds several entries, one TOML table per name, and the scene binds one file and one selected entry per kind. With no ‘path’ the bound file is read, and a kind with no file bound is refused rather than reported as empty.
MATERIAL and PIN bind their file to a dynamics group, so both need group_uuid; SCENE and CONNECTION refuse one.
‘unrecognized_keys’ names keys of an entry that this kind’s apply drops, which is what an entry saved under a different kind looks like from here.
- Parameters:
kind – SCENE, MATERIAL, PIN or CONNECTION.
group_uuid – UUID of the group the file is bound to, for MATERIAL and PIN.
path – Profile file to read instead of the bound one. Absolute, or ‘//’ relative to a saved .blend.
- save_profile(kind: str, name: str, group_uuid: str | None = None, vertex_group_identifier: str | None = None, path: str | None = None)#
Save current settings as a named entry in a profile file.
Each kind reads a different part of the scene: SCENE the solver parameters, the dynamic parameter schedules and the invisible colliders; MATERIAL one group’s material parameters, and no pins; PIN the operations of one pin; CONNECTION the solver host settings. MATERIAL and PIN need group_uuid, and PIN also needs vertex_group_identifier.
An entry that already carries this name is replaced, and the result says so under ‘replaced_existing_entry’. Every other entry in the file is kept. A file whose top level carries a key outside an [entry] table is refused before anything is written, because the writer emits entry tables only and would destroy the rest of the file; edit such a file by hand first. With no ‘path’ the file already bound is written, which for MATERIAL and PIN is the file bound to the group and for SCENE and CONNECTION the file bound to the scene; passing one writes that file and binds it, which is what the panel’s Save button does with a file it was just given. The file and the entry become the selection the panel shows.
- Parameters:
kind – SCENE, MATERIAL, PIN or CONNECTION.
name – Entry name to write. An entry named NONE is refused, since that identifier means “no profile” in the dropdowns.
group_uuid – UUID of the group to read, for MATERIAL and PIN.
vertex_group_identifier – Pin to read, in ‘object_name::vertex_group_name’ form, for PIN. The pin also becomes the one selected in the panel, which is how the pin profile picker addresses a pin.
path – Profile file to write instead of the bound one. Absolute, or ‘//’ relative to a saved .blend.
- load_profile(kind: str, name: str, group_uuid: str | None = None, vertex_group_identifier: str | None = None, path: str | None = None)#
Apply a named entry from a profile file onto the scene.
The entry overwrites every setting its kind covers, so a MATERIAL entry replaces the group’s material parameters, including its Type and, when the entry embeds pins, the operations of the pins it names. A material lock does not hold against a profile load; it guards against the presets and the clipboard.
An entry whose keys this kind’s apply understands none of is refused rather than applied as nothing, which is what loading an entry saved under a different kind would otherwise look like. Keys the apply does drop are reported under ‘ignored_keys’, for an entry written by an older build.
Every value the entry names for one of this kind’s own parameters is read back off its property afterwards and compared with what the entry asked for, and a value the property did not take raises, naming both. Blender clamps a number outside a property’s range and reports nothing, so a value the entry names is otherwise reported as applied while the property holds something else. A PIN entry’s operations are rebuilt rather than assigned to properties this way, so they are reported as applied without that comparison.
The file and the entry become the selection the panel shows.
- Parameters:
kind – SCENE, MATERIAL, PIN or CONNECTION.
name – Entry name, as reported by list_profiles.
group_uuid – UUID of the group to write, for MATERIAL and PIN.
vertex_group_identifier – Pin to write, in ‘object_name::vertex_group_name’ form, for PIN. The pin also becomes the one selected in the panel, which is how the pin profile picker addresses a pin.
path – Profile file to read instead of the bound one. Absolute, or ‘//’ relative to a saved .blend.
- clear_profile_path(kind: str, group_uuid: str | None = None)#
Unbind a profile file from the scene, leaving the file untouched.
This is the panel’s Clear button: the scene stops pointing at the file, and the dropdown for that kind goes empty. Nothing on disk changes, and the settings the last load applied stay as they are. Removing an entry from a profile file has no path in the addon, so no tool here does it.
- Parameters:
kind – SCENE, MATERIAL, PIN or CONNECTION.
group_uuid – UUID of the group the file is bound to, for MATERIAL and PIN.
- copy_material_parameters(group_uuid: str)#
Copy a group’s material parameters into the addon’s material clipboard.
The clipboard holds one set of parameters at a time and lives on the window manager, so it is not saved in the .blend and is empty again after a Blender restart. Copying records the source group’s Type as well, which decides which parameters a later paste applies.
This copies parameters only. Identity, the group’s Type, its overlay color, its profile bindings, its per parameter locks and everything owned by an assigned object stay with their own group.
- Parameters:
group_uuid – UUID of the group to copy from.
- paste_material_parameters(group_uuid: str)#
Paste the material clipboard onto a group, keeping its locked values.
Call copy_material_parameters first: the clipboard lives on the window manager, so a paste is refused after a restart, and after a session that never copied.
A parameter the target has locked keeps its value, which is what the padlock beside it promises; those are reported under ‘kept_locked’. A parameter only the source’s Type reads is not pasted at all, so a paste between two Types carries the shared parameters and leaves the target’s own model fields alone. The target’s Type never changes.
- Parameters:
group_uuid – UUID of the group to paste onto.
- copy_pin_operations(group_uuid: str, vertex_group_identifier: str)#
Copy one pin’s operations into the addon’s pin operation clipboard.
The clipboard holds the operations of one pin at a time and lives on the window manager, so it is not saved in the .blend and is empty again after a Blender restart. The pin named here also becomes the one selected in the panel, which is how the pin clipboard addresses a pin.
- Parameters:
group_uuid – UUID of the group that owns the pin.
vertex_group_identifier – Pin in ‘object_name::vertex_group_name’ form, as reported by list_pins.
- paste_pin_operations(group_uuid: str, vertex_group_identifier: str)#
Paste the pin operation clipboard onto a pin, replacing its operations.
Every operation the target pin carries is discarded and replaced by the clipboard’s, so this is not an append. Call copy_pin_operations first: the clipboard lives on the window manager, so a paste is refused after a restart, and after a session that never copied.
The pin named here also becomes the one selected in the panel, which is how the pin clipboard addresses a pin.
- Parameters:
group_uuid – UUID of the group that owns the pin.
vertex_group_identifier – Pin in ‘object_name::vertex_group_name’ form, as reported by list_pins.
Statistics#
- list_statistics_objects()#
List the objects the solver recorded statistics for, with their channels.
The statistics are whatever is on disk from the last simulation whose frames were fetched, so this reports a past run, not what the scene would produce if it were run now.
object_nameis the object’s name in the scene at this moment and is null when its UUID resolves to nothing, which happens once the object is deleted; passobject_uuidto the other statistics tools in that case.recorded_nameanddynamics_typeare what the solver stored at run time.channelsholds the channel ids measured for that object, which is the set get_object_statistics_series accepts for it, andchannel_cataloggives every channel’s label and unit.start_frameis the Blender frame the solve starts on, which every frame number in these tools is expressed against.
- get_object_statistics(object_name: str, frame: int)#
Read every channel the solver measured for one object at one frame.
frameis a Blender timeline frame, the same number the statistics panel shows, and it is converted to the solver frame by subtracting the start frame reported aseffective_start_frameby get_scene_parameters.Only the channels the object supports are returned, since which quantities exist depends on what the object is: a rod has a length, a solid has a volume. The remaining ids are listed under
unsupported_channels. A supported channel whose value the solver did not record for this frame comes back with a nullvalue.A frame the run never wrote is refused rather than reported as zero; call get_object_statistics_series for the frames that are present.
- Parameters:
object_name – Blender object name, or the object_uuid from list_statistics_objects when the object is gone from the scene.
frame – Blender timeline frame to read.
- get_object_statistics_series(object_name: str, channel: str, frame_start: int | None = None, frame_end: int | None = None)#
Read one channel of one object across frames, as the CSV export does.
Returns one sample per recorded frame, each carrying the Blender frame, the simulated time in seconds, and the value. The channel is a single id from list_statistics_objects, so a vector is read one component at a time (LOCATION_X, LOCATION_Y, LOCATION_Z), and a channel the object does not support is refused instead of answered with nulls. A sample whose value the solver did not record for that frame carries a null
value.The window bounds are Blender frames and both ends are inclusive. Leaving one out extends the window to the recorded frames on that side, so leaving both out returns every frame in the cache. An empty
sampleslist means no frame in the window has been recorded yet.- Parameters:
object_name – Blender object name, or the object_uuid from list_statistics_objects when the object is gone from the scene.
channel – Channel id, for example SPEED or CONTACT_COUNT.
frame_start – First Blender frame to include; omit for the earliest recorded frame.
frame_end – Last Blender frame to include; omit for the latest recorded frame.