JavaScript Post Processors
Understand how RabbitCAM X JavaScript post processors turn toolpaths into NC programs, and learn about packages, callbacks, runtime inputs, and customization.
What a Post Processor Does
A Post Processor converts RabbitCAM X's calculated toolpaths into the NC text understood by a particular CNC controller and machine setup.
RabbitCAM X calculates and links the toolpaths, preserves operation order, and supplies movement, tool, spindle, and coolant data. The JavaScript post processor translates that data into the required G-code syntax, number formatting, tool-change sequences, offsets, and program start/end commands.
The same machining project can produce different NC text when processed with different posts. Choose a post that matches the controller and the machine's configuration, including its tool-changing and offset conventions.
This guide explains the shared JavaScript system used by RabbitCAM X post processors.
Generating and Saving an NC Program
- Prepare the operations and review their toolpaths in Simulation.
- Click Post Process to open NC Program Generation.
- Select a post processor from the category tree and review its description and output extension.
- Select the operations to include in the export. Their existing project order is preserved.
- Click Generate NC. RabbitCAM X runs the required license validation and Run & Link, then processes the selected operations.
- Complete any input dialog requested by the selected post processor, such as a program number.
- Review the generated NC preview and choose Save to File. Copy to clipboard copies the preview text; after saving, Open File Location opens its folder.
NC generation requires a signed-in SourceRabbit account with an active RabbitCAM X subscription. If a post specifies a required filename, the save dialog asks for an output folder. Otherwise, you can edit its suggested filename.
The file is saved using the post's output encoding and line endings. After changing an operation or post setting, generate the NC program again.
Post Processor Packages
Each post processor is a package inside the application's Post Processors directory. A typical layout is:
Post Processors/
My Workshop/
Custom 3-Axis Post/
manifest.json
custom-post.js
icon.png
- manifest.json describes the post, its output format, script filename, and default properties.
- custom-post.js contains the JavaScript callbacks that generate NC text.
- icon.png supplies the package icon.
The intermediate folders become categories in the selection tree. The package folder names the tree entry, while the manifest's name appears in the details. Keep these names consistent.
Packages are discovered when RabbitCAM X starts. Restart the application after adding a package or changing its manifest. The script and icon paths must resolve to files inside the package directory.
Understanding the Manifest
The following example shows the required manifest structure and one optional property. Replace the example identity and controller details when creating your own package:
{
"id": "custom.example.3-axis",
"name": "Custom 3-Axis Post",
"version": "1.0.0",
"author": "My Workshop",
"controller": "Custom 3-Axis Controller",
"description": "A custom post processor for a specific 3-axis machine setup.",
"fileExtension": "nc",
"script": "custom-post.js",
"icon": "icon.png",
"supportedAxes": [
"X",
"Y",
"Z"
],
"outputEncoding": "US-ASCII",
"lineEnding": "CRLF",
"properties": {
"writeComments": true
}
}
id identifies the post; use a unique value for a custom package. name, version, author, controller, and description describe it. script and icon identify package files.
fileExtension has no leading dot. outputEncoding selects the saved text encoding, and lineEnding normally uses CRLF or LF. supportedAxes describes the post's intended axes; adding an axis name does not create new CAM or controller support.
properties is optional. Its values must be strings, numbers, or booleans. Property names belong to the individual script: adding a property has an effect only when that script reads and uses it.
How the JavaScript Runs
RabbitCAM X loads the script into a fresh V8 JavaScript runtime for each input-discovery pass and each final generation. Top-level code runs first, followed by named callbacks.
Callbacks are global functions with exact, case-sensitive names, such as OnProgramStart(data). Use normal JavaScript function declarations. Browser APIs, Node.js modules, and direct access to the application's Java objects are not part of the post processor API.
The script receives plain data objects and should treat them as read-only. Keep any modal state, such as the last tool or feed rate, in script variables initialized for the current execution. State does not survive between discovery and generation or between exports.
NC output is collected through WriteLine(...). Returning a string from a callback does not add it to the NC program.
The Callback Sequence
The final generation follows this sequence:
OnProgramStart(program)
OnOrigin(origin)
OnPlane(plane)
For each selected operation:
OnOperationStart(operation)
Command callbacks in toolpath order
OnOperationEnd(operation)
OnProgramEnd(program)
The six lifecycle callbacks shown above must exist. Command callbacks must also exist when their commands occur; a missing callback stops generation.
| Callbacks | Purpose |
|---|---|
OnRapidMove, OnLinearMove, OnArcMove | Translate movement data into controller motion blocks. |
OnToolChange, OnSpindleStart, OnSpindleStop | Handle explicit tool and spindle commands. |
OnCoolantChange, OnCutterCompensation | Apply coolant and cutter-compensation changes. |
OnComment, OnManualNC, OnProgramStop, OnDwell | Handle comments, manual NC text, stops, and timed waits. |
Operation initialization matters: for normal machining operations with tool metadata, RabbitCAM X supplies the initial tool and spindle state through OnOperationStart. The script must establish the required state there. Do not assume that a separate initial OnToolChange or OnSpindleStart callback will always follow.
OnInputDiscovery is optional and is used before final generation to declare input fields. OnCannedCycle is reserved in the callback interface; the current drilling strategies supply explicit motion commands.
The Data Passed to Callbacks
- Program data includes the name, units, operation count, application version, tools, and ordered operation summaries.
- Operation data includes the operation name and type,
hasMachiningMoves,tool,spindle, coolant settings, levels, and feeds. Use these values to prepare the controller for that operation. - Rapid moves provide
startandendpoints, each containingx,y, andz. - Linear moves also provide
feedRate. Use the move's feed value when writing its block. - Arc moves also provide
center,clockwise,plane,feedRate,radius, andsweepAngleDegrees.
Motion points arrive as absolute work coordinates in millimeters, and feeds are in mm/min. The origin callback's workZero describes the origin in model coordinates. Motion points already include the work-coordinate conversion, so do not subtract workZero again.
The current arc data uses the XY plane. Arc centers are absolute. For a controller that expects incremental I/J offsets, calculate I = center.x - start.x and J = center.y - start.y. The script is responsible for the controller's arc syntax, limits, splitting, and any required linearization.
The Four Host API Functions
| Function | What it does |
|---|---|
WriteLine(text) | Appends NC text using the configured line ending. Normally call it once for each output line. |
GetProperty(name) | Reads a manifest property or runtime override. Returns null when the property is absent. |
RequestInput(definitionJSON) | Declares a typed input and returns its current, default, or temporary discovery value. Pass a JSON string, usually made with JSON.stringify(...). |
SetOutputFileName(baseName, policy) | Sets a filename without the extension or directory. The policy is SUGGESTED or REQUIRED. |
SUGGESTED lets the user edit the filename. REQUIRED keeps the post's filename and lets the user choose the destination folder. RabbitCAM X adds the manifest extension automatically. If no filename is specified, it suggests one derived from the program name.
Functions such as FormatNumber or GetBooleanProperty found in existing posts are helpers defined by those scripts. They are not additional built-in Host API functions.
Properties and Runtime Inputs
Manifest properties provide defaults. Values entered for the current export override properties with the same ID. Validate property types and ranges in the script before using them in controller output.
A post can request STRING, INTEGER, NUMBER, BOOLEAN, or ENUM inputs. Each definition needs an id, label, and type. Optional fields include description, defaultValue, required, and numeric limits. ENUM inputs require options.
This helper declares a program-number input:
/**
* Declares and reads the program number for the current export.
*
* @return {number} The validated program number.
*/
function RequestProgramNumber()
{
return RequestInput(JSON.stringify({
id: "programNumber",
label: "Program number",
type: "INTEGER",
defaultValue: 1001,
required: true,
minimum: 1,
maximum: 99999
}));
}
Call this helper from OnInputDiscovery(data) to expose the field, and call it again during final generation when the value is needed. Use identical definitions for the same ID.
Discovery and generation run in separate sessions. The application can repeat discovery for conditional fields, so keep definitions stable and avoid depending on state from a previous pass. A dedicated OnInputDiscovery callback prevents the application from having to run the full generation sequence just to find input requests.
Example: Writing a Linear Move
This fragment illustrates how callback data becomes an NC line. It assumes the surrounding post has established absolute coordinates, millimeter units, and feed per minute, for example the appropriate G90, G21, and G94 modes on a compatible controller.
/**
* Formats a finite NC value with a decimal point and no negative zero.
*
* @param {number} value The value to format.
* @param {number} decimals The number of decimal places.
* @return {string} The formatted value.
* @throws {Error} If the value is not finite.
*/
function FormatNumber(value, decimals)
{
if (!Number.isFinite(value))
{
throw new Error("NC values must be finite numbers.");
}
const text = value.toFixed(decimals);
return Number(text) === 0 ? (0).toFixed(decimals) : text;
}
/**
* Writes one linear move using absolute metric coordinates.
*
* @param {Object} data The motion data supplied by RabbitCAM X.
* @throws {Error} If a coordinate or feed rate is invalid.
*/
function OnLinearMove(data)
{
if (!Number.isFinite(data.feedRate) || data.feedRate <= 0)
{
throw new Error("Feed rate must be greater than zero.");
}
const end = data.end;
WriteLine("G1 X" + FormatNumber(end.x, 3)
+ " Y" + FormatNumber(end.y, 3)
+ " Z" + FormatNumber(end.z, 3)
+ " F" + FormatNumber(data.feedRate, 1));
}
For an endpoint of X10, Y20, Z-2 and a feed of 300 mm/min, it writes:
G1 X10.000 Y20.000 Z-2.000 F300.0
This is a callback example, not a complete machine post. A complete implementation also handles initialization, tool changes, spindle, coolant, rapid and arc moves, compensation, and program completion. Decimal precision and output conventions must match the intended controller.
Customizing and Checking a Post
- Copy a suitable existing package to a new folder and give the copy a unique manifest ID and a clear name.
- Identify the required change: a manifest property, runtime input, output format, controller command, or callback behavior.
- Keep the exact callback names and data-field names. Preserve operation and motion order, and manage modal state explicitly.
- Restart RabbitCAM X after manifest changes, select the custom package, and generate a small representative program.
- Inspect units, work offset, tool and length offsets, spindle direction, coolant, feeds, rapid moves, arcs, and the ending sequence in the NC preview.
- Generate again after every revision and validate the resulting NC with the target controller's verification or dry-run procedure before cutting.
RabbitCAM X Simulation checks the CAM toolpaths. Changes made by the post to controller commands and modal state also need review in the generated NC output. Renaming an extension alone does not make a post compatible with another controller.
Common Problems
- The package does not appear: check its folder location, valid JSON, required manifest fields, and icon file, then restart RabbitCAM X.
- The script cannot load: check the script filename, package path, and JavaScript syntax.
- A callback is missing: define the exact global callback named in the error. Reject unsupported commands explicitly instead of silently dropping a required motion or machine action.
- Input discovery fails: check field types, defaults, ranges, ENUM options, and repeated definitions. The same ID must keep the same definition.
- The program contains unexpected coordinates: check output units, absolute/incremental modes, work-offset handling, and arc-center conversion.
- The controller rejects the file: inspect its extension, encoding, line endings, number formatting, supported commands, and controller-specific limits.
A failed callback stops generation; RabbitCAM X does not replace it with generic G-code. Use the error message to correct the package and generate a fresh NC program.
