Automation scripts
An automation script is JavaScript that opens, changes and saves drawings without the app's window: for an order or database system that makes a drawing for each order, a batch job that turns a folder of drawings into DXF files, or a nightly export to the cutting tables. It uses the same drawing API as extensions, and adds functions to open and save drawings, run the library's parametric designs, export them, and read and write files.
// orders.js: a box for each order, as a PDF for the customer and a DXF for the sample table
const box = runDesign("Packaging › FEFCO 0201 Regular slotted container", { L: 400, W: 300, D: 250 });
box.setNote("order", args[0]);
box.export("pdf", "out/" + args[0] + ".pdf");
box.export("dxf", "out/" + args[0] + ".dxf");
box.save("out/" + args[0] + ".piq");
log(args[0], "blank", box.info().totals.width, "×", box.info().totals.height);
Running a script
From the command line, with the app's program and the word run:
PiQ run orders.js A-1017
PiQ run --folder D:\Orders --timeout 120 orders.js A-1017
The options come before the script; every word after it is given to the script as args
(args[0] is "A-1017"). What the script logs is written to the output, and why it failed to the error output. The
exit code is 0 when it ran to the end, 1 when it failed, 2 when the command line is wrong - so the system that runs it
can tell. No window opens.
| Option | Meaning |
|---|---|
--folder DIR |
A folder the script may read and write, and those in it; give it more than once for several. The first is its working folder: paths that aren't whole are read from there. Without one, the current folder and the script's own. |
--extensions DIR |
An Extensions folder whose library designs (Parametric), post-processors, reports, save extensions and machine profiles (Profiles) the script uses; without one, yours and the app's. |
--allow-host HOST |
A web host drawings may be opened from (example.com, or *.example.com for those below it). None unless given. |
--timeout SECONDS |
The longest it may run: 600 seconds unless given. |
--no-save-extensions |
Saves drawings without running the save extensions. |
--help |
Says all this. |
From the app: File › Extensions › Run Script… asks for the script and its arguments (separated by spaces, in
double quotes if one has a space), and runs it in the background. It may use the files in its own folder and those
in it. What it logs goes to the Interactive window of the drawing open, and how it went is said when it finishes.
show(drawing) opens a drawing it made in the app, to look at or go on with. Put your scripts where you keep the
files they work on; the app comes with an example in its Extensions\Automation folder.
Saving and exporting need a licence that can be used, as they do in the app: without one, the script can open and read
drawings, and save and export fail saying why.
Drawings
| Function | Meaning |
|---|---|
openDrawing(path, values) |
A drawing file opened. values (if given) take the place of the file's own values of its variables as it is read, as Run Parametric does: openDrawing("tray.piq", { L: 300, BOARD: "B flute" }). |
openDrawing(url, values) |
A drawing opened from the web, from a host allowed (--allow-host). |
openDrawing(text, values) |
Drawing text (the drawing language, with a line break in it): a drawing made from it. |
openDrawing({path, url, text, values, units, name}) |
The same, said in full: units "mm" or "in" (else as the file says), name its name. |
newDrawing({units, industry, name}) |
A new, empty drawing: in "mm" (unless said), for an industry ("Packaging", "SheetMetal" …) if said. |
runDesign(name, values) |
A library design run with values, as File › Run Parametric runs it, for the industry of its folder: runDesign("Packaging › Sleeve", { L: 200 }), or just runDesign("Sleeve") if no other design has that name. |
designs() |
The library's designs: each {name, industry, description}. |
designInputs(name) |
What a design asks for: each {name, label, kind, value, choices}; kind is "number", "text", "toggle" or "choice". |
use(drawing) |
Makes a drawing the current one (below). |
currentDrawing() |
The current drawing, or null. |
show(drawing) |
In the app, the drawing opened in a window of its own (not saved); from the command line, nothing. |
batch(items, fn) |
fn(item, index) for each item (a file's path, a CSV row …). One that throws is said in the log and the rest go on; drawings opened in a call are closed after it. Gives back a list of {item, ok, result, error}. |
The value of a choice is the item's name ("B flute") or its place in the list, from 0. A variable the file doesn't
have is refused.
The current drawing
The drawing API - vars.L, newPoint, line, circle, command("…"), drawingInfo(),
setNote, classify … - works on the current drawing: the one opened or made last, or the one use(drawing)
chose. Changes are made as the Interactive window makes them, so what is drawn is parametric.
const panel = newDrawing({ units: "in", industry: "SignMaking", name: "Panel" });
setVariable("W", 48);
setVariable("H", 24);
const a = newPoint("[0,0]");
const b = newPoint("[W,0]");
const c = newPoint("[W,H]");
const d = newPoint("[0,H]");
polyline([a, b, c, d], true);
panel.save("panel.piq");
A drawing's functions
openDrawing, newDrawing and runDesign give back a drawing, with these:
| Function | Meaning |
|---|---|
name, path |
Its name, and its file (null until it has one). |
variable("L") |
A variable's value. |
variables() |
Its variables (not the hidden ones), by name, worked out. |
inputs() |
Its labelled variables, as designInputs gives them. |
setVariable("L", value), setVariables({ L: 300, W: "L/2" }) |
Sets variables, and works the drawing out again. A number, true or false; text for a text variable; a choice's item; else an expression ("L/2"). Its label is kept. |
evaluate("…") |
An expression worked out in it: evaluate("DISTANCE(P0,P2)"). |
run("…") |
Statements of the drawing language carried out in it, a line each: run("FILLET(@1,@2,5)"). |
info() |
Everything known about it, as drawingInfo() gives it: sizes, totals, layers, nests … |
notes(), setNote(name, value), classification(), classify(…) |
Its notes and what it is, as in the drawing API. |
regenerate() |
Worked out again (it is after each change): what went wrong in a block of it (IF, FOR …) throws. |
check() |
Every design rule's findings: each {rule, severity, message, elements, at}. |
report(name, options, path) |
A report: {title, summary, tables, notes, text, csv}, and written to path if given (.csv, .xlsx, .ods, .html, .pdf, .docx, .odt, .md, .json, else text). |
export(format, path, options) |
Exported (below): {path, format, extension, size, warnings}. |
export(path, options) |
Exported in the format the file's extension says. |
sendTo(profile, path) |
Exported with a machine profile (its id or name), as File › Send Using Machine Profile does: its format, its layers' names, colours and pens, its post-processor, its file name pattern; into path (a folder or a file), else its own folder. |
save(path) |
Saved as a drawing file (.piq if the name has no extension), to its own file if no path is given; then the save extensions run, as File › Save runs them. Gives back {path, records}: what each save extension returned, {extension, record, error}. |
text() |
The drawing as drawing text, as it would be saved. |
use(), with(fn) |
Makes it the current drawing; or calls fn(drawing) with it current, then the one before current again. |
close() |
Closes it: it can't be used after. |
Exporting
format is an export format's name, any case - pdf, svg, eps, ai, png, jpeg, webp, dxf, gcode,
hpgl, cf2, ddes, lightburn, laserSvg, aamaDxf, tiledPdf, projectorPdf, wrapTemplatePdf,
printCutPdf, printCutEps, gpgl, cuttingSvg, matCutterDxf, matCutterHpgl, dielinePdf, dstv, ifc,
bendDxf, step, piq (exportFormats() lists them) - or a file extension (jpg, plt, nc, dd3, lbrn2,
nc1, stp); null for the path's extension. See File formats. If path is a folder (it exists, or
ends with /), the file is the drawing's name in it. Each format is written with its usual settings; options can
give:
| Option | Meaning |
|---|---|
margin |
Space round the drawing, in points (PDF, SVG, EPS, AI, pictures). |
spotColours |
false: no spot colours for the dieline layers. |
textAsOutlines |
true: text as outlines. |
width, dpi, quality, transparent |
Pictures: pixels across (or dpi), JPEG/WebP quality, a transparent background. |
title |
The title written in the file. |
paper, overlap |
The tiled print's paper (A4, A3, Letter …) and overlap. |
postProcessor, settings |
Written by a post-processor instead (by its name), with its settings (the rest its own): export(null, "out/", { postProcessor: "Router 2", settings: { feed: 1200 } }). |
Files
A script reads and writes files only in its folders (--folder, or the script's in the app); a path that isn't whole
is read from the first. Anything else is refused.
| Function | Meaning |
|---|---|
args |
The words after the script's name: a list of text. |
readText(path), writeText(path, text), appendText(path, text) |
A text file (UTF-8). |
readJson(path), writeJson(path, value) |
A JSON file. |
readCsv(path, { separator }) |
A CSV file, a record for each row by the header row's names; numbers as numbers. The separator is a comma, semicolon or tab, whichever the header has most of, unless given. |
writeCsv(path, rows) |
Records (objects: the first one's names are the header) or lists as a CSV file. |
writeSpreadsheet(path, rows) |
Rows as writeCsv takes them, as an Excel workbook (.xlsx, which Numbers and Google Sheets open too), an OpenDocument spreadsheet (.ods, LibreOffice's) or CSV, by the path's extension: numbers stay numbers, the header bold. |
listFiles(folder, pattern, all) |
The files in a folder ("*.piq"; all: in the folders in it too), whole paths, in order. |
exists(path), makeFolder(path) |
Whether a file or folder is there; a folder made. |
joinPath(a, b, …), baseName(path) |
Paths joined; a file's name without its folder or extension. |
log(…), print(…), console.log(…) |
Says something: in the output, or the Interactive window. Values other than text are written as JSON. |
Folders are made as files are written in them. A file written again is replaced.
Errors
What goes wrong - a file not allowed or not there, a variable the drawing doesn't have, a statement it can't carry
out, a format it doesn't know - is a JavaScript error, with a message saying why. Catch it with try … catch to go
on, or let it stop the script: it is said with the script's name and line (orders.js, line 12: …), and the exit code
is 1. batch catches each item's.
for (const file of listFiles("in", "*.piq")) {
try {
const d = openDrawing(file);
d.export("dxf", "dxf/");
d.close();
} catch (e) {
log("Not exported:", file, e.message);
}
}
Example: a box for each row of a CSV file
box-sizes.js, in the app's Extensions\Automation folder with a box-sizes.csv to try it with, makes a regular
slotted container for each row of box sizes (name, L, W, D and board), writes it as a PDF and a DXF and saves it, and
writes made.csv with each blank's size and cut length for the order system to read back:
PiQ run box-sizes.js box-sizes.csv out
const made = batch(readCsv(args[0]), row => {
const values = { L: row.L, W: row.W, D: row.D };
if (row.board) values.T = row.board;
const box = runDesign("Packaging › FEFCO 0201 Regular slotted container", values);
box.export("pdf", joinPath(args[1], row.name + ".pdf"));
box.export("dxf", joinPath(args[1], row.name + ".dxf"));
box.save(joinPath(args[1], row.name + ".piq"));
return box.info().totals;
});
writeCsv(joinPath(args[1], "made.csv"),
made.map(m => ({ name: m.item.name, ok: m.ok, width: m.ok ? m.result.width : "", error: m.error ?? "" })));
Notes
- A script has no window and asks nothing: what a format would ask in the app takes its usual settings. Machine profiles give their format, layers, file names and post-processor; the format options a profile keeps (from the format's options page) aren't used yet: the format's usual settings are.
- The script runs for up to ten minutes (
--timeout), however many statements;DateandMath.random()work as usual. It can't reach other programs, files outside its folders, or the web (but for drawings opened from a host allowed). - The drawings a script saves say in their header that it made them, as the app's do.
- To record each drawing saved in a database, write a save extension: it runs for the
drawings a script saves too, and what it gives back is in
save'srecords.
See also: Extensions, Drawing API, Run Parametric, File formats, Machine profiles.