Scripting in Fusion
The globals a fusionctl script gets, the API's centimetres, which way each sketch plane points, user parameters, and recipes taken from examples/bracket.py.
fusionctl exec and fusionctl run send Python to the add-in, which runs it on Fusion's main thread with the full adsk API. These notes were checked on Fusion 2705.1.30.
Globals
| Name | What it is |
|---|---|
app | adsk.core.Application |
ui | app.userInterface (do not open dialogs with it, see below) |
design | the active adsk.fusion.Design |
root | design.rootComponent |
adsk | the adsk package (adsk.core, adsk.fusion, …) |
mm(v) | millimetres to the API's centimetres: mm(5) returns 0.5 |
P(x, y, z) | adsk.core.Point3D.create |
V(v) | adsk.core.ValueInput.createByReal (API units) |
VS(s) | adsk.core.ValueInput.createByString, e.g. VS("12 mm") or VS("width / 2") |
Anything else a script defines (variables, functions) stays available to the next exec or run until fusionctl reset or fusionctl new. The globals above are refreshed on every call, so design and root always point at the active document.
Returning values
print() output is captured and printed by the CLI. Set result to return a value as JSON:
fusionctl exec 'result = {"bodies": root.bRepBodies.count, "features": design.timeline.count}'A value that is not JSON-serialisable is returned as its repr(). With --json, the CLI prints the whole reply, stdout and result included.
Units
The API works in centimetres and radians, whatever the document's display units. Writing millimetre numbers into Point3D makes the part ten times too large and raises no error.
P(mm(40), 0, 0) # 40 mm along X
VS("12 mm") # a length from an expression, stays parametric
VS("width / 2") # an expression over user parametersPrefer VS(...) with an expression for feature sizes, so the feature follows the parameters.
Sketch planes
For sketches created through the API on the origin planes:
| Plane | sketch +X | sketch +Y | extrude (+) |
|---|---|---|---|
xYConstructionPlane | world +X | world +Y | +Z |
xZConstructionPlane | world +X | world −Z | +Y |
yZConstructionPlane | world −Z | world +Y | +X |
On XZ, a point at world height z is P(x, -z, 0) in sketch coordinates. The bracket script keeps that in one helper:
xz = lambda x, z: P(x, -z, 0) # world (x, z) -> XZ sketch coordinatesSketches on body faces choose their own axes: check sketch.xDirection or convert with sketch.modelToSketchSpace(...).
Orientation
fusionctl ping reports orientation. On a Z-up install the print bed is the XY plane and +Z is up. On a Y-up install the floor is XZ. The bracket script assumes Z-up; check before you reuse it.
Parameters
Create user parameters first and refer to them by name in dimensions and features. Then fusionctl params --set changes the part and the timeline regenerates.
params = {
"length": "40 mm", # base, along X
"height": "30 mm", # wall, along Z
"width": "24 mm", # along Y
"thick": "4 mm",
"hole_d": "4.5 mm", # M4 clearance, ISO 273 medium
"bend_r": "3 mm", # inner fillet: stiffens the bend
"bed_chamfer": "0.6 mm" # chamfer, not fillet, on edges touching the bed (elephant foot)
}
for name, expr in params.items():
p = design.userParameters.itemByName(name)
if p is None:
design.userParameters.add(name, VS(expr), "mm", "")The itemByName check makes the script safe to run twice in the same design.
Recipes from the bracket
Dimension a sketch to a parameter
Place the geometry at its current size, then dimension it and set the dimension's expression:
d = dims.addDistanceDimension(seg.startSketchPoint, seg.endSketchPoint, orient, at)
d.parameter.expression = "length"Extrude symmetrically by a parameter
ext_in = root.features.extrudeFeatures.createInput(
sk.profiles.item(0), adsk.fusion.FeatureOperations.NewBodyFeatureOperation)
ext_in.setSymmetricExtent(VS("width"), True)
ext = root.features.extrudeFeatures.add(ext_in)Holes that follow the parameters
A bare sketch point does not move when parameters change. Dimension it to the sketch origin with an expression:
hs.sketchDimensions.addDistanceDimension(
hs.originPoint, a, H_, P(x0, -W / 2 - 0.5, 0)
).parameter.expression = "thick + (length - thick) / 2"Two sketch points that share an X cannot both get a horizontal dimension from the origin: Fusion reports VCS_SKETCH_OVER_CONSTRAINTS with no visible constraint. Dimension the first point fully, give the second only its Y, then tie the X:
hs.geometricConstraints.addVerticalPoints(a, b)A hole drills against its sketch normal. From a sketch on the XY plane at the bed, that is −Z, away from the part. Drill up through the base with:
h_in.setAllExtent(adsk.fusion.ExtentDirections.NegativeExtentDirection)Find a face or an edge by geometry
def face_at(normal, pred):
for f in body.faces:
ok, n = f.evaluator.getNormalAtPoint(f.pointOnFace)
if ok and n.isEqualTo(normal) and pred(f.pointOnFace):
return f
raise RuntimeError("face not found")
outer = face_at(adsk.core.Vector3D.create(-1, 0, 0), lambda p: abs(p.x) < 1e-6)The script selects the bend edge (a line along Y at x = z = thick) and the bed edges (lines at z = 0) the same way, then fillets and chamfers them with VS("bend_r") and VS("bed_chamfer"). It returns the edge counts in result, so a wrong selection shows up as a number.
Things that break a session
- Modal dialogs.
ui.messageBox, selection prompts and other dialogs block Fusion's main thread, so the bridge cannot answer and the CLI times out. Print instead. - Occurrences. New occurrences are grounded to their parent: setting
occurrence.transform2is ignored untiloccurrence.isGroundToParent = False. Then calldesign.snapshots.add()ifdesign.snapshots.hasPendingSnapshot. - 3MF export. The API method is
createC3MFExportOptions.fusionctl export part.3mfhandles it. - Renamed methods. Older samples use names that have changed. Check with
fusionctl apidoc ExtrudeFeatures.addSimpleagainst the installed build instead of guessing.
Made by Lucas Piera. MIT licence. fusionctl is not affiliated with or endorsed by Autodesk; Autodesk and Fusion are trademarks of Autodesk, Inc.
Commands
Every fusionctl command with its usage line, what it prints and the options it takes. Usage lines are copied from fusionctl <command> --help.
Verifying a part
A script that ran without an exception is not proof that the geometry is right. Check the timeline, the bodies, interference and screenshots after every step, and print a test piece.