Reads a .plasticity file, decodes only the curve objects (lines, arcs,
circles, ellipses, NURBS) with their exact control points, weights and knots,
and writes them into a .blend file (plus a JSON dump and a preview image).
You need Plasticity and
Blender installed in /Applications, and a
Python 3.10+ (python.org, Homebrew, or Blender's own Python is used
automatically).
-
Download / clone this repo (Code → Download ZIP, unzip anywhere).
-
Double-click
Make Droplet.commandonce. It buildsPlasticity2Blend.appnext to it. (If macOS says the file can't be opened: right-click → Open, or runchmod +x *.commandin Terminal.) -
Drag one or more
.plasticityfiles ontoPlasticity2Blend.app. A Terminal window shows progress; next to each input you get<name>.curves.blend Blender file, one curve object per Plasticity curve <name>.curves.json control points / weights / knots of every edge <name>.curves.png orthographic front view for a quick checkThe first run creates a
.venvfolder and installsparasolid-kit(needs internet once).
Double-clicking Plasticity2Blend.command itself opens a file chooser
instead (Finder cannot drop files onto a .command, hence the droplet app).
python3 plasticity2blend.py "sakina tilk.plasticity" out.blend
python3 plasticity2blend.py "sakina tilk.plasticity" --json curves.json # geometry only, no Blender
python3 plasticity2blend.py in.plasticity out.blend --preview check.png # + orthographic render
python3 plasticity2blend.py in.plasticity out.blend --all-nurbs --scale 1000
./Plasticity2Blend.command a.plasticity b.plasticity # same as dropping
Requirements
- Python 3.10+ and
pip install -r requirements.txt(onlyparasolid-kit) - Plasticity installed (its app bundle contains the Parasolid schema catalogs
the parser needs; override with
--schema-dir/$PLASDECODE_SCHEMA_DIR) - Blender 4.x/5.x for
.blendoutput (found automatically in/Applications,$BLENDER, or--blender PATH)
Windows/Linux: the Python CLI works the same; only the .command launcher and
the droplet are macOS-specific. Point --schema-dir at Plasticity's
resources/app/.webpack/main/parasolid-schema folder.
Options
| flag | meaning |
|---|---|
--json PATH |
write decoded geometry (raw Parasolid data and Bezier pieces) as JSON |
--all-nurbs |
store every spline as NURBS with weights instead of Bezier splines |
--scale S |
multiply coordinates (data is in meters; 1000 gives millimeters) |
--collection NAME |
Blender collection to put the objects in |
--bevel D |
bevel depth for the curve objects (0 = wire only) |
--preview PNG |
render a front orthographic view for a visual check |
Each Blender object is named like the Plasticity outliner entry and carries
custom properties plasticity_item (index in the file) and
plasticity_stable_id.
.plasticity is a small glTF-style binary container (little-endian):
| offset | size | content |
|---|---|---|
| 0 | 10 | magic plasticity |
| 10 | 4 | uint32 container version (1) |
| 14 | 4 | uint32 total file length |
| 18 | 4 | uint32 JSON chunk length n |
| 22 | 4 | JSON |
| 26 | n | JSON document |
| 26+n | 4 | uint32 BIN chunk length m |
| 30+n | 4 | BIN\0 |
| 34+n | m | binary buffer 0 |
The JSON (asset.version 2.5 for Plasticity 25.3) contains:
nodes[]— outliner entries{"item": i, "name": "Bridge curve.001"}(also{"group": g},{"measurement": m}), which give items their names;items[]— one per solid/sheet/curve:{"bufferView": k, "stableId": id, "lods": [{"mesh": j}]}. Curve items have nolods(solids and sheets carry tessellated display meshes there); this is how curves are told apart;bufferViews[]—{"buffer": 0, "byteOffset": o, "byteLength": l}slices of the binary buffer;meshes[]etc. describe the display tessellation and are ignored here.
Every item's bufferView is a complete Parasolid binary transmit file
("X_B", signature PS, header TRANSMIT FILE created by modeller version 3800198, schema key e.g. SCH_3800198_37102_13006). Plasticity uses the
Parasolid kernel, so this is the native B-Rep, not an export.
The X_B node stream is schema-driven; to read it one needs the schema catalog named in the header. Plasticity ships them:
/Applications/Plasticity.app/Contents/Resources/app/.webpack/main/parasolid-schema/sch_13006.sch_txt
We parse the stream with parasolid-kit
(read_brep(blob, schema_dir=...)), which resolves the schema and maps the
nodes to a typed B-Rep model.
A curve object is a Parasolid wire body: BODY → REGION → SHELL → EDGEs,
each edge with two VERTEX nodes (each holding a POINT) and a geometric
curve node:
| Parasolid node | data |
|---|---|
LINE |
point, unit direction (unbounded) |
CIRCLE |
center, normal, x_axis, radius (full circle) |
ELLIPSE |
center, normal, x_axis, major/minor radius |
NURBS_CURVE + BSPLINE_VERTICES + KNOT_SET + KNOT_MULT |
degree, periodic/closed flags, control vertices (homogeneous wx wy wz w when rational), distinct knots + multiplicities |
SP_CURVE |
a 2-D NURBS curve in the parameter space of a surface (used e.g. by Offset curve) |
Important details when reconstructing an edge:
- Curves are unbounded/full; the edge's extent comes from its two vertex
points. For lines the piece is simply start→end. For circles the angles of
the vertex points are measured from
x_axistowardsnormal × x_axis. For NURBS the vertex points are inverted to parameters (closest point) and the portion is cut out exactly by knot insertion. - Every curve node has a
sense(+/-).-means the edge runs from its start vertex to its end vertex against the curve's parametric direction. - An edge with no vertices (or identical vertices) is a closed loop (full circle, whole periodic NURBS).
- Periodic NURBS (
periodic = true, e.g. Plasticity's Circle.002/003, which are actually degree-3 B-spline approximations of circles) carry wrapped control points and an extended knot vector; the parametric domain is[knots[degree], knots[n]]and a trimmed portion may wrap through the seam. - Coordinates are in meters even though Plasticity's UI shows mm.
- An
SP_CURVEon an offset surface (an offset of a B-spline surface) has no exact NURBS form; the tool samples it into a polyline and reports a warning.
For every curve item: name, item, stable_id, closed_loop, and per
edge
kind,sense,start,end,closedgeometry— the raw Parasolid definition (line point/direction; circle center/normal/x_axis/radius and the arc angles; NURBS degree, control points, weights, full knot vector, periodic flag, and the edge's parameter interval)bezier— the edge as exact rational Bezier segments in chain order:{"degree": d, "segments": [{"points": [[x,y,z]...], "weights": [w...]}]}. Circle/ellipse arcs become quadratic rational segments (≤ 90° each, middle weightcos(θ/2)), NURBS become segments of their own degree, lines are degree 1.
This Bezier form is what any downstream tool needs to reproduce the curve exactly: points + weights per segment, no knot vectors required.
| piece | Blender spline |
|---|---|
| lines / polylines | POLY |
| non-rational degree 2/3 | BEZIER (quadratics degree-elevated to cubic; handles = control points) |
rational (arcs, circles) or --all-nurbs |
NURBS, order = degree+1, Bezier + Endpoint knot mode, weights in point.co.w |
| degree ≥ 4 | one single-span NURBS spline (Endpoint mode) per segment |
| sampled SP curves | POLY |
Blender's legacy curves expose no custom knot vector, but its Bezier knot mode generates exactly the piecewise-Bezier knot vector (verified for orders 3 and 4 to ~1e-7), so a run of segments of equal degree fits in one NURBS spline with no loss.
plasticity2blend.py CLI entry point
plasdecode/container.py .plasticity container reader
plasdecode/decode.py Parasolid wire bodies -> exact Bezier pieces (+JSON)
plasdecode/nurbs.py knot insertion, Bezier extraction, point inversion, arcs
plasdecode/blender_import.py runs inside Blender, builds splines, saves .blend
plasdecode/cli.py argument handling and Blender subprocess
