For the authoritative, single-source-of-truth JSON schema definitions, see:
This page provides context and examples. The master reference is the authoritative source when schemas are updated.
For the authoritative, single-source-of-truth JSON schema definitions, see:
This page provides context and examples. The master reference is the authoritative source when schemas are updated.
The width trim system uses a consistent approach for creating cutting bodies:
For simple cuts with no angle or tilt, a block is created directly at the final position:
sld blo centerX centerY centerZ sizeX sizeY sizeZ 0 0 0 i_body '*** Rotate for compound blade orientation if bladeAngle <> 0 then sld rot 1 i_body 0 0 0 0 0 1 bladeAngle end if
For cuts with draft angles or tilt, the cutter is built in XY plane first, then rotated:
This approach is more reliable than trying to construct angled geometry directly.
The blade generation system uses JSON files to define blade parameters. This allows both interactive UI and headless/batch modes to use identical parameter definitions.
fxReadBladeJSON parses it → blade generated.C:\Program Files\SolidCut_CAD_2025\support\fixture_dev_2026Q1\schemas\blade_params.schema.json
| Section | Purpose | Required |
|---|---|---|
blade |
Core geometry: position, normal, thickness, length | ✓ Yes |
profile |
Profile generation: offset, gravity direction | ✓ Yes |
trimming |
Open sides, extensions, gravity trim | No |
edgeModifications |
Taper, blend, grippers, notches | No |
modularAssembly |
Lego block system parameters | No |
foulingCheck |
Interference checking | No |
dangerZone |
Sharp edge safety marking and blending | No |
output |
Layer, color, DXF options | No |
processingMode |
headless, showProgress, debugLevel | No |
metadata |
Job tracking (jobId, partFile) | No |
Only the required fields - uses defaults for everything else:
{
"version": "1.0",
"blade": {
"position": { "x": 100.0, "y": 0.0, "z": 0.0 },
"normal": { "x": 1.0, "y": 0.0, "z": 0.0 },
"thickness": 6.0
},
"profile": {
"offset": 2.0,
"gravityDirection": "AUTO"
}
}
Open-top blade with gravity and width trim - typical fixture configuration:
{
"version": "1.0",
"metadata": {
"jobId": "BLD-2026-0001",
"partFile": "bracket_assembly.x_t",
"createdAt": "2026-01-11T17:30:00Z"
},
"blade": {
"position": { "x": 150.0, "y": 0.0, "z": 50.0 },
"normal": { "x": 1.0, "y": 0.0, "z": 0.0 },
"thickness": 6.0,
"length": "auto",
"overshoot": 25.0
},
"profile": {
"offset": 2.0,
"gravityDirection": "BOTTOM",
"gravityThreshold": 0.5
},
"trimming": {
"openSide": "top",
"openSideMargin": 15.0,
"sideExtension": {
"left": 10.0,
"right": 10.0
},
"gravityTrim": {
"enabled": true,
"side": "both",
"leftDist": 20.0,
"rightDist": 30.0
},
"widthTrim": {
"enabled": false,
"leftThickness": 5.0,
"rightThickness": 5.0,
"leftAngle": 0.0,
"rightAngle": 0.0,
"leftTilt": 0.0,
"rightTilt": 0.0,
"leftOffset": 0.0,
"rightOffset": 0.0,
"leftTopAngle": 0.0,
"rightTopAngle": 0.0,
"anglePivot": "corner"
},
"safetyBlend": {
"enabled": false,
"radius": 2.0,
"minFaceFactor": 2.0,
"externalOnly": true,
"excludePocket": true
}
},
"edgeModifications": {
"blend": {
"enabled": true,
"radius": 1.0
}
},
"processingMode": {
"showProgress": true,
"progressMinDelta": 10,
"debugLevel": 0
}
}
These control how the blade is trimmed for open-sided fixtures and material reduction:
Direction that gravity acts - determines which faces are "up" vs "down" for trimming operations.
"AUTO" - Derive from blade normal (default). For blade normal in XY plane, gravity is -Z."BOTTOM" - Gravity toward -Z (most common)"TOP" - Gravity toward +Z"LEFT" - Gravity toward -X"RIGHT" - Gravity toward +X"FRONT" - Gravity toward -Y"BACK" - Gravity toward +Y"NONE" - No gravity direction (disables gravity-based operations)AUTO mode: Analyzes the blade normal vector. Gravity is assumed to act on the axis where the blade normal has the smallest component. This works correctly for standard vertical blades and compound angle blades.
Which side of the blade is cut away (open). Relative to gravity direction.
"none" - Full blade, no open side (default)"top" - Cut away top, blade supports from below"bottom" - Cut away bottom (rare, trim fixtures)Extend blade beyond part profile on left/right sides (looking along blade normal).
"sideExtension": {
"left": 10.0, // Extend left side 10mm
"right": 15.0 // Extend right side 15mm
}
Trim blade walls along gravity direction. Keeps material near contact surface, removes material away from contact. Distances are measured from the contact point along the wall - how much to keep, not how much to remove.
"gravityTrim": {
"enabled": true,
"side": "both", // "left", "right", or "both"
"leftDist": 20.0, // Keep 20mm on left wall from contact
"rightDist": 30.0 // Keep 30mm on right wall from contact
}
Use case: When a part rests in a pocket, the wall portions near the floor support the part. The upper portions of the walls can be trimmed away to reduce weight and material cost.
Asymmetric trim: Left and right walls can have different distances - useful when one side of the part is heavier or when access is needed on one side.
Trim blade walls from the outside edge inward toward the pocket. Used for extraction clearance (remove walls entirely) or wall thinning (keep specified thickness).
"widthTrim": {
"enabled": true,
"side": "both", // "none", "left", "right", or "both"
"leftThickness": 0.0, // Wall thickness interpretation:
"rightThickness": 5.0, // 0 = remove wall to pocket edge
// >0 = keep this much wall from pocket edge
// <0 = cut past pocket edge (aggressive)
"leftAngle": 15.0, // Draft angle for extraction (degrees)
"rightAngle": 15.0, // +ve = opens outward at top (V-exit)
"leftTilt": 0.0, // Tilt perpendicular to outer face
"rightTilt": 0.0,
"leftOffset": 10.0, // Vertical offset above pivot reference (mm)
"rightOffset": 10.0,
"leftInset": 0.0, // Horizontal inset from pocket edge (mm)
"rightInset": 0.0, // Only used when thickness <= 0
"anglePivot": "corner" // "corner", "contact", or "bottom"
}
Thickness values:
0 - Remove wall entirely, cut to pocket edge (safe, won't affect center geometry)>0 - Keep this much wall from pocket edge (e.g., 5 = leaves 5mm wall stub)<0 - Aggressive removal, cut past pocket edge toward center (e.g., -10 = cuts 10mm into base area)Angle pivot modes:
The anglePivot parameter controls where the vertical-to-angled transition occurs on the cut face. The cutter is a 5-sided "pencil" shape that creates a vertical wall section below the pivot and an angled wall section above it.
"corner" (recommended for most cases) - Pivot point is calculated from the geometric pocket corner (where the inner wall meets the pocket floor) plus the offset value. This mode uses actual blade geometry rather than user-defined values, making it more reliable for automated processing.
"contact" (default) - Pivot point is at the user-defined contact level (w_FX_CONTACT_LEVEL) plus the offset value. The contact level represents where the part rests in the blade pocket.
"bottom" - Pivot point is at the blade bottom. The entire wall is angled from base to top with no vertical section.
Angled cuts: The angle parameters create draft angles for part extraction. Positive angles open outward at the top, creating a V-shape exit path. The angle pivots from the point specified by anglePivot plus any offset.
Horizontal inset: The inset parameter only applies when removing walls entirely (thickness ≤ 0). It creates a horizontal shelf/ledge at the bottom of the angled cut. For wall thinning (thickness > 0), inset is ignored.
Automatic safety marking for sharp edges on thin blade faces. Identifies dangerous edges and marks them with red strips for operator awareness.
"dangerZone": {
"enabled": false, // Master enable for danger zone marking
"distance": 5, // Width of red strip from edge (mm) - also blend radius
"angleThreshold": 90, // Max angle between faces to mark (degrees)
"blend": false // Apply blend to inner edges between red faces
}
| Parameter | Type | Default | Description |
|---|---|---|---|
enabled |
boolean | false | Master enable for danger zone processing |
distance |
number | 5 | Width of danger strip from edge (mm). Also used as blend radius if blending enabled |
angleThreshold |
number | 90 | Maximum angle between adjacent face normals to consider edge "sharp" (degrees) |
blend |
boolean | false | Apply constant blend to edges where two red (danger) faces meet |
| Global Variable | JSON Path |
|---|---|
i_FX_JSON_DANGER_ZONE_ENABLED | dangerZone.enabled |
w_FX_JSON_DANGER_ZONE_DIST | dangerZone.distance |
w_FX_JSON_DANGER_ZONE_ANGLE | dangerZone.angleThreshold |
i_FX_JSON_DANGER_ZONE_BLEND | dangerZone.blend |
i_FX_DANGER_ZONE_COUNT | (output) Number of zones marked |
'*** Set globals and call directly: i_FX_JSON_DANGER_ZONE_ENABLED = 1 w_FX_JSON_DANGER_ZONE_DIST = 5 w_FX_JSON_DANGER_ZONE_ANGLE = 90 i_FX_JSON_DANGER_ZONE_BLEND = 1 call fxDangerZoneMarking i_bladeBody '*** Check results: write $_FIXTURE_PERSISTENT_MESSAGE 'Danger zones marked: ' i_FX_DANGER_ZONE_COUNT call fxPrintStatus
Control overhead and visual feedback based on context:
| Setting | Effect | Use Case |
|---|---|---|
headless: true |
No GUI, no progress, maximum speed | Batch processing, API calls |
showProgress: false |
Skip NucleoSphere (~1s vs 2-4s per blade) | Quick jobs, batch mode |
progressMinDelta: 25 |
Update every 25% (4 updates, ~1s overhead) | Fast interactive feedback |
progressMinDelta: 10 |
Update every 10% (10 updates, ~2.5s overhead) | Normal interactive use (default) |
debugLevel: 2 |
Verbose debug output to message window | Troubleshooting |
debugLevel value overwrites any value set in your calling macro. To prevent this (e.g., for debugging), set i_FX_DEBUG_LEVEL_OVERRIDE = 1 before calling fxReadBladeJSON. This tells the parser to respect your macro's debug level instead of the JSON value.
'*** Force debug level 2 even if JSON says 0 i_FX_DEBUG_LEVEL = 2 i_FX_DEBUG_LEVEL_OVERRIDE = 1 call fxReadBladeJSON $_jsonPath
headless: true to skip all visual overhead. Processing time drops from ~4 seconds to ~1 second per blade.
Use fxReadBladeJSON to parse a JSON file and populate global variables:
'*** Load blade parameters from JSON
call fxReadBladeJSON 'C:\temp\blade_001.json'
if i_return = i_ERROR then
write $_FIXTURE_PERSISTENT_MESSAGE 'Failed: ' $_return
call fxPrintStatus
termac
end if
'*** Now use the populated globals
call fxCreateBladeFromIntersect i_partBody \
w_FX_JSON_CENTER_X w_FX_JSON_CENTER_Y w_FX_JSON_CENTER_Z \
w_FX_JSON_NORMAL_X w_FX_JSON_NORMAL_Y w_FX_JSON_NORMAL_Z \
w_FX_JSON_THICKNESS w_FX_JSON_STOCK_MARGIN
| Global Variable | JSON Path |
|---|---|
w_FX_JSON_CENTER_X/Y/Z | blade.position.x/y/z |
w_FX_JSON_NORMAL_X/Y/Z | blade.normal.x/y/z |
w_FX_JSON_THICKNESS | blade.thickness |
w_FX_JSON_OFFSET | profile.offset |
$_FX_JSON_GRAVITY_DIR | profile.gravityDirection |
$_FX_JSON_OPEN_SIDE | trimming.openSide |
| Gravity Trim | |
i_FX_JSON_GRAV_TRIM | trimming.gravityTrim.enabled |
w_FX_JSON_GRAV_TRIM_LEFT | trimming.gravityTrim.leftDist |
w_FX_JSON_GRAV_TRIM_RIGHT | trimming.gravityTrim.rightDist |
$_FX_JSON_GRAV_TRIM_SIDE | trimming.gravityTrim.side |
| Width Trim | |
i_FX_JSON_WIDTH_TRIM | trimming.widthTrim.enabled |
w_FX_JSON_WIDTH_TRIM_LEFT | trimming.widthTrim.leftThickness |
w_FX_JSON_WIDTH_TRIM_RIGHT | trimming.widthTrim.rightThickness |
w_FX_JSON_WIDTH_TRIM_LEFT_ANGLE | trimming.widthTrim.leftAngle |
w_FX_JSON_WIDTH_TRIM_RIGHT_ANGLE | trimming.widthTrim.rightAngle |
w_FX_JSON_WIDTH_TRIM_LEFT_TILT | trimming.widthTrim.leftTilt |
w_FX_JSON_WIDTH_TRIM_RIGHT_TILT | trimming.widthTrim.rightTilt |
$_FX_JSON_WIDTH_TRIM_SIDE | trimming.widthTrim.side |
w_FX_JSON_WIDTH_TRIM_LEFT_OFFSET | trimming.widthTrim.leftOffset |
w_FX_JSON_WIDTH_TRIM_RIGHT_OFFSET | trimming.widthTrim.rightOffset |
w_FX_JSON_WIDTH_TRIM_LEFT_INSET | trimming.widthTrim.leftInset |
w_FX_JSON_WIDTH_TRIM_RIGHT_INSET | trimming.widthTrim.rightInset |
$_FX_JSON_WIDTH_TRIM_ANGLE_PIVOT | trimming.widthTrim.anglePivot |
| Gravity Vector (computed from gravityDirection) | |
w_FX_GRAVITY_X/Y/Z | Unit gravity vector (computed) |
i_FX_GRAVITY_AXIS | Gravity axis: 1=X, 2=Y, 3=Z (computed) |
i_FX_GRAVITY_SIGN | Direction: -1 or +1 (computed) |
w_FX_CONTACT_LEVEL | Contact level on gravity axis (set by caller) |
| Processing | |
i_FX_SHOW_PROGRESS | processingMode.showProgress |
w_FX_PROGRESS_MIN_DELTA | processingMode.progressMinDelta |
i_FX_DEBUG_LEVEL | processingMode.debugLevel (unless i_FX_DEBUG_LEVEL_OVERRIDE=1) |
| Danger Zone | |
i_FX_JSON_DANGER_ZONE_ENABLED | dangerZone.enabled |
w_FX_JSON_DANGER_ZONE_DIST | dangerZone.distance |
w_FX_JSON_DANGER_ZONE_ANGLE | dangerZone.angleThreshold |
i_FX_JSON_DANGER_ZONE_BLEND | dangerZone.blend |
i_FX_DANGER_ZONE_COUNT | (output) Number of danger zones marked |
Post-creation features applied to specific blade face zones. Supports grippers, plungers, labels, and other manufacturing features based on face topology.
"edgeFeatures": {
"grippers": {
"enabled": true,
"zones": ["left-inside", "bottom-inside", "right-inside"],
"radius": 3.0,
"interval": 25.0,
"clearance": 0.5,
"depthOffset": 2.0
},
"plungers": {
"enabled": true,
"zones": ["left-inside"],
"width": 12.0,
"depth": 8.0,
"spacing": 50.0,
"fromTop": 15.0
},
"labels": {
"enabled": true,
"zones": ["top-left"],
"text": "BLADE-001",
"height": 5.0,
"depth": 0.3
}
}
Zones are grouped by category:
left-inside, right-inside, bottom-inside, all-insideleft-outside, right-outside, bottom-outside, top-left, top-right, all-outside, all-outside-except-baseall-no-topZFaces, all-everything, all-everything-except-baseReference markers are circular imprints placed on blade faces to identify reference surfaces for fixture alignment. The marked face becomes the datum for positioning operations.
"referenceMarker": {
"enabled": true, // Enable reference marker placement
"diameter": "3mm" // Marker diameter with units
}
Global (in fixtureConfig): Applies to all blades unless overridden
"fixtureConfig": {
"referenceMarker": {
"enabled": true,
"diameter": "3mm",
"color": { "r": 255, "g": 0, "b": 0 }
}
}
Per-Blade Override (in blades array):
"blades": [
{
"id": 1,
"referenceMarker": {
"diameter": "5mm" // Override for this blade only
}
},
{
"id": 2 // Uses global 3mm default
}
]
Both the parent face and the marker face are named for identification:
| Face | Name | Description |
|---|---|---|
| Parent face | sld des fac i_faceID ^24 9999 'Reference Face' |
The planar face selected for marking (datum surface) |
| Marker face | sld des fac i_faceID ^24 9999 'Reference Face Marker' |
The red circular imprint face created on the parent |
Note: The ^24 9999 prefix indicates internationalization-ready strings.
referenceMarker.diameter → use blade valuefixtureConfig.referenceMarker.diameter exists → use global| Global Variable | JSON Path | Description |
|---|---|---|
w_FX_JSON_REFMARKER_DIAMETER | fixtureConfig.referenceMarker.diameter | Global diameter (0 = use default) |
i_FX_JSON_REFMARKER_ENABLED | fixtureConfig.referenceMarker.enabled | Global enable (1=on, 0=off) |
w_FX_BLADE_REFMARKER_DIAMETER | blades[].referenceMarker.diameter | Per-blade override (0 = use global) |
i_FX_BLADE_REFMARKER_FACE_ID | blades[].referenceMarker.faceId | Specific face (0 = auto-detect) |
'*** Interactive mode - pick a face call fxPlaceRefImprint '*** Programmatic mode - specify face ID call fxPlaceRefImprint 512 '*** With per-blade override w_FX_BLADE_REFMARKER_DIAMETER = 5.0 '*** 5mm for this blade call fxPlaceRefImprint i_faceID w_FX_BLADE_REFMARKER_DIAMETER = 0 '*** Reset for next blade
fxPlaceRefImprint.ovm → modeling\blade\fxRefMarker.var → modeling\
| File | Location | Purpose |
|---|---|---|
blade_params.schema.json |
schemas\ |
JSON Schema definition |
blade_params_example.json |
schemas\ |
Full example with trimming |
blade_params_minimal.json |
schemas\ |
Minimal example (required fields only) |
fxReadBladeJSON.ovm |
modeling\blade\ |
JSON parser macro |
fxParseEdgeFeaturesJSON.ovm |
modeling\blade\ |
Edge features JSON parser |
fxPlaceRefImprint.ovm |
modeling\blade\ |
Reference face marker placement macro |
fxRefMarker.var |
modeling\ |
Reference marker global variables |