fullcontrol-js
Version:
FullControl TypeScript rewrite - API parity mirror of Python library (G-code generation & geometry)
1,298 lines (1,263 loc) • 87.6 kB
JavaScript
var __defProp = Object.defineProperty;
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
}) : x)(function(x) {
if (typeof require !== "undefined") return require.apply(this, arguments);
throw Error('Dynamic require of "' + x + '" is not supported');
});
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
// src/core/base-model.ts
var BaseModelPlus = class {
// Accept partial init object; assign only known keys if enforceKeys provided
constructor(init, enforceKeys) {
if (init) {
for (const k of Object.keys(init)) {
if (!enforceKeys || enforceKeys.includes(k)) {
this[k] = init[k];
} else {
throw new Error(`attribute "${k}" not allowed for class ${this.constructor.name}`);
}
}
}
}
updateFrom(source) {
if (!source) return;
for (const [k, v] of Object.entries(source)) {
if (v === void 0) continue;
this[k] = v;
}
}
// Python parity alias
update_from(source) {
this.updateFrom(source);
}
copy() {
const clone = Object.create(this.constructor.prototype);
for (const [k, v] of Object.entries(this)) clone[k] = structuredClone(v);
return clone;
}
};
// src/util/format.ts
function formatPrecision6(val) {
return val.toPrecision(6).replace(/\.?0+$/, "");
}
function formatCoordinate(val) {
return val.toFixed(6).replace(/0+$/, "").replace(/\.$/, "");
}
function formatExtrusion(val) {
return val.toFixed(6).replace(/0+$/, "").replace(/\.$/, "");
}
function formatFeedrate(val) {
return val.toFixed(1).replace(/\.0+$/, "").replace(/\.$/, "");
}
// src/models/point.ts
var _Point = class _Point extends BaseModelPlus {
constructor(init) {
super(init);
}
toJSON() {
return { x: this.x, y: this.y, z: this.z, color: this.color, extrude: this.extrude, speed: this.speed };
}
static fromJSON(data) {
return new _Point(data);
}
XYZ_gcode(prev) {
let s = "";
if (this.x != null && this.x !== prev.x) s += `X${formatCoordinate(this.x)} `;
if (this.y != null && this.y !== prev.y) s += `Y${formatCoordinate(this.y)} `;
if (this.z != null && this.z !== prev.z) s += `Z${formatCoordinate(this.z)} `;
return s === "" ? void 0 : s;
}
gcode(state) {
const XYZ = this.XYZ_gcode(state.point);
if (XYZ == null) return void 0;
const isFirst = state._first_movement_done !== true;
const extruding = !!state.extruder?.on && !isFirst;
const G = isFirst ? "G0 " : extruding || state.extruder?.travel_format === "G1_E0" ? "G1 " : "G0 ";
const F = state.printer?.f_gcode(state) || "";
let E = "";
if (!isFirst && state.extruder) {
if (extruding) E = state.extruder.e_gcode(this, state);
else if (state.extruder?.travel_format === "G1_E0") E = state.extruder.e_gcode(this, state);
}
const line = `${G}${F}${XYZ}${E}`.trim();
if (state.printer) state.printer.speed_changed = false;
state.point.updateFrom(this);
if (isFirst) state._first_movement_done = true;
return line;
}
};
// optional per-move speed override
_Point.typeName = "Point";
var Point = _Point;
// src/models/vector.ts
var _Vector = class _Vector {
constructor(init) {
Object.assign(this, init);
}
toJSON() {
return { x: this.x, y: this.y, z: this.z };
}
static fromJSON(data) {
return new _Vector(data);
}
};
_Vector.typeName = "Vector";
var Vector = _Vector;
// src/models/extrusion.ts
var _ExtrusionGeometry = class _ExtrusionGeometry extends BaseModelPlus {
constructor(init) {
super(init);
}
update_area() {
if (this.area_model === "rectangle" && this.width != null && this.height != null) this.area = this.width * this.height;
else if (this.area_model === "stadium" && this.width != null && this.height != null)
this.area = (this.width - this.height) * this.height + Math.PI * (this.height / 2) ** 2;
else if (this.area_model === "circle" && this.diameter != null)
this.area = Math.PI * (this.diameter / 2) ** 2;
}
toJSON() {
return { area_model: this.area_model, width: this.width, height: this.height, diameter: this.diameter, area: this.area };
}
static fromJSON(d) {
return new _ExtrusionGeometry(d);
}
gcode(state) {
state.extrusion_geometry.updateFrom(this);
if (this.width != null || this.height != null || this.diameter != null || this.area_model != null) {
try {
state.extrusion_geometry.update_area();
} catch {
}
}
return void 0;
}
};
_ExtrusionGeometry.typeName = "ExtrusionGeometry";
var ExtrusionGeometry = _ExtrusionGeometry;
var _StationaryExtrusion = class _StationaryExtrusion extends BaseModelPlus {
constructor(init) {
super(init);
}
toJSON() {
return { volume: this.volume, speed: this.speed };
}
static fromJSON(d) {
return new _StationaryExtrusion(d);
}
gcode(state) {
if (state.printer) state.printer.speed_changed = true;
const eVal = state.extruder.get_and_update_volume(this.volume) * state.extruder.volume_to_e;
if (state.extruder && state.extruder.on !== true) state.extruder.on = true;
return `G1 F${this.speed} E${formatPrecision6(eVal)}`;
}
};
_StationaryExtrusion.typeName = "StationaryExtrusion";
var StationaryExtrusion = _StationaryExtrusion;
var _Extruder = class _Extruder extends BaseModelPlus {
constructor(init) {
super(init);
}
update_e_ratio() {
if (this.units === "mm3") this.volume_to_e = 1;
else if (this.units === "mm" && this.dia_feed != null) this.volume_to_e = 1 / (Math.PI * (this.dia_feed / 2) ** 2);
}
get_and_update_volume(volume) {
if (this.total_volume == null) this.total_volume = 0;
if (this.total_volume_ref == null) this.total_volume_ref = 0;
this.total_volume += volume;
this.total_volume = Math.round(this.total_volume * 1e12) / 1e12;
const ret = this.total_volume - this.total_volume_ref;
if (this.relative_gcode) this.total_volume_ref = this.total_volume;
return ret;
}
toJSON() {
return { on: this.on, units: this.units, dia_feed: this.dia_feed, relative_gcode: this.relative_gcode };
}
static fromJSON(d) {
return new _Extruder(d);
}
e_gcode(point1, state) {
const distance_forgiving = (p1, p2) => {
const dx = p1.x == null || p2.x == null ? 0 : p1.x - p2.x;
const dy = p1.y == null || p2.y == null ? 0 : p1.y - p2.y;
const dz = p1.z == null || p2.z == null ? 0 : p1.z - p2.z;
return Math.sqrt(dx * dx + dy * dy + dz * dz);
};
if (this.on) {
const length = distance_forgiving(point1, state.point);
if (length === 0) return "";
const area = state.extrusion_geometry?.area || 0;
const ratio = this.volume_to_e || 1;
const val = this.get_and_update_volume(length * area) * ratio;
return `E${formatExtrusion(val)}`;
} else {
if (this.travel_format === "G1_E0") {
const ratio = this.volume_to_e || 1;
const val = this.get_and_update_volume(0) * ratio;
return `E${formatExtrusion(val)}`;
}
return "";
}
}
gcode(state) {
state.extruder.updateFrom(this);
if (this.on != null && state.printer) state.printer.speed_changed = true;
if (this.units != null || this.dia_feed != null) state.extruder.update_e_ratio();
if (this.relative_gcode != null) {
state.extruder.total_volume_ref = state.extruder.total_volume;
return state.extruder.relative_gcode ? "M83 ; relative extrusion" : "M82 ; absolute extrusion\nG92 E0 ; reset extrusion position to zero";
}
return void 0;
}
};
_Extruder.typeName = "Extruder";
var Extruder = _Extruder;
var _Retraction = class _Retraction extends BaseModelPlus {
constructor(init) {
super(init);
}
toJSON() {
return { length: this.length, speed: this.speed };
}
static fromJSON(d) {
return new _Retraction(d);
}
gcode(state) {
const cmdMap = state.printer?.command_list;
if (cmdMap && cmdMap.retract) return void 0;
const len = this.length ?? state.extruder.retraction_length;
if (len == null || len === 0) return void 0;
const speed = this.speed ?? state.extruder.retraction_speed ?? 1800;
if (state.printer) state.printer.speed_changed = true;
const ratio = state.extruder.volume_to_e || 1;
let eDelta;
if (state.extruder.units === "mm3") {
if (state.extruder.dia_feed) {
const area = Math.PI * (state.extruder.dia_feed / 2) ** 2;
eDelta = len * area * ratio;
} else {
return void 0;
}
} else {
eDelta = len * ratio;
}
state.extruder.get_and_update_volume(-(eDelta / ratio));
const eVal = state.extruder.total_volume - state.extruder.total_volume_ref;
if (state.extruder.relative_gcode) {
const rel = -eDelta;
return `G1 F${speed} E${formatExtrusion(rel)}`;
} else {
return `G1 F${speed} E${formatExtrusion(eVal * ratio)}`;
}
}
};
// mm/min feedrate for retraction move
_Retraction.typeName = "Retraction";
var Retraction = _Retraction;
var _Unretraction = class _Unretraction extends BaseModelPlus {
constructor(init) {
super(init);
}
toJSON() {
return { length: this.length, speed: this.speed };
}
static fromJSON(d) {
return new _Unretraction(d);
}
gcode(state) {
const cmdMap = state.printer?.command_list;
if (cmdMap && cmdMap.unretract) return void 0;
const len = this.length ?? state.extruder.retraction_length;
if (len == null || len === 0) return void 0;
const speed = this.speed ?? state.extruder.retraction_speed ?? 1800;
if (state.printer) state.printer.speed_changed = true;
const ratio = state.extruder.volume_to_e || 1;
let eDelta;
if (state.extruder.units === "mm3") {
if (state.extruder.dia_feed) {
const area = Math.PI * (state.extruder.dia_feed / 2) ** 2;
eDelta = len * area * ratio;
} else return void 0;
} else {
eDelta = len * ratio;
}
state.extruder.get_and_update_volume(eDelta / ratio);
const eVal = state.extruder.total_volume - state.extruder.total_volume_ref;
if (state.extruder.relative_gcode) {
return `G1 F${speed} E${formatExtrusion(eDelta)}`;
} else {
return `G1 F${speed} E${formatExtrusion(eVal * ratio)}`;
}
}
};
_Unretraction.typeName = "Unretraction";
var Unretraction = _Unretraction;
// src/models/printer.ts
var _Printer = class _Printer extends BaseModelPlus {
constructor(init) {
super(init);
}
f_gcode(state) {
if (this.speed_changed) {
const speed = state.extruder?.on ? this.print_speed : this.travel_speed;
if (speed != null) return `F${formatFeedrate(speed)} `;
}
return "";
}
gcode(state) {
state.printer.update_from(this);
if (this.print_speed != null || this.travel_speed != null) state.printer.speed_changed = true;
if (this.new_command) state.printer.command_list = { ...state.printer.command_list || {}, ...this.new_command };
return void 0;
}
toJSON() {
return { print_speed: this.print_speed, travel_speed: this.travel_speed };
}
static fromJSON(d) {
return new _Printer(d);
}
};
_Printer.typeName = "Printer";
var Printer = _Printer;
// src/models/auxiliary.ts
var Buildplate = class extends BaseModelPlus {
constructor(init) {
super(init);
}
gcode() {
if (this.temp == null) return "";
const code = this.wait ? "M190" : "M140";
return `${code} S${this.temp}`;
}
};
Buildplate.typeName = "Buildplate";
var Hotend = class extends BaseModelPlus {
constructor(init) {
super(init);
}
gcode() {
if (this.temp == null) return "";
const code = this.wait ? "M109" : "M104";
const tool = this.tool != null ? ` T${this.tool}` : "";
return `${code}${tool} S${this.temp}`;
}
};
Hotend.typeName = "Hotend";
var Fan = class extends BaseModelPlus {
// future multi-fan
constructor(init) {
super(init);
this.speed_percent = 0;
}
gcode() {
const s = Math.round(Math.max(0, Math.min(100, this.speed_percent)) * 255 / 100);
return this.speed_percent > 0 ? `M106 S${s}` : "M107";
}
};
Fan.typeName = "Fan";
// src/models/commands.ts
var PrinterCommand = class extends BaseModelPlus {
constructor(init) {
super(init);
}
gcode(state) {
if (this.id && state.printer.command_list) return state.printer.command_list[this.id];
}
};
PrinterCommand.typeName = "PrinterCommand";
var ManualGcode = class extends BaseModelPlus {
constructor(init) {
super(init);
}
gcode() {
return this.text;
}
};
ManualGcode.typeName = "ManualGcode";
var GcodeComment = class extends BaseModelPlus {
constructor(init) {
super(init);
}
gcode(state) {
if (this.end_of_previous_line_text && state.gcode.length > 0)
state.gcode[state.gcode.length - 1] += " ; " + this.end_of_previous_line_text;
if (this.text) return "; " + this.text;
}
};
GcodeComment.typeName = "GcodeComment";
// src/models/controls.ts
var GcodeControls = class extends BaseModelPlus {
constructor(init) {
super(init);
this.include_date = true;
this.show_banner = true;
this.show_tips = true;
this.silent = false;
}
initialize() {
if (!this.printer_name) {
this.printer_name = "generic";
console.warn("warning: printer is not set - defaulting to 'generic'");
}
}
};
GcodeControls.typeName = "GcodeControls";
var PlotControls = class extends BaseModelPlus {
constructor(init) {
super(init);
this.color_type = "z_gradient";
this.tube_type = "flow";
this.tube_sides = 4;
this.zoom = 1;
this.hide_annotations = false;
this.hide_travel = false;
this.hide_axes = false;
this.neat_for_publishing = false;
this.raw_data = false;
this.printer_name = "generic";
}
initialize() {
if (!this.raw_data) {
if (!this.style) {
this.style = "tube";
console.warn("warning: plot style is not set - defaulting to 'tube'");
}
if (this.style === "tube" && this.line_width != null) {
console.warn("warning: line_width set but style=tube; it is ignored for extruding lines");
}
if (this.line_width == null) this.line_width = 2;
}
}
};
PlotControls.typeName = "PlotControls";
// src/models/annotations.ts
var PlotAnnotation = class extends BaseModelPlus {
constructor(init) {
super(init);
}
visualize(state, plot_data, _plot_controls) {
if (!this.point) this.point = new Point({ x: state.point.x, y: state.point.y, z: state.point.z });
if (plot_data?.add_annotation) plot_data.add_annotation(this);
}
};
PlotAnnotation.typeName = "PlotAnnotation";
// src/util/extra.ts
function flatten(steps) {
return steps.flatMap((s) => Array.isArray(s) ? s : [s]);
}
function linspace(start, end, number_of_points) {
if (number_of_points < 2) return [start];
const out = [];
const step = (end - start) / (number_of_points - 1);
for (let i = 0; i < number_of_points; i++) out.push(start + step * i);
return out;
}
function points_only(steps, track_xyz = true) {
const pts = steps.filter((s) => s instanceof Point);
if (!track_xyz) return pts;
for (let i = 0; i < pts.length - 1; i++) {
const next = pts[i + 1].copy();
const cur = pts[i];
if (cur.x != null && next.x == null) next.x = cur.x;
if (cur.y != null && next.y == null) next.y = cur.y;
if (cur.z != null && next.z == null) next.z = cur.z;
pts[i + 1] = next;
}
while (pts.length && (pts[0].x == null || pts[0].y == null || pts[0].z == null)) pts.shift();
return pts;
}
function relative_point(reference, x_offset, y_offset, z_offset) {
let pt;
if (reference instanceof Point) pt = reference;
else if (Array.isArray(reference)) {
for (let i = reference.length - 1; i >= 0; i--) if (reference[i] instanceof Point) {
pt = reference[i];
break;
}
}
if (!pt) throw new Error("The reference object must be a Point or list containing at least one point");
if (pt.x == null || pt.y == null || pt.z == null) throw new Error(`The reference point must have all x,y,z defined (x=${pt.x}, y=${pt.y}, z=${pt.z})`);
return new Point({ x: pt.x + x_offset, y: pt.y + y_offset, z: pt.z + z_offset });
}
function first_point(steps, fully_defined = true) {
for (const s of steps) if (s instanceof Point) {
if (!fully_defined || s.x != null && s.y != null && s.z != null) return s;
}
throw new Error(fully_defined ? "No point found in steps with all of x y z defined" : "No point found in steps");
}
function last_point(steps, fully_defined = true) {
for (let i = steps.length - 1; i >= 0; i--) {
const s = steps[i];
if (s instanceof Point) {
if (!fully_defined || s.x != null && s.y != null && s.z != null) return s;
}
}
throw new Error(fully_defined ? "No point found in steps with all of x y z defined" : "No point found in steps");
}
function export_design(steps, filename) {
const serialized = steps.map((s) => ({ type: s.constructor.typeName || s.constructor.name, data: { ...s } }));
const json = JSON.stringify(serialized, null, 2);
if (filename) {
if (typeof window === "undefined") {
import("fs").then((fs2) => fs2.writeFileSync(filename + ".json", json));
}
}
return json;
}
function import_design(registry, jsonOrFilename) {
let jsonStr = jsonOrFilename;
if (jsonOrFilename.endsWith(".json")) {
if (typeof window !== "undefined") throw new Error("File system import not available in browser context");
const fs2 = __require("fs");
jsonStr = fs2.readFileSync(jsonOrFilename, "utf-8");
}
const arr = JSON.parse(jsonStr);
return arr.map((o) => {
const cls = registry[o.type];
if (!cls) throw new Error(`Unknown design type '${o.type}'`);
return cls.fromJSON ? cls.fromJSON(o.data) : new cls(o.data);
});
}
function build_default_registry() {
const reg = {};
const add = (cls) => {
if (cls && cls.typeName) reg[cls.typeName] = cls;
};
[
Point,
Vector,
Extruder,
ExtrusionGeometry,
StationaryExtrusion,
Retraction,
Unretraction,
Printer,
Fan,
Hotend,
Buildplate,
PrinterCommand,
ManualGcode,
GcodeComment,
GcodeControls,
PlotControls,
PlotAnnotation
].forEach(add);
return reg;
}
// src/util/check.ts
function check(steps) {
if (!Array.isArray(steps)) {
console.warn("design must be a 1D list of instances");
return;
}
const types = new Set(steps.map((s) => Array.isArray(s) ? "list" : s?.constructor?.name));
let results = "";
if (types.has("list")) {
results += "warning - list contains nested lists; use flatten() to convert to 1D\n";
}
results += "step types " + JSON.stringify([...types]);
console.log("check results:\n" + results);
}
function fix(steps, result_type, controls) {
const hasNested = steps.some((s) => Array.isArray(s));
if (hasNested) {
console.warn("warning - design includes nested lists; flattening automatically");
steps = flatten(steps);
}
const p0 = first_point(steps, false);
if (p0.x == null || p0.y == null || p0.z == null) {
console.warn(`warning - first point should define x,y,z; filling missing with 0`);
p0.x = p0.x ?? 0;
p0.y = p0.y ?? 0;
p0.z = p0.z ?? 0;
}
if (result_type === "plot" && controls?.color_type === "manual" && p0.color == null) {
throw new Error("for PlotControls(color_type='manual') first point must have a color");
}
return steps;
}
function check_points(geometry, checkType) {
if (checkType === "polar_xy") {
const checkPoint = (pt) => {
if (pt.x == null || pt.y == null) throw new Error("polar transformations require points with x and y defined");
};
if (geometry instanceof Point) checkPoint(geometry);
else for (const g of geometry) if (g instanceof Point) checkPoint(g);
}
}
// src/geometry/polar.ts
function polar_to_point(centre, radius, angle) {
return new Point({ x: (centre.x ?? 0) + radius * Math.cos(angle), y: (centre.y ?? 0) + radius * Math.sin(angle), z: centre.z });
}
function point_to_polar(target_point, origin_point) {
check_points([target_point, origin_point], "polar_xy");
const r = Math.hypot(target_point.x - origin_point.x, target_point.y - origin_point.y);
const angle = Math.atan2(target_point.y - origin_point.y, target_point.x - origin_point.x);
return { radius: r, angle: (angle % (2 * Math.PI) + 2 * Math.PI) % (2 * Math.PI) };
}
function polar_to_vector(length, angle) {
return new Vector({ x: length * Math.cos(angle), y: length * Math.sin(angle) });
}
// src/geometry/midpoint.ts
function midpoint(p1, p2) {
return new Point({ x: avg(p1.x, p2.x), y: avg(p1.y, p2.y), z: avg(p1.z, p2.z) });
}
function avg(a, b) {
return a != null && b != null ? (a + b) / 2 : void 0;
}
function interpolated_point(p1, p2, f) {
const interp = (a, b) => a != null || b != null ? (a ?? b) + f * ((b ?? a) - (a ?? b)) : void 0;
return new Point({ x: interp(p1.x, p2.x), y: interp(p1.y, p2.y), z: interp(p1.z, p2.z) });
}
function centreXY_3pt(p1, p2, p3) {
const D = 2 * (p1.x * (p2.y - p3.y) + p2.x * (p3.y - p1.y) + p3.x * (p1.y - p2.y));
if (D === 0) throw new Error("The points are collinear, no unique circle");
const x_centre = ((p1.x ** 2 + p1.y ** 2) * (p2.y - p3.y) + (p2.x ** 2 + p2.y ** 2) * (p3.y - p1.y) + (p3.x ** 2 + p3.y ** 2) * (p1.y - p2.y)) / D;
const y_centre = ((p1.x ** 2 + p1.y ** 2) * (p3.x - p2.x) + (p2.x ** 2 + p2.y ** 2) * (p1.x - p3.x) + (p3.x ** 2 + p3.y ** 2) * (p2.x - p1.x)) / D;
return new Point({ x: x_centre, y: y_centre, z: p1.z });
}
// src/geometry/measure.ts
function distance(p1, p2) {
return Math.sqrt(((p1.x ?? 0) - (p2.x ?? 0)) ** 2 + ((p1.y ?? 0) - (p2.y ?? 0)) ** 2 + ((p1.z ?? 0) - (p2.z ?? 0)) ** 2);
}
function angleXY_between_3_points(start, mid, end) {
return point_to_polar(end, mid).angle - point_to_polar(start, mid).angle;
}
function path_length(points) {
let len = 0;
for (let i = 0; i < points.length - 1; i++) len += distance(points[i], points[i + 1]);
return len;
}
// src/geometry/move.ts
function move(geometry, vector, copy = false, copy_quantity = 2) {
return copy ? copy_geometry(geometry, vector, copy_quantity) : move_geometry(geometry, vector);
}
function move_geometry(geometry, vector) {
const move_point = (p) => {
const n = p.copy();
if (n.x != null && vector.x != null) n.x += vector.x;
if (n.y != null && vector.y != null) n.y += vector.y;
if (n.z != null && vector.z != null) n.z += vector.z;
return n;
};
if (geometry instanceof Point) return move_point(geometry);
return geometry.map((e) => e instanceof Point ? move_point(e) : e);
}
function copy_geometry(geometry, vector, quantity) {
const out = [];
for (let i = 0; i < quantity; i++) {
const v = new Vector({ x: vector.x != null ? vector.x * i : void 0, y: vector.y != null ? vector.y * i : void 0, z: vector.z != null ? vector.z * i : void 0 });
const g = move_geometry(geometry, v);
if (g instanceof Point) out.push(g);
else out.push(...g);
}
return out;
}
// src/geometry/move_polar.ts
function move_polar(geometry, centre, radius, angle, copy = false, copy_quantity = 2) {
check_points(geometry, "polar_xy");
return copy ? copy_geometry_polar(geometry, centre, radius, angle, copy_quantity) : move_geometry_polar(geometry, centre, radius, angle);
}
function move_geometry_polar(geometry, centre, radius, angle) {
const move_point = (p) => {
const pol = point_to_polar(p, centre);
const np = polar_to_point(centre, pol.radius + radius, pol.angle + angle);
const clone = p.copy();
clone.x = np.x;
clone.y = np.y;
return clone;
};
if (geometry instanceof Point) return move_point(geometry);
return geometry.map((e) => e instanceof Point ? move_point(e) : e);
}
function copy_geometry_polar(geometry, centre, radius, angle, quantity) {
const out = [];
for (let i = 0; i < quantity; i++) {
const rnow = radius * i;
const anow = angle * i;
const g = move_geometry_polar(geometry, centre, rnow, anow);
if (g instanceof Point) out.push(g);
else out.push(...g);
}
return out;
}
// src/geometry/reflect.ts
function reflectXY_mc(p, m_reflect, c_reflect) {
const m_reflect_normal = -1 / m_reflect;
const c_reflect_normal = (p.y ?? 0) - m_reflect_normal * (p.x ?? 0);
const x = (c_reflect_normal - c_reflect) / (m_reflect - m_reflect_normal);
const y = (c_reflect_normal - m_reflect_normal / m_reflect * c_reflect) / (1 - m_reflect_normal / m_reflect);
return new Point({ x: (p.x ?? 0) + 2 * (x - (p.x ?? 0)), y: (p.y ?? 0) + 2 * (y - (p.y ?? 0)), z: p.z });
}
function reflectXY(p, p1, p2) {
if (p2.x === p1.x) return new Point({ x: (p.x ?? 0) + 2 * (p1.x - (p.x ?? 0)), y: p.y, z: p.z });
if (p2.y === p1.y) return new Point({ x: p.x, y: (p.y ?? 0) + 2 * (p1.y - (p.y ?? 0)), z: p.z });
const m = (p2.y - p1.y) / (p2.x - p1.x);
const c = p1.y - m * p1.x;
return reflectXY_mc(p, m, c);
}
// src/geometry/reflect_polar.ts
function reflectXYpolar(p, preflect, angle_reflect) {
return reflectXY(p, preflect, polar_to_point(preflect, 1, angle_reflect));
}
// src/geometry/segmentation.ts
function segmented_line(p1, p2, segments) {
const xs = linspace(p1.x, p2.x, segments + 1);
const ys = linspace(p1.y, p2.y, segments + 1);
const zs = linspace(p1.z, p2.z, segments + 1);
return xs.map((_, i) => new Point({ x: xs[i], y: ys[i], z: zs[i] }));
}
function segmented_path(points, segments) {
const lengths = points.slice(0, -1).map((_, i) => distance(points[i], points[i + 1]));
const cumulative = [0];
for (const l of lengths) cumulative.push(cumulative[cumulative.length - 1] + l);
const seg_length = cumulative[cumulative.length - 1] / segments;
const out = [points[0]];
let path_section_now = 1;
for (let s = 1; s < segments; s++) {
const target = seg_length * s;
while (target > cumulative[path_section_now]) path_section_now++;
const interpolation_length = target - cumulative[path_section_now - 1];
const fraction = interpolation_length / distance(points[path_section_now - 1], points[path_section_now]);
out.push(interpolated_point(points[path_section_now - 1], points[path_section_now], fraction));
}
out.push(points[points.length - 1]);
return out;
}
// src/geometry/ramping.ts
function ramp_xyz(list, x_change = 0, y_change = 0, z_change = 0) {
const xs = linspace(0, x_change, list.length);
const ys = linspace(0, y_change, list.length);
const zs = linspace(0, z_change, list.length);
for (let i = 0; i < list.length; i++) list[i] = move(list[i], new Vector({ x: xs[i], y: ys[i], z: zs[i] }));
return list;
}
function ramp_polar(list, centre, radius_change = 0, angle_change = 0) {
const rs = linspace(0, radius_change, list.length);
const as = linspace(0, angle_change, list.length);
for (let i = 0; i < list.length; i++) list[i] = move_polar(list[i], centre, rs[i], as[i]);
return list;
}
// src/geometry/arcs.ts
function arcXY(centre, radius, start_angle, arc_angle, segments = 100) {
return linspace(start_angle, start_angle + arc_angle, segments + 1).map((a) => polar_to_point(centre, radius, a));
}
function variable_arcXY(centre, start_radius, start_angle, arc_angle, segments = 100, radius_change = 0, z_change = 0) {
let arc = arcXY(centre, start_radius, start_angle, arc_angle, segments);
arc = ramp_xyz(arc, 0, 0, z_change);
return ramp_polar(arc, centre, radius_change, 0);
}
function elliptical_arcXY(centre, a, b, start_angle, arc_angle, segments = 100) {
const t = linspace(start_angle, start_angle + arc_angle, segments + 1);
return t.map((tt) => new Point({ x: a * Math.cos(tt) + centre.x, y: b * Math.sin(tt) + centre.y, z: centre.z }));
}
function arcXY_3pt(p1, p2, p3, segments = 100) {
const centre = centreXY_3pt(p1, p2, p3);
const radius = Math.hypot(p1.x - centre.x, p1.y - centre.y);
const start_angle = Math.atan2(p1.y - centre.y, p1.x - centre.x);
const mid_angle = Math.atan2(p2.y - centre.y, p2.x - centre.x);
const end_angle = Math.atan2(p3.y - centre.y, p3.x - centre.x);
const twoPi = Math.PI * 2;
const norm = (a) => {
while (a < 0) a += twoPi;
while (a >= twoPi) a -= twoPi;
return a;
};
const sa = norm(start_angle), ma = norm(mid_angle), ea = norm(end_angle);
const ccw = ma > sa && ma < ea || sa > ea && (ma > sa || ma < ea);
const arc_angle = ccw ? ea - sa : -(twoPi - (ea - sa));
return arcXY(centre, radius, sa, arc_angle, segments);
}
// src/geometry/shapes.ts
function rectangleXY(start, x_size, y_size, cw = false) {
const p1 = new Point({ x: start.x + x_size * (cw ? 0 : 1), y: start.y + y_size * (cw ? 1 : 0), z: start.z });
const p2 = new Point({ x: start.x + x_size, y: start.y + y_size, z: start.z });
const p3 = new Point({ x: start.x + x_size * (cw ? 1 : 0), y: start.y + y_size * (cw ? 0 : 1), z: start.z });
return [start.copy(), p1, p2, p3, start.copy()];
}
function circleXY(centre, radius, start_angle, segments = 100, cw = false) {
return arcXY(centre, radius, start_angle, Math.PI * 2 * (1 - 2 * Number(cw)), segments);
}
function circleXY_3pt(p1, p2, p3, start_angle, start_at_first_point, segments = 100, cw = false) {
const centre = centreXY_3pt(p1, p2, p3);
const radius = Math.hypot(p1.x - centre.x, p1.y - centre.y);
if (start_angle != null && start_at_first_point != null) throw new Error("start_angle and start_at_first_point cannot both be set");
if (start_angle == null) {
if (start_at_first_point == null) throw new Error("neither start_angle nor start_at_first_point set");
start_angle = Math.atan2(p1.y - centre.y, p1.x - centre.x);
}
return arcXY(centre, radius, start_angle, Math.PI * 2 * (1 - 2 * Number(cw)), segments);
}
function ellipseXY(centre, a, b, start_angle, segments = 100, cw = false) {
return elliptical_arcXY(centre, a, b, start_angle, Math.PI * 2 * (1 - 2 * Number(cw)), segments);
}
function polygonXY(centre, enclosing_radius, start_angle, sides, cw = false) {
return arcXY(centre, enclosing_radius, start_angle, Math.PI * 2 * (1 - 2 * Number(cw)), sides);
}
function spiralXY(centre, start_radius, end_radius, start_angle, n_turns, segments, cw = false) {
return variable_arcXY(centre, start_radius, start_angle, n_turns * Math.PI * 2 * (1 - 2 * Number(cw)), segments, end_radius - start_radius, 0);
}
function helixZ(centre, start_radius, end_radius, start_angle, n_turns, pitch_z, segments, cw = false) {
return variable_arcXY(centre, start_radius, start_angle, n_turns * Math.PI * 2 * (1 - 2 * Number(cw)), segments, end_radius - start_radius, pitch_z * n_turns);
}
// src/geometry/waves.ts
function squarewaveXYpolar(start, direction_polar, amplitude, line_spacing, periods, extra_half_period = false, extra_end_line = false) {
const steps = [start.copy()];
for (let i = 0; i < periods; i++) {
steps.push(polar_to_point(steps[steps.length - 1], amplitude, direction_polar + Math.PI / 2));
steps.push(polar_to_point(steps[steps.length - 1], line_spacing, direction_polar));
steps.push(polar_to_point(steps[steps.length - 1], amplitude, direction_polar - Math.PI / 2));
if (i !== periods - 1) steps.push(polar_to_point(steps[steps.length - 1], line_spacing, direction_polar));
}
if (extra_half_period) {
steps.push(polar_to_point(steps[steps.length - 1], line_spacing, direction_polar));
steps.push(polar_to_point(steps[steps.length - 1], amplitude, direction_polar + Math.PI / 2));
}
if (extra_end_line) steps.push(polar_to_point(steps[steps.length - 1], line_spacing, direction_polar));
return steps;
}
function squarewaveXY(start, direction_vector, amplitude, line_spacing, periods, extra_half_period = false, extra_end_line = false) {
const vx = direction_vector.x ?? 0, vy = direction_vector.y ?? 0;
const direction_polar = Math.atan2(vy, vx);
return squarewaveXYpolar(start, direction_polar, amplitude, line_spacing, periods, extra_half_period, extra_end_line);
}
function trianglewaveXYpolar(start, direction_polar, amplitude, tip_separation, periods, extra_half_period = false) {
const steps = [start.copy()];
for (let i = 0; i < periods; i++) {
let temp = polar_to_point(steps[steps.length - 1], amplitude, direction_polar + Math.PI / 2);
steps.push(polar_to_point(temp, tip_separation / 2, direction_polar));
temp = polar_to_point(steps[steps.length - 1], amplitude, direction_polar - Math.PI / 2);
steps.push(polar_to_point(temp, tip_separation / 2, direction_polar));
}
if (extra_half_period) {
const temp = polar_to_point(steps[steps.length - 1], amplitude, direction_polar + Math.PI / 2);
steps.push(polar_to_point(temp, tip_separation / 2, direction_polar));
}
return steps;
}
function sinewaveXYpolar(start, direction_polar, amplitude, period_length, periods, segments_per_period = 16, extra_half_period = false, phase_shift = 0) {
const steps = [];
const totalSegments = periods * segments_per_period + (extra_half_period ? Math.floor(0.5 * segments_per_period) : 0);
for (let i = 0; i <= totalSegments; i++) {
const axis_distance = i * period_length / segments_per_period;
const amp_now = amplitude * (0.5 - 0.5 * Math.cos(i / segments_per_period * Math.PI * 2 + phase_shift));
steps.push(move(start, new Vector({ x: axis_distance, y: amp_now, z: 0 })));
}
return move_polar(steps, start, 0, direction_polar);
}
// src/geometry/travel_to.ts
function travel_to(geometry) {
let point;
if (geometry instanceof Point) point = geometry;
else if (Array.isArray(geometry)) point = first_point(geometry);
else throw new Error("travel_to expects a Point or array of steps containing at least one Point");
return [new Extruder({ on: false }), point, new Extruder({ on: true })];
}
// src/gcode/primer/index.ts
function clonePoint(p) {
return new Point({ x: p.x, y: p.y, z: p.z, extrude: p.extrude });
}
function buildPrimer(name, endPoint, options) {
if (!options?.enablePrimer || name === "no_primer") return [];
switch (name) {
case "travel":
return [new Extruder({ on: false }), clonePoint(endPoint), new Extruder({ on: true })];
case "front_lines_then_y":
return frontLinesThen("y", endPoint);
case "front_lines_then_x":
return frontLinesThen("x", endPoint);
case "front_lines_then_xy":
return frontLinesThen("xy", endPoint);
case "x":
return axisPrime("x", endPoint);
case "y":
return axisPrime("y", endPoint);
default:
return [];
}
}
function addBoxSeq(endPoint) {
return [new Point({ x: 110 }), new Point({ y: 14 }), new Point({ x: 10 }), new Point({ y: 16 })];
}
function frontLinesThen(mode, endPoint) {
const seq = [];
seq.push(new ManualGcode({ text: ";-----\n; START OF PRIMER PROCEDURE\n;-----" }));
seq.push(new Extruder({ on: false }));
seq.push(new Point({ x: 10, y: 12, z: endPoint.z }));
seq.push(new Extruder({ on: true }));
seq.push(...addBoxSeq(endPoint));
if (mode === "y") {
seq.push(new Point({ x: endPoint.x }));
seq.push(new Point({ y: endPoint.y }));
} else if (mode === "x") {
seq.push(new Point({ y: endPoint.y }));
seq.push(new Point({ x: endPoint.x }));
} else {
seq.push(new Point({ x: endPoint.x, y: endPoint.y }));
}
seq.push(new ManualGcode({ text: ";-----\n; END OF PRIMER PROCEDURE\n;-----\n" }));
return seq;
}
function axisPrime(first, endPoint) {
const seq = [];
seq.push(new ManualGcode({ text: ";-----\n; START OF PRIMER PROCEDURE\n;-----" }));
seq.push(new Extruder({ on: false }));
seq.push(new Point({ x: 10, y: 12, z: endPoint.z }));
seq.push(new Extruder({ on: true }));
if (first === "x") {
seq.push(new Point({ x: endPoint.x }));
seq.push(new Point({ y: endPoint.y }));
} else {
seq.push(new Point({ y: endPoint.y }));
seq.push(new Point({ x: endPoint.x }));
}
seq.push(new ManualGcode({ text: ";-----\n; END OF PRIMER PROCEDURE\n;-----\n" }));
return seq;
}
// src/devices/community/singletool/generic.ts
var generic_exports = {};
__export(generic_exports, {
set_up: () => set_up
});
// src/devices/community/singletool/base_settings.ts
var default_initial_settings = {
print_speed: 1e3,
travel_speed: 8e3,
area_model: "rectangle",
extrusion_width: 0.4,
extrusion_height: 0.2,
nozzle_temp: 210,
bed_temp: 40,
enclosure_temp: 0,
tool_number: 0,
fan_percent: 100,
print_speed_percent: 100,
material_flow_percent: 100,
e_units: "mm",
// 'mm' | 'mm3'
relative_e: true,
manual_e_ratio: null,
dia_feed: 1.75,
travel_format: "G0",
primer: "front_lines_then_y",
printer_command_list: {
home: "G28 ; home axes",
retract: "G10 ; retract",
unretract: "G11 ; unretract",
absolute_coords: "G90 ; absolute coordinates",
relative_coords: "G91 ; relative coordinates",
units_mm: "G21 ; set units to millimeters"
}
};
// src/devices/community/singletool/generic.ts
function set_up(user_overrides) {
const printer_overrides = { primer: "travel" };
let initialization_data = { ...default_initial_settings, ...printer_overrides };
initialization_data = { ...initialization_data, ...user_overrides };
const starting_procedure_steps = [];
starting_procedure_steps.push(new ManualGcode({ text: "; Time to print!!!!!\n; GCode created with FullControl - tell us what you're printing!\n; info@fullcontrol.xyz or tag FullControlXYZ on Twitter/Instagram/LinkedIn/Reddit/TikTok" }));
starting_procedure_steps.push(new Extruder({ relative_gcode: initialization_data.relative_e }));
if ("bed_temp" in user_overrides) starting_procedure_steps.push(new Buildplate({ temp: initialization_data.bed_temp, wait: false }));
if ("nozzle_temp" in user_overrides) starting_procedure_steps.push(new Hotend({ temp: initialization_data.nozzle_temp, wait: false }));
if ("bed_temp" in user_overrides) starting_procedure_steps.push(new Buildplate({ temp: initialization_data.bed_temp, wait: true }));
if ("nozzle_temp" in user_overrides) starting_procedure_steps.push(new Hotend({ temp: initialization_data.nozzle_temp, wait: true }));
if ("fan_percent" in user_overrides) starting_procedure_steps.push(new Fan({ speed_percent: initialization_data.fan_percent }));
if ("print_speed_percent" in user_overrides) starting_procedure_steps.push(new ManualGcode({ text: "M220 S" + initialization_data.print_speed_percent + " ; set speed factor override percentage" }));
if ("material_flow_percent" in user_overrides) starting_procedure_steps.push(new ManualGcode({ text: "M221 S" + initialization_data.material_flow_percent + " ; set extrude factor override percentage" }));
const ending_procedure_steps = [];
initialization_data.starting_procedure_steps = starting_procedure_steps;
initialization_data.ending_procedure_steps = ending_procedure_steps;
return initialization_data;
}
// src/pipeline/state.ts
var State = class {
constructor(steps = [], options) {
this.gcodeLines = [];
this.points = [];
this.extruders = [];
this.annotations = [];
// Python-style single tracking instances
this.point = new Point();
const flat = flatten(steps);
const printerName = options?.printer_name || "generic";
let initData;
initData = set_up(options?.initialization_data || {});
const starting = initData.starting_procedure_steps || [];
const ending = initData.ending_procedure_steps || [];
const primerName = initData.primer || "no_primer";
let firstPoint = void 0;
for (const s of flat) {
if (s instanceof Point) {
firstPoint = s;
break;
}
if (Array.isArray(s)) {
const p = s.find((x) => x instanceof Point);
if (p) {
firstPoint = p;
break;
}
}
}
let primerSteps = [];
if (firstPoint && primerName && primerName !== "no_primer") {
primerSteps = buildPrimer(primerName, firstPoint, { enablePrimer: true });
}
this.steps = [...starting, ...primerSteps, ...flat, ...ending];
if (!this.printer) {
this.printer = new Printer({
print_speed: initData.print_speed,
travel_speed: initData.travel_speed,
speed_changed: true,
command_list: initData.printer_command_list
});
}
if (!this.extruders.length) {
this.extruder = new Extruder({
units: initData.e_units,
dia_feed: initData.dia_feed,
total_volume: 0,
total_volume_ref: 0,
relative_gcode: initData.relative_e,
travel_format: initData.travel_format === "G1_E0" ? "G1_E0" : "none",
on: false
});
this.extruder.update_e_ratio();
if (initData.manual_e_ratio != null) this.extruder.volume_to_e = initData.manual_e_ratio;
this.extruders.push(this.extruder);
} else {
this.extruder = this.extruders[0];
}
const hasGeom = this.steps.some((s) => s instanceof ExtrusionGeometry);
if (!hasGeom) {
const g = new ExtrusionGeometry({
area_model: initData.area_model,
width: initData.extrusion_width,
height: initData.extrusion_height
});
this.steps.unshift(g);
this.extrusion_geometry = g;
try {
g.update_area();
} catch {
}
} else {
const gstep = this.steps.find((s) => s instanceof ExtrusionGeometry);
if (gstep) {
this.extrusion_geometry = gstep;
try {
gstep.update_area();
} catch {
}
}
}
}
addPoint(p) {
this.points.push(p);
}
addGcode(line) {
if (line.includes("\n")) {
for (const l of line.split(/\r?\n/)) if (l.trim().length) this.gcodeLines.push(l);
} else {
this.gcodeLines.push(line);
}
}
register(step) {
if (step && typeof step === "object") {
if (step.type === "Extruder" || step.constructor?.name === "Extruder") this.extruders.push(step);
if (step.type === "Printer" || step.constructor?.name === "Printer") this.printer = step;
if (step.constructor?.name === "PlotAnnotation") this.annotations.push(step);
}
}
};
// src/pipeline/gcode.ts
function generate_gcode(state, controls) {
const gstate = { printer: state.printer || new Printer(), gcode: state.gcodeLines };
if (state.extrusion_geometry && state.extrusion_geometry.area == null) {
try {
state.extrusion_geometry.update_area();
} catch {
}
}
let firstMovementEmitted = false;
const pendingModeAfterFirstMove = [];
let seenFirstMode = false;
let queuedPrinterUpdate = null;
for (const step of state.steps) {
if (Array.isArray(step) && step.length && step[0] instanceof Point) {
for (const pt of step) {
state.addPoint(pt);
const line = pt.gcode(state);
if (line) {
state.addGcode(line);
if (!firstMovementEmitted) {
firstMovementEmitted = true;
if (pendingModeAfterFirstMove.length) {
for (const m of pendingModeAfterFirstMove) state.addGcode(m);
pendingModeAfterFirstMove.length = 0;
}
}
}
}
continue;
}
if (step instanceof Point) {
state.addPoint(step);
const line = step.gcode(state);
if (line) {
state.addGcode(line);
if (!firstMovementEmitted) {
firstMovementEmitted = true;
if (pendingModeAfterFirstMove.length) {
for (const m of pendingModeAfterFirstMove) state.addGcode(m);
pendingModeAfterFirstMove.length = 0;
}
if (queuedPrinterUpdate) {
queuedPrinterUpdate.gcode(state);
queuedPrinterUpdate = null;
}
}
}
continue;
}
if (step instanceof ExtrusionGeometry) {
step.gcode(state);
continue;
}
if (step instanceof StationaryExtrusion) {
const line = step.gcode(state);
if (line) state.addGcode(line);
continue;
}
if (step instanceof Retraction) {
const line = step.gcode(state);
if (line) state.addGcode(line);
continue;
}
if (step instanceof Unretraction) {
const line = step.gcode(state);
if (line) state.addGcode(line);
continue;
}
if (step instanceof Extruder) {
const prevOn = state.extruder.on;
const line = step.gcode(state);
const becameOn = step.on === true && prevOn !== true;
if (line) {
const lines = line.split("\n");
if (!firstMovementEmitted) {
if (!seenFirstMode) {
for (const l of lines) state.addGcode(l);
seenFirstMode = true;
} else {
pendingModeAfterFirstMove.push(...lines);
}
} else {
for (const l of lines) state.addGcode(l);
}
}
if (becameOn && !firstMovementEmitted) {
state.extruder.on = true;
if (state.printer) state.printer.speed_changed = true;
} else if (becameOn) {
if (state.printer) state.printer.speed_changed = true;
}
if (step.on === false && prevOn === true) {
if (state.printer) state.printer.speed_changed = true;
}
continue;
}
if (step instanceof Printer) {
if (!firstMovementEmitted) queuedPrinterUpdate = step;
else step.gcode(state);
continue;
}
if (step instanceof ManualGcode) {
const out = step.gcode();
if (out) state.addGcode(out);
continue;
}
if (step instanceof GcodeComment) {
const out = step.gcode(gstate);
if (out) state.addGcode(out);
continue;
}
if (step instanceof PrinterCommand) {
let out = step.gcode(gstate);
if (state.printer?.command_list && step.id) {
const cmd = state.printer.command_list[step.id];
if (cmd) out = cmd;
}
if (out) state.addGcode(out);
continue;
}
}
if (!firstMovementEmitted && pendingModeAfterFirstMove.length) {
for (const m of pendingModeAfterFirstMove) state.addGcode(m);
}
return state.gcodeLines.join("\n");
}
// src/pipeline/visualize.ts
function build_plot_data(state) {
const points = state.points.map((p) => ({ x: p.x, y: p.y, z: p.z, color: p.color }));
return { points, annotations: state.annotations.slice() };
}
// src/pipeline/transform.ts
function transform(steps, result_type = "gcode", controls = {}) {
const gcodeControls = new GcodeControls(controls);
gcodeControls.initialize();
const fixed = fix(steps, result_type, gcodeControls);
const state = new State(fixed, {
initialization_data: gcodeControls.initialization_data,
printer_name: gcodeControls.printer_name
});
state.controls = gcodeControls;
for (const s of state.steps) state.register(s);
const gcode = generate_gcode(state, gcodeControls);
const plot = build_plot_data(state);
return { gcode, plot, state };
}
// src/devices/community/singletool/custom.ts
var custom_exports = {};
__export(custom_exports, {
set_up: () => set_up2
});
function set_up2(user_overrides) {
const printer_overrides = { primer: "no_primer", relative_e: false };
let initialization_data = { ...default_initial_settings, ...printer_overrides };
initialization_data = { ...initialization_data, ...user_overrides };
const starting_procedure_steps = [];
starting_procedure_steps.push(new ManualGcode({ text: "; Time to print!!!!!\n; GCode created with FullControl - tell us what you're printing!\n; info@fullcontrol.xyz or tag FullControlXYZ on Twitter/Instagram/LinkedIn/Reddit/TikTok" }));
if ("relative_e" in user_overrides) starting_procedure_steps.push(new Extruder({ relative_gcode: initialization_data.relative_e }));
if ("bed_temp" in user_overrides) starting_procedure_steps.push(new Buildplate({ temp: initialization_data.bed_temp, wait: false }));
if ("nozzle_temp" in user_overrides) starting_procedure_steps.push(new Hotend({ temp: initialization_data.nozzle_temp, wait: false }));
if ("bed_temp" in user_overrides) starting_procedure_steps.push(new Buildplate({ temp: initialization_data.bed_temp, wait: true }));
if ("nozzle_temp" in user_overrides) starting_procedure_steps.push(new Hotend({ temp: initialization_data.nozzle_temp, wait: true }));
if ("fan_percent" in user_overrides) starting_procedure_steps.push(new Fan({ speed_percent: initialization_data.fan_percent }));
if ("print_speed_percent" in user_overrides) starting_procedure_steps.push(new ManualGcode({ text: "M220 S" + initialization_data.print_speed_percent + " ; set speed factor override percentage" }));
if ("material_flow_percent" in user_overrides) starting_procedure_steps.push(new ManualGcode({ text: "M221 S" + initialization_data.material_flow_percent + " ; set extrude factor override percentage" }));
const ending_procedure_steps = [];
initialization_data.starting_procedure_steps = starting_procedure_steps;
initialization_data.ending_procedure_steps = ending_procedure_steps;
return initialization_data;
}
// src/devices/community/singletool/prusa_mk4.ts
var prusa_mk4_exports = {};
__export(prusa_mk4_exports, {
set_up: () => set_up3
});
function set_up3(user_overrides) {
const printer_overrides = { nozzle_probe_temp: 170 };
let initialization_data = { ...default_initial_settings, ...printer_overrides };
initialization_data = { ...initialization_data, ...user_overrides };
const s = [];
s.push(new ManualGcode({ text: "; Time to print!!!!!\n; GCode created with FullControl - tell us what you're printing!\n; info@fullcontrol.xyz or tag FullControlXYZ on Twitter/Instagram/LinkedIn/Reddit/TikTok " }));
s.push(new Buildplate({ temp: initialization_data.bed_temp, wait: false }));
s.push(new Hotend({ temp: initialization_data.nozzle_probe_temp, wait: false }));
s.push(new Buildplate({ temp: initialization_data.bed_temp, wait: true }));
s.push(new Hotend({ temp: initialization_data.nozzle_probe_temp, wait: true }));
s.push(new PrinterCommand({ id: "