# Primitive and Profile Operation Serialization This guide covers replayable primitive/profile operations in the canonical operation graph. All examples assume: ```python import json import simplecadapi as scad with scad.GraphSession() as session: ... payload = json.loads(scad.export_model_json(session)) ``` In exported JSON, each operation appears in `payload["graph"]["nodes"]` as: ```json { "node_id": "node_xxxxxxxx", "op": "make_line_redge", "params": {...}, "inputs": [], "output_count": 1, "tags": [...], "display": {...}, "param_exprs": {...}, "context": {...} } ``` `display`, `tags`, `context`, `semantic_delta`, and `topo_delta` are useful metadata. Replay primarily depends on `op`, `params`, and `inputs`. ## Point Source: ```python p = scad.make_point_rvertex(1.0, 2.0, 3.0) ``` Serialized node: ```json { "op": "make_point_rvertex", "params": {"x": 1.0, "y": 2.0, "z": 3.0}, "inputs": [], "output_count": 1 } ``` Replay effect: calls `make_point_rvertex(x, y, z)` and returns a `Vertex`. ## Line edge Source: ```python edge = scad.make_line_redge((0, 0, 0), (5, 0, 0)) ``` Serialized node: ```json { "op": "make_line_redge", "params": {"start": [0.0, 0.0, 0.0], "end": [5.0, 0.0, 0.0]}, "inputs": [], "output_count": 1 } ``` Replay effect: calls `make_line_redge(start, end)` and returns an `Edge`. ### Segment aliases `make_segment_redge(start, end)` is an alias of `make_line_redge(...)` and records the same `make_line_redge` node. `make_segment_rwire(start, end)` lowers to: 1. `make_line_redge` 2. `make_wire_from_edges_rwire` There is no canonical `make_segment_wire` node in model JSON. ## Circle edge, wire, and face Source edge: ```python edge = scad.make_circle_redge((0, 0, 0), 2.0, normal=(0, 0, 1)) ``` Serialized node: ```json { "op": "make_circle_redge", "params": { "center": [0.0, 0.0, 0.0], "radius": 2.0, "normal": [0.0, 0.0, 1.0] }, "inputs": [], "output_count": 1 } ``` Replay effect: calls `make_circle_redge(center, radius, normal)`. Source wire: ```python wire = scad.make_circle_rwire((0, 0, 0), 2.0) ``` Lowered serialized graph: ```text make_circle_redge -> make_wire_from_edges_rwire ``` Source face: ```python face = scad.make_circle_rface((0, 0, 0), 2.0) ``` Lowered serialized graph: ```text make_circle_redge -> make_wire_from_edges_rwire -> make_face_from_wire_rface ``` There is no canonical `make_circle_wire` or `make_circle_face` node. ## Three-point arc edge and wire Source edge: ```python arc = scad.make_three_point_arc_redge( (0, 0, 0), (1, 1, 0), (2, 0, 0), ) ``` Serialized node: ```json { "op": "make_three_point_arc_redge", "params": { "start": [0.0, 0.0, 0.0], "middle": [1.0, 1.0, 0.0], "end": [2.0, 0.0, 0.0] }, "inputs": [], "output_count": 1 } ``` Replay effect: calls `make_three_point_arc_redge(start, middle, end)`. `make_three_point_arc_rwire(...)` lowers to: ```text make_three_point_arc_redge -> make_wire_from_edges_rwire ``` ## Angle arc edge and wire Source edge: ```python arc = scad.make_angle_arc_redge( center=(0, 0, 0), radius=1.0, start_angle=0.0, end_angle=1.57, normal=(0, 0, 1), ) ``` Serialized node: ```json { "op": "make_angle_arc_redge", "params": { "center": [0.0, 0.0, 0.0], "radius": 1.0, "start_angle": 0.0, "end_angle": 1.57, "normal": [0.0, 0.0, 1.0] }, "inputs": [], "output_count": 1 } ``` Replay effect: calls `make_angle_arc_redge(center, radius, start_angle, end_angle, normal)`. `make_angle_arc_rwire(...)` lowers to: ```text make_angle_arc_redge -> make_wire_from_edges_rwire ``` ## Spline edge and wire Source edge: ```python fit = scad.fit_cubic_bspline_control_points( [(0, 0, 0), (1, 1, 0), (2, 0, 0)], tolerance=0.01, ) spline = scad.make_spline_redge( control_points=fit.control_points, knots=fit.unique_knots, multiplicities=fit.multiplicities, ) ``` Serialized node: ```json { "op": "make_spline_redge", "params": { "control_points": [[0.0, 0.0, 0.0], [0.6, 1.0, 0.0], [1.4, 1.0, 0.0], [2.0, 0.0, 0.0]], "degree": 3, "knots": [0.0, 1.0], "multiplicities": [4, 4], "weights": null, "periodic": false }, "inputs": [], "output_count": 1 } ``` Replay effect: calls `make_spline_redge(control_points=..., degree=..., knots=..., multiplicities=..., weights=..., periodic=...)`. `make_spline_rwire(control_points=..., ...)` lowers to: ```text make_spline_redge -> make_wire_from_edges_rwire ``` `make_spline_redge` now stores an exact B-spline definition. It does not accept sampled/interpolated curve points directly; use `fit_cubic_bspline_control_points(...)` first when human/LLM-authored code starts from samples. ## Helix edge and wire Source edge: ```python helix = scad.make_helix_redge( pitch=0.7, height=2.2, radius=0.9, center=(0, 0, 0), dir=(0, 0, 1), ) ``` Serialized node: ```json { "op": "make_helix_redge", "params": { "pitch": 0.7, "height": 2.2, "radius": 0.9, "center": [0.0, 0.0, 0.0], "dir": [0.0, 0.0, 1.0] }, "inputs": [], "output_count": 1 } ``` Replay effect: calls `make_helix_redge(pitch, height, radius, center, dir)`. `make_helix_rwire(...)` lowers to: ```text make_helix_redge -> make_wire_from_edges_rwire ``` ## Wire from edges Source: ```python a = scad.make_line_redge((0, 0, 0), (1, 0, 0)) b = scad.make_line_redge((1, 0, 0), (1, 1, 0)) wire = scad.make_wire_from_edges_rwire([a, b]) ``` Serialized node: ```json { "op": "make_wire_from_edges_rwire", "params": {"edge_count": 2}, "inputs": ["node_for_a", "node_for_b"], "output_count": 1 } ``` Replay effect: 1. Replay each input edge node. 2. Collect input edge outputs in input order. 3. Call `make_wire_from_edges_rwire(edges)`. The actual edge geometry is not duplicated inside this node; it is recovered through `inputs`. ## Face from wire Source: ```python face = scad.make_face_from_wire_rface(wire, normal=(0, 0, 1)) ``` Serialized node: ```json { "op": "make_face_from_wire_rface", "params": {"normal": [0.0, 0.0, 1.0]}, "inputs": ["node_for_wire"], "output_count": 1 } ``` Replay effect: 1. Replay the input wire node. 2. Call `make_face_from_wire_rface(wire, normal=...)`. ## Rectangle wire and face lowering Source: ```python wire = scad.make_rectangle_rwire(4.0, 2.0, center=(0, 0, 0)) face = scad.make_rectangle_rface(4.0, 2.0, center=(0, 0, 0)) ``` Lowered serialized graph: ```text make_rectangle_rwire: make_line_redge x4 -> make_wire_from_edges_rwire make_rectangle_rface: make_line_redge x4 -> make_wire_from_edges_rwire -> make_face_from_wire_rface ``` There is no canonical `make_rectangle_wire` or `make_rectangle_face` node. ## Polyline wire lowering Source: ```python wire = scad.make_polyline_rwire( [(0, 0, 0), (1, 0, 0), (1, 1, 0)], closed=False, ) ``` Lowered serialized graph: ```text make_line_redge x(number_of_segments) -> make_wire_from_edges_rwire ``` If `closed=True`, one additional closing line edge is emitted. There is no canonical `make_polyline_wire` node. ## Box, cylinder, sphere, and cone lowering These user-facing primitive solids are intentionally lowered to canonical profile/feature operations. ### Box Source: ```python box = scad.make_box_rsolid(4.0, 2.0, 1.0) ``` Lowered serialized graph: ```text make_line_redge x4 -> make_wire_from_edges_rwire -> make_face_from_wire_rface -> make_extrude_rsolid ``` Replay effect: rebuilds the rectangular face, then extrudes it. There is no canonical `make_box` node. ### Cylinder Source: ```python cyl = scad.make_cylinder_rsolid(1.0, 3.0) ``` Lowered serialized graph: ```text make_circle_redge -> make_wire_from_edges_rwire -> make_face_from_wire_rface -> make_extrude_rsolid ``` There is no canonical `make_cylinder` node. ### Sphere Source: ```python sphere = scad.make_sphere_rsolid(1.5, center=(0, 0, 0)) ``` Lowered serialized graph: ```text profile edges/wire/face -> make_revolve_rsolid ``` There is no canonical `make_sphere` node. ### Cone / truncated cone Source: ```python cone = scad.make_cone_rsolid(1.2, 2.0, top_radius=0.4) ``` Lowered serialized graph: ```text profile edges/wire/face -> make_revolve_rsolid ``` There is no canonical `make_cone` node.