Scripting API
Runtime-Scripting fuer Tabellen, Scenegraph-Motion, Roboter und UI-Overlays
Uebersicht
confBuild-Skripte laufen direkt im aktiven Editor. Sie koennen Tabellendaten lesen und schreiben, THREE.js-Objekte direkt manipulieren, wiederverwendbare Szenenanimationen anlegen, URDF-Roboter steuern und eigene Oberflaechen ueber dem Editor einblenden.
Tabellenlogik
Verwenden Sie ActiveWorkbook, um Parameter zu lesen, Formeln zu schreiben, ueber Tabellen zu iterieren und gezielte Modell-Rebuilds auszulösen.
Direkte Scenegraph-Steuerung
Mit API.getSceneObject(), API.updateSceneObject() und API.renderScene() aendern Sie die Szene live, ohne das Spreadsheet-Modell neu zu berechnen.
Animationen und Motion
Erstellen Sie benannte Animationen, scrubben Sie deren Fortschritt oder treiben Sie Maschinen und URDF-Roboter direkt aus JavaScript an.
Eigene UI und Debugging
Mounten Sie HTML-, jQuery-UI- oder React-Panels im Editor und lesen Sie Logs sowie Laufzeitfehler direkt aus der Script-API aus.
Schnellstart
Die Runtime ist um drei zentrale Einstiegspunkte organisiert.
ActiveWorkbook
Tabellen lesen, schreiben, Bereiche abfragen und Hilfsfunktionen fuer Sheets
API
UI-Updates, Scenegraph-Helfer, Animationen, Roboter, Script-UI und Debugging
scene
Szenenbezogene Helfer wie das Erstellen und Aktualisieren von Connectors
Refresh-Regeln
- Rufen Sie
await API.updateUI()auf, nachdem Sie Tabellenzellen mitActiveWorkbookgeaendert haben. - Rufen Sie
API.renderScene()auf, wenn Sie nur den Live-Scenegraph angepasst haben und keinen Spreadsheet-Rebuild ausloesen. - Zelladressen sind 0-basiert:
{ sheet: 0, row: 0, col: 0 }ist die erste Zelle. - Verwenden Sie fuer Strings am besten doppelte Anfuehrungszeichen.
Minimales Beispiel
async function projectLoaded(project) {
const width = await ActiveWorkbook.getCellSerialized({ sheet: 0, row: 0, col: 1 });
console.log("Projekt geladen:", project?.name, "aktuelle Breite:", width);
await ActiveWorkbook.setCellContents({ sheet: 0, row: 4, col: 1 }, "Bereit");
await API.updateUI();
}
Spreadsheet-Operationen
Verwenden Sie ActiveWorkbook fuer jede zellbasierte Projektlogik.
ActiveWorkbook.getCellSerialized(address)
Aktuellen serialisierten Zellwert lesen
ActiveWorkbook.getCellFormula(address)
Zellenformel lesen
ActiveWorkbook.setCellContents(address, value)
Wert oder Formel in eine Zelle schreiben
ActiveWorkbook.getRangeValues(range)
Einen Zellbereich auslesen
ActiveWorkbook.getRangeFormulas(range)
Formeln eines Bereichs auslesen
ActiveWorkbook.getSheetDimensions(sheetId)
Zeilen- und Spaltenanzahl eines Sheets zurueckgeben
ActiveWorkbook.simpleCellAddressFromString("B5", 0)
Eine Tabellenadresse in ein 0-basiertes Adressobjekt umwandeln
ActiveWorkbook.simpleCellAddressToString(address, 0)
Ein Adressobjekt wieder in Tabellen-Notation umwandeln
Beispiel: Lesen, verarbeiten, schreiben
async function processRows() {
const dims = await ActiveWorkbook.getSheetDimensions(0);
for (let row = 1; row < dims.rows; row++) {
const input = await ActiveWorkbook.getCellSerialized({ sheet: 0, row, col: 0 });
if (!input) {
continue;
}
const result = Number(input) * 2;
await ActiveWorkbook.setCellContents({ sheet: 0, row, col: 1 }, result);
}
await API.updateUI();
}
Live-Scenegraph-Helfer
Verwenden Sie die Runtime-API, wenn Sie sofortige Transform-, Sichtbarkeits- oder Metadaten-Aenderungen benoetigen, ohne Geometrie aus dem Spreadsheet neu zu erzeugen.
API.getSelectedSceneObject()
Das aktuell selektierte THREE.js-Objekt zurueckgeben
API.getSceneObject(target)
Ein Objekt ueber outputid, Szenenpfad, Namen oder Objektreferenz aufloesen
API.getSceneObjectState(target)
Einen einfachen Snapshot von Position, Rotation, Scale, Sichtbarkeit und Parent-Info lesen
API.updateSceneObject(target, updates)
Absolute oder relative Position, Rotation, Scale, Sichtbarkeit, Name oder userData aendern
API.renderScene(force?)
Den Viewport nach direkten Scenegraph-Aenderungen neu rendern
Unterstuetzte Felder fuer updateSceneObject()
Sie koennen position, translate, rotation, rotate, scale, scaleBy, visible, name, userData, angleUnit und render uebergeben.
Beispiel: Selektiertes Teil verschieben
async function nudgeSelection() {
const selected = API.getSelectedSceneObject();
const target =
selected?.userData?.outputid ||
selected?.userData?.path ||
selected?.name;
if (!target) {
console.warn("Kein stabiler Szenen-Target gefunden");
return;
}
await API.updateSceneObject(target, {
translate: { x: 25, z: 10 },
rotate: { z: 15 },
angleUnit: "degrees",
userData: { lastAction: "nudgeSelection" }
});
API.renderScene();
}
Szenenanimationen
Szenenanimationen laufen direkt auf dem Live-THREE.js-Scenegraph. Sie eignen sich fuer Maschinenbewegungen, Oeffnen-Schliessen-Verhalten, Verfahrwege und wiederkehrende visuelle Zustände.
API.animate(target, config)
Eine Animation direkt aus Target und Konfiguration erzeugen
API.setAnimation(id, config)
Eine benannte Animation erstellen oder ersetzen
API.playAnimation(id?, restart?)
Eine Animation oder alle Animationen abspielen
API.pauseAnimation(id?)
Eine Animation oder alle Animationen pausieren
API.stopAnimation(id?, restore?)
Die Bewegung stoppen und optional die urspruengliche Transform-Basis wiederherstellen
API.setAnimationProgress(id, progress)
Den Fortschritt zwischen 0 und 1 setzen
API.setAnimationValue(id, value)
Direkt zu einem konkreten Wert zwischen from und to springen
API.getAnimation(id)
Status, Richtung, Dauer und Fortschritt einer Animation lesen
API.listAnimations(id?)
Alle Animationen oder eine passende Gruppe auflisten
Referenz fuer die Animations-Konfiguration
Verwenden Sie property als "position", "rotation" oder "scale". Die Bewegungsachse definieren Sie mit axis. Dazu kommen from, to, durationMs, optional delayMs, der Loop-Modus "once", "repeat" oder "pingpong" und Easing wie "linear", "easeOutQuad" oder "easeInOutCubic".
Tipp: Verwenden Sie einen stabilen Target-Identifier. Bevorzugen Sie outputid, dann Szenenpfad, dann Objektnamen.
Beispiel: Hub eines Pneumatikzylinders
async function ONLOADED() {
const selected = API.getSelectedSceneObject();
const target =
selected?.userData?.outputid ||
selected?.userData?.path ||
selected?.name;
if (!target) {
console.warn("Kein Target fuer die Zylinder-Animation");
return;
}
await API.setAnimation("pistonRod", {
target,
property: "position",
axis: [0, 0, 1],
from: 0,
to: 120,
durationMs: 900,
loop: "pingpong",
easing: "easeInOutCubic",
autoplay: false,
restoreOnStop: true
});
await API.setAnimationProgress("pistonRod", 0);
}
async function playCylinder() {
await API.playAnimation("pistonRod", true);
}
async function setCylinderStroke(strokeMm) {
await API.setAnimationValue("pistonRod", strokeMm);
}
URDF-Roboter
Die Scripting-API kann URDF-Roboter laden, deren Joints auslesen, sie ueber Jointwerte bewegen, Inverse Kinematik berechnen und Toolpaths direkt aus Projektskripten abfahren.
API.addRobot(urdfUrl, name, options)
Einen URDF-Roboter in die aktuelle Szene laden
API.listRobots()
Manager-geladene und Sheet-erzeugte Roboter als Snapshots zurueckgeben
API.getRobot(target)
Roboterstatus ueber ID oder Namen lesen
API.setActiveRobot(target)
Einen Roboter als aktiven Roboter fuer Folgeaktionen markieren
API.getRobotJoints(target)
Joints mit Limits, Achse und aktuellem Wert auflisten
API.setRobotJointValue(target, jointName, value, angleUnit)
Einen Joint sofort setzen
API.setRobotJointValues(target, values, angleUnit)
Mehrere Joints gleichzeitig setzen
API.animateRobotJointValues(target, values, durationMs, angleUnit, steps)
Joints ueber die Zeit weich animieren
API.updateRobot(target, updates)
Basisposition, Rotation, Scale oder Sichtbarkeit des Roboters aendern
API.getRobotEndEffectorPosition(target)
Die aktuelle Endeffektor-Position lesen
API.solveRobotIK(target, position)
Inverse Kinematik fuer eine Ziel-TCP-Position loesen
API.followRobotPath(target, path)
Ein Array von TCP-Wegpunkten mit optionaler Zeit pro Punkt abfahren
API.homeRobot(target)
Die Robot-Joints in die Home-Pose zuruecksetzen
API.stopRobotMotion()
Den aktuellen Roboter-Motion-Run stoppen
API.removeRobot(target)
Einen einzelnen Roboter aus der Szene entfernen
API.clearRobots()
Alle verwalteten Roboter entfernen
Toolhead- und TCP-Positionierung
API.solveRobotIK() loest aktuell nur auf die Endeffektor-Position, nicht auf ein vollstaendiges Orientierungsziel. Wenn die Werkzeugausrichtung wichtig ist, kombinieren Sie TCP-Zielpunkte mit expliziten Wrist-Joint-Werten oder einer anschliessenden Joint-Korrektur.
Fuer Prozessbewegungen sollten Sie immer approach, work und retract definieren, statt direkt auf den Arbeitspunkt zu springen.
Beispiel: Einen TCP-Pfad abfahren
async function runRobotPath() {
const robots = API.listRobots();
const robot = robots[0];
if (!robot) {
console.warn("Kein URDF-Roboter im Projekt geladen");
return;
}
const joints = API.getRobotJoints(robot.id);
console.log("Verfuegbare Joints:", joints.map((joint) => joint.name));
if (joints.length > 0) {
await API.animateRobotJointValues(robot.id, {
[joints[0].name]: 20
}, 500, "degrees", 24);
}
const tcpApproach = { x: 650, y: 0, z: 980, time: 300 };
const tcpWork = { x: 650, y: 0, z: 900, time: 400 };
const tcpRetract = { x: 650, y: 0, z: 1020, time: 300 };
await API.followRobotPath(robot.id, [tcpApproach, tcpWork, tcpRetract]);
const ee = API.getRobotEndEffectorPosition(robot.id);
console.log("Finale TCP-Position:", ee);
}
Eigene Script-UI
Skripte koennen leichte Interface-Layer direkt ueber dem Editor einblenden. Das eignet sich fuer Status-Panels, eigene Tools, Dialoge und Debug-Helfer.
API.requireLibrary(name)
Unterstuetzte Runtime-Bibliotheken wie "jquery", "jquery-ui", "react" oder "babel" laden
API.loadExternalScript(url, globalName?)
Ein externes Script laden und optional auf einen globalen Export warten
API.loadExternalStyle(url, id?)
Ein externes Stylesheet einbinden
API.createScriptMountPoint(mountId, options)
Ein absolutes oder fix positioniertes Mount-Element erzeugen
API.removeScriptMountPoint(mountId)
Einen bestimmten Script-UI-Mount entfernen
API.clearScriptUi()
Alle vom aktuellen Skript erzeugten Mount-Points entfernen
API.createReactRoot(mountId, options)
Nach automatischem Laden von React einen React-Root erzeugen
API.renderReactComponent(mountId, elementFactory, options)
Ein React-Element oder eine Component-Factory in ein Mount rendern
API.renderReactComponentFromSource(mountId, source, options, componentName)
React-Quellcode mit Babel kompilieren und rendern
API.openJQueryDialog(mountId, html, dialogOptions, mountOptions)
Einen jQuery-UI-Dialog aus Script-Code erzeugen
Beispiel: jQuery-UI-Statusdialog oeffnen
async function showScriptStatus() {
await API.openJQueryDialog(
"script-status",
"<p>Robot setup complete.</p><p>Ready for path execution.</p>",
{ title: "Script Status", width: 360 },
{ target: "body", top: 24, right: 24 }
);
}
Beispiel: Kleines React-Panel rendern
async function showReactPanel() {
await API.renderReactComponent(
"react-status",
(React) => React.createElement(
"div",
{
style: {
padding: "14px",
borderRadius: "12px",
background: "#111827",
color: "#ffffff",
boxShadow: "0 10px 30px rgba(0,0,0,0.25)"
}
},
"Scene animation bereit"
),
{ target: "body", right: 24, bottom: 24, width: 260 }
);
}
Events und Lifecycle-Hooks
Skripte koennen auf Editorzustand, Auswahlwechsel und direkte Objektinteraktionen reagieren.
Projekt- und Auswahl-Events
projectLoaded(project)
Wird aufgerufen, wenn ein Projekt fertig geladen ist
projectActivated(project)
Wird aufgerufen, wenn ein Projekt aktiv wird
ONLOADED()
Wird aufgerufen, wenn DOM und Script-Umgebung bereit sind
projectSelected(project)
Wird aufgerufen, wenn ein Projekt oder Subprojekt selektiert wird
projectDeselected(project)
Wird aufgerufen, wenn ein Projekt oder Subprojekt deselektiert wird
sheetSelected(sheet)
Wird aufgerufen, wenn ein Sheet selektiert wird
sheetDeselected(sheet)
Wird aufgerufen, wenn ein Sheet deselektiert wird
connectorSelected(connectorData)
Wird aufgerufen, wenn ein Connector in der Szene selektiert wird
Maus-Events auf 3D-Objekten
ONENTER(object)
Hover-Enter-Helfer, der in vielen Projektskripten genutzt wird
ONLEAVE(object)
Hover-Leave-Helfer, der in vielen Projektskripten genutzt wird
MouseClick(object)
Wird beim Klick auf ein Objekt aufgerufen
MouseEnter(object)
Wird beim Eintritt des Cursors in ein Objekt aufgerufen
MouseLeave(object)
Wird beim Verlassen des Objekts durch den Cursor aufgerufen
MouseMove(object)
Wird waehrend der Bewegung ueber einem Objekt aufgerufen
MouseDown(object)
Wird beim Druecken der Maustaste auf einem Objekt aufgerufen
MouseUp(object)
Wird beim Loslassen der Maustaste auf einem Objekt aufgerufen
Beispiel: Hervorheben bei Hover
const originalColors = new Map();
function MouseEnter(object) {
if (!originalColors.has(object.uuid) && object.material?.color) {
originalColors.set(object.uuid, object.material.color.getHex());
}
object.material?.color?.set?.("#ff6600");
object.material?.emissive?.set?.("#221100");
API.renderScene();
}
function MouseLeave(object) {
const originalColor = originalColors.get(object.uuid);
if (originalColor && object.material?.color) {
object.material.color.setHex(originalColor);
}
object.material?.emissive?.set?.("#000000");
API.renderScene();
}
Debugging
Die Runtime fuehrt eine Script-spezifische Debug-Historie und speichert den letzten Laufzeitfehler, damit Sie Fehler nicht im Blindflug suchen muessen.
console.log(), console.warn(), console.error()
Beschriftete Meldungen in die Script-Konsole schreiben
API.getScriptDebugHistory()
Aktuelle strukturierte Debug-Eintraege zurueckgeben
API.getLastScriptError()
Den letzten Laufzeitfehler mit Position und Codeausschnitt zurueckgeben
API.clearScriptDebugHistory()
Debug-Historie und Error-State zuruecksetzen
Beispiel: Den letzten Fehler pruefen
function inspectScriptState() {
console.log("Debug history:", API.getScriptDebugHistory());
console.log("Last script error:", API.getLastScriptError());
}
Best Practices
Diese Muster helfen dabei, Skripte vorhersehbar, schnell und gut debugbar zu halten.
- Verwenden Sie
ActiveWorkbooknur fuer Daten- und Geometrieaenderungen, die wirklich einen Modell-Rebuild benoetigen. - Nutzen Sie
API.updateSceneObject()undAPI.setAnimation()fuer fluessige Runtime-Motion, statt pro Frame Tabellenzellen zu schreiben. - Bevorzugen Sie stabile Szenen-Targets: zuerst
outputid, dann Szenenpfad, dann Objektname. - Ermitteln Sie echte Roboternamen und Joint-Namen mit
API.listRobots()undAPI.getRobotJoints(), bevor Sie Roboterbefehle ausgeben. - Planen Sie fuer Roboter-Prozessbewegungen immer Toolhead-Punkte als approach, work und retract.
- Lassen Sie in fruehen Script-Versionen bewusst
console.log()-Ausgaben stehen. Das spart spaeter viel Debug-Zeit. - Wenn Sie eine screenshot-basierte Einfuehrung in den Editor wollen, lesen Sie das Scripts Editor Workflow-Tutorial.