### Setup BaklavaJS Editor and Dependency Engine Source: https://github.com/newcat/baklavajs/blob/master/docs/execution/setup.md Initializes the BaklavaJS editor and sets up the DependencyEngine for graph execution. The engine must be started to begin processing. ```javascript import { Editor } from "@baklavajs/core"; import { DependencyEngine } from "@baklavajs/engine"; const editor = new Editor(); const engine = new DependencyEngine(editor); engine.start(); ``` -------------------------------- ### Importing Events Module Source: https://github.com/newcat/baklavajs/blob/master/packages/events/README.md Import the events module to start using its functionalities. This is a common setup step. ```javascript const events = require('@baklavajs/events'); ``` -------------------------------- ### Install BaklavaJS Packages Source: https://context7.com/newcat/baklavajs/llms.txt Install the combined package or individual scoped packages for BaklavaJS. ```bash # All-in-one npm install baklavajs # or individually npm install @baklavajs/core @baklavajs/engine @baklavajs/renderer-vue @baklavajs/interface-types @baklavajs/themes ``` -------------------------------- ### Install BaklavaJS Packages Source: https://github.com/newcat/baklavajs/blob/master/docs/getting-started.md Install the core BaklavaJS package or individual components using npm, yarn, or pnpm. ```bash # npm npm i baklavajs # yarn yarn add baklavajs # pnpm pnpm add baklavajs ``` -------------------------------- ### Browser Build with CDN Source: https://context7.com/newcat/baklavajs/llms.txt Use BaklavaJS directly from a CDN in plain HTML without any build tools. This setup includes the necessary CSS theme and the core JavaScript bundle. ```html
``` -------------------------------- ### Create MathNode using Class-based Approach (JavaScript) Source: https://github.com/newcat/baklavajs/blob/master/docs/nodes/nodes.md This JavaScript example shows a class-based implementation for a 'MathNode', similar to the TypeScript version. Remember to call `this.initializeIo()` within the constructor. ```javascript import { Node, NodeInterface, NumberInterface, SelectInterface } from "baklavajs"; export default class MathNode extends Node { constructor() { super(); this.type = "MathNode"; this.title = this.type; this.inputs = { number1: new NumberInterface("Number", 1), number2: new NumberInterface("Number", 2), operation: new SelectInterface("Operation", "Add", ["Add", "Subtract"]).setPort(false), }; this.outputs = { output: new NodeInterface("Output", 0), }; this.calculate = ({ number1, number2, operation }) => { let output; if (operation === "Add") { output = number1 + number2; } else if (operation === "Subtract") { output = number1 - number2; } else { throw new Error("Unknown operation: " + operation); } return { output }; }; this.initializeIo(); } } ``` -------------------------------- ### Create MathNode using Class-based Approach (TypeScript) Source: https://github.com/newcat/baklavajs/blob/master/docs/nodes/nodes.md This TypeScript example demonstrates a class-based approach for creating a 'MathNode' with dynamic inputs and outputs. It's crucial to call `this.initializeIo()` in the constructor for proper node functionality. ```typescript import { Node, NodeInterface, CalculateFunction, NumberInterface, SelectInterface } from "baklavajs"; interface Inputs { number1: number; number2: number; operation: string; } interface Outputs { output: number; } export default class MathNode extends Node { public type = "MathNode"; public title = this.type; public inputs = { number1: new NumberInterface("Number", 1), number2: new NumberInterface("Number", 2), operation: new SelectInterface("Operation", "Add", ["Add", "Subtract"]).setPort(false), }; public outputs = { output: new NodeInterface("Output", 0), }; public constructor() { super(); this.initializeIo(); } public calculate: CalculateFunction = ({ number1, number2, operation }) => { let output; if (operation === "Add") { output = number1 + number2; } else if (operation === "Subtract") { output = number1 - number2; } else { throw new Error("Unknown operation: " + operation); } return { output }; } } ``` -------------------------------- ### Customize Toolbar with Custom Commands Source: https://github.com/newcat/baklavajs/blob/master/docs/visual-editor/toolbar.md Register a custom command and add it to the toolbar alongside default commands. This example shows how to toggle the minimap. ```typescript import { useBaklava, TOOLBAR_COMMANDS, TOOLBAR_SUBGRAPH_COMMANDS } from "@baklavajs/renderer-vue"; import { defineComponent, h, markRaw } from "vue"; const baklavaView = useBaklava(); // Register a custom command const TOGGLE_MINIMAP_COMMAND = "TOGGLE_MINIMAP"; baklavaView.commandHandler.registerCommand(TOGGLE_MINIMAP_COMMAND, { execute: () => { baklavaView.settings.enableMinimap = !baklavaView.settings.enableMinimap; }, canExecute: () => true, }); // Customize the toolbar with a mix of default and custom commands baklavaView.settings.toolbar.commands = [ TOOLBAR_COMMANDS.COPY, TOOLBAR_COMMANDS.PASTE, TOOLBAR_COMMANDS.DELETE_NODES, TOOLBAR_COMMANDS.UNDO, TOOLBAR_COMMANDS.REDO, { command: TOGGLE_MINIMAP_COMMAND, title: "Toggle Minimap", icon: markRaw( defineComponent(() => { return () => h("div", "Map"); }), ), }, ]; // Customize subgraph commands baklavaView.settings.toolbar.subgraphCommands = [ TOOLBAR_SUBGRAPH_COMMANDS.SAVE_SUBGRAPH, TOOLBAR_SUBGRAPH_COMMANDS.SWITCH_TO_MAIN_GRAPH, ]; ``` -------------------------------- ### Importing a Dark Theme Source: https://github.com/newcat/baklavajs/blob/master/docs/visual-editor/customization.md Import a specific theme's CSS file to apply its styling to the Baklava editor. Ensure the theme package is installed. ```javascript import "@baklavajs/themes/syrup-dark.css"; ``` -------------------------------- ### Node Interface Middleware Example Source: https://github.com/newcat/baklavajs/blob/master/docs/nodes/interfaces.md Utilize middleware functions to add custom logic or meta-data to node interfaces in a type-safe manner. The middleware receives the interface instance as the first argument. ```javascript function setType(intf, type) { intf.type = type.name; } // usage - just an example, the interface types plugin works a bit different new NodeInterface("My Interface", 0).use(setType, "number"); ``` -------------------------------- ### Styling Nodes by Type with CSS Source: https://github.com/newcat/baklavajs/blob/master/docs/visual-editor/customization.md Use CSS selectors targeting data attributes to style specific node types. This example makes nodes of type 'MyNodeType' have a light blue background. ```css .baklava-node[data-node-type="MyNodeType"] { background-color: lightblue; } ``` -------------------------------- ### Define Node with Sidebar Interfaces Source: https://github.com/newcat/baklavajs/blob/master/docs/visual-editor/sidebar.md Use `displayInSidebar` to show node interfaces in the sidebar. This example defines a node with a dropdown and a hidden number input, both displayed in the sidebar. ```typescript import { defineNode, NodeInterface, NumberInterface, SelectInterface, displayInSidebar } from "baklavajs"; export default defineNode({ type: "SidebarNode", inputs: { sidebarOption1: () => new SelectInterface("Dropdown", "foo", ["foo", "bar", "blub"]).use(displayInSidebar, true).setPort(false), sidebarOption2: () => new NumberInterface("Test", 4).setHidden(true).use(displayInSidebar, true), }, }); ``` -------------------------------- ### Standalone BaklavaJS Integration Source: https://github.com/newcat/baklavajs/blob/master/docs/browser-build.md Include this HTML structure in your project to use BaklavaJS directly in the browser. It requires linking to the BaklavaJS bundle and theme CSS from a CDN. This setup allows for immediate use without any build process. ```html Document
``` -------------------------------- ### Define a Math Node with defineNode() Source: https://github.com/newcat/baklavajs/blob/master/docs/nodes/nodes.md Use `defineNode` to create a reusable node type. This example defines a 'MathNode' that accepts two numbers and an operation ('Add' or 'Subtract'), performing the calculation and returning the result. It utilizes `NumberInterface` for numeric inputs and `SelectInterface` for the operation choice. ```typescript import { defineNode, NodeInterface, NumberInterface, SelectInterface } from "baklavajs"; export default defineNode({ type: "MathNode", inputs: { number1: () => new NumberInterface("Number", 1), number2: () => new NumberInterface("Number", 10), operation: () => new SelectInterface("Operation", "Add", ["Add", "Subtract"]).setPort(false), }, outputs: { output: () => new NodeInterface("Output", 0), }, calculate({ number1, number2, operation }) { let output: number; if (operation === "Add") { output = number1 + number2; } else if (operation === "Subtract") { output = number1 - number2; } else { throw new Error("Unknown operation: " + operation); } return { output }; }, }); ``` -------------------------------- ### Manual Engine Execution Source: https://github.com/newcat/baklavajs/blob/master/docs/execution/forward.md Manually triggers a single run of the forward engine starting from a specified node. The first argument can be used for global calculation data, and the third for node update event data. ```javascript const triggerNode = editor.graph.nodes[0]; const result = await engine.runOnce(undefined, triggerNode, undefined); ``` -------------------------------- ### Prevent Adding a Connection Source: https://github.com/newcat/baklavajs/blob/master/docs/event-system.md Example of using a preventable event to stop a connection from being added based on custom logic. The `prevent` function must be called to block the action. ```typescript editor.graphEvents.beforeAddConnection.subscribe(token, (conn, prevent) => { // check, whether the user should be able to create this connection. if (/* user not allowed to create connection */) { prevent(); return; } }); ``` -------------------------------- ### Automatic Engine Execution Source: https://github.com/newcat/baklavajs/blob/master/docs/execution/forward.md Starts the forward engine to automatically re-run whenever a node's interface value changes. Execution will restart from the node whose value was modified. ```javascript engine.start(); // Now any value change will trigger forward execution from the affected node ``` -------------------------------- ### Define a Custom Node Type Source: https://github.com/newcat/baklavajs/blob/master/docs/getting-started.md Create a new node type using `defineNode`, specifying its inputs, outputs, and default values. This example defines a node with two number inputs, an operation selector, and a single output. ```typescript // file: MyNode.ts import { defineNode, NodeInterface, NumberInterface, SelectInterface } from "baklavajs"; export default defineNode({ type: "MyNode", inputs: { number1: () => new NumberInterface("Number", 1), number2: () => new NumberInterface("Number", 10), operation: () => new SelectInterface("Operation", "Add", ["Add", "Subtract"]).setPort(false), }, outputs: { output: () => new NodeInterface("Output", 0), }, }); ``` -------------------------------- ### Custom Node Renderer with Conditional Logic Source: https://github.com/newcat/baklavajs/blob/master/docs/visual-editor/customization.md Replace the default node renderer with a custom component for specific node types. This example uses 'MyNodeRenderer' for 'MyNodeType' and falls back to the default 'BaklavaNode' for others. ```vue ``` -------------------------------- ### Initialize Editor and Forward Engine Source: https://github.com/newcat/baklavajs/blob/master/docs/execution/forward.md Sets up the BaklavaJS editor and initializes the ForwardEngine. The engine requires an Editor instance to manage the graph. ```javascript import { Editor } from "@baklavajs/core"; import { ForwardEngine } from "@baklavajs/engine"; const editor = new Editor(); const engine = new ForwardEngine(editor); ``` -------------------------------- ### Initialize BaklavaJS Core Source: https://github.com/newcat/baklavajs/blob/master/packages/engine/README.md Import and initialize the baklavajs-core module. Further API demonstration is pending. ```javascript const baklavajsCore = require('baklavajs-core'); // TODO: DEMONSTRATE API ``` -------------------------------- ### Import baklavajs-full Source: https://github.com/newcat/baklavajs/blob/master/packages/full/README.md Import the full baklavajs package. Further API demonstration is pending. ```javascript const baklavajsFull = require('baklavajs-full'); // TODO: DEMONSTRATE API ``` -------------------------------- ### useBaklava() — Create the View Model Source: https://context7.com/newcat/baklavajs/llms.txt Returns a reactive view model that integrates the editor, renderer, command handler, history, clipboard, and settings. This view model should be passed to the `` component. ```APIDOC ## useBaklava() ### Description Returns a reactive view model (`IBaklavaViewModel`) that wires together the editor, renderer, command handler, history, clipboard, and settings. Pass it to the `` component. ### Usage ```vue ``` ``` -------------------------------- ### Import BaklavaJS Core Source: https://github.com/newcat/baklavajs/blob/master/packages/core/README.md Import the BaklavaJS core library for use in your project. This is the initial step for integrating BaklavaJS. ```javascript const baklavajsCore = require('baklavajs-core'); ``` -------------------------------- ### Create View Model with useBaklava() Source: https://context7.com/newcat/baklavajs/llms.txt Use the `useBaklava()` hook to create a reactive view model for the BaklavaJS editor. Pass this view model to the `` component. Ensure to import the necessary CSS for theming. ```vue ``` -------------------------------- ### Use Subset of Default Toolbar Commands Source: https://github.com/newcat/baklavajs/blob/master/docs/visual-editor/toolbar.md Customize the toolbar to display only specific default commands. Import `TOOLBAR_COMMANDS` and assign an array of desired commands to `baklavaView.settings.toolbar.commands`. ```typescript import { useBaklava, TOOLBAR_COMMANDS } from "@baklavajs/renderer-vue"; const baklavaView = useBaklava(); // Use only copy, paste, and undo commands baklavaView.settings.toolbar.commands = [TOOLBAR_COMMANDS.COPY, TOOLBAR_COMMANDS.PASTE, TOOLBAR_COMMANDS.UNDO]; ``` -------------------------------- ### Create a Button Interface Source: https://github.com/newcat/baklavajs/blob/master/docs/nodes/pre-defined-interfaces.md Use ButtonInterface to display a button that triggers a callback when clicked. ```javascript import { ButtonInterface } from "baklavajs"; new ButtonInterface("Name", () => console.log("Button clicked")); ``` -------------------------------- ### Subscribe to a Normal Event with Tokens Source: https://github.com/newcat/baklavajs/blob/master/docs/event-system.md Demonstrates subscribing to and emitting a normal event using a Symbol as a token for managing the listener. Ensure the token is kept to unsubscribe. ```typescript import { BaklavaEvent } from "@baklavajs/events"; const ev = new BaklavaEvent(null); const token = Symbol(); ev.subscribe(token, (data) => { console.log("Event triggered:", data); }); ev.emit("Hello World"); ev.unsubscribe(token); ev.emit("This won't be printed"); // Console output: // Event triggered: Hello World ``` -------------------------------- ### Create View Model with useBaklava Source: https://github.com/newcat/baklavajs/blob/master/docs/visual-editor/setup.md Use the `useBaklava` function to create a view model for the visual editor. This function accepts an existing editor instance if needed. Note that due to Vue's reactivity, you should use `viewModel.editor` afterwards. ```vue ``` -------------------------------- ### Initialize BaklavaJS Editor Source: https://github.com/newcat/baklavajs/blob/master/packages/full/test.html Initializes the BaklavaJS editor instance and attaches it to a specified DOM element. Ensure the target element exists in the HTML. ```javascript const vm = BaklavaJS.createBaklava(document.getElementById("editor")); console.log(vm); ``` -------------------------------- ### Create a TextInput Interface Source: https://github.com/newcat/baklavajs/blob/master/docs/nodes/pre-defined-interfaces.md Use TextInputInterface to display a text field for user input. ```javascript import { TextInputInterface } from "baklavajs"; new TextInputInterface("Name", "Edit me"); ``` -------------------------------- ### Force Update Dynamic Node Interfaces Source: https://github.com/newcat/baklavajs/blob/master/docs/nodes/dynamic-nodes.md Demonstrates how to use `forceUpdateInputs` to ensure an interface is always updated, even if its type changes, which can break existing connections. ```javascript onUpdate({ type }) { const inputs = type === "Number" ? { myInput: () => new NumberInterface("Input", 0) } : { myInput: () => new TextInputInterface("Input", "") }; return { input, forceUpdateInputs: ["myInput"] }; } ``` -------------------------------- ### Manually Set Execution Flow Source: https://github.com/newcat/baklavajs/blob/master/docs/execution/forward.md Demonstrates how to manually set the execution flow on a NodeInterface using setExecutionFlow. It's crucial to use NodeInterface for type safety. ```typescript import { setExecutionFlow } from "@baklavajs/engine"; const intf = new NodeInterface()("Exec", false); setExecutionFlow(intf); ``` -------------------------------- ### Class-Based Node Definition (`Node`) Source: https://context7.com/newcat/baklavajs/llms.txt An alternative approach for defining nodes that require more control, such as dynamically adding interfaces in the constructor. This method requires calling `this.initializeIo()`. ```APIDOC ## Class-Based Node Definition (`Node`) ### Description An alternative approach for nodes that need fine-grained control (e.g., dynamic interfaces added in the constructor). Requires calling `this.initializeIo()`. ### Usage ```ts import { Node, NodeInterface, NumberInterface, CalculateFunction } from "baklavajs"; interface Inputs { a: number; b: number; } interface Outputs { sum: number; } export default class AddNode extends Node { public type = "AddNode"; public title = "Add"; public inputs = { a: new NumberInterface("A", 0), b: new NumberInterface("B", 0), }; public outputs = { sum: new NodeInterface("Sum", 0), }; constructor() { super(); this.initializeIo(); // required } public calculate: CalculateFunction = ({ a, b }) => ({ sum: a + b }); } ``` ``` -------------------------------- ### Create a Number Interface Source: https://github.com/newcat/baklavajs/blob/master/docs/nodes/pre-defined-interfaces.md Use NumberInterface for numeric input that accepts decimal values. Optional minimum and maximum values can be provided. ```javascript import { NumberInterface } from "baklavajs"; // without min and max values new NumberInterface("Name", 0.5); // with min and max values new NumberInterface("Name", 0.5, 0, 1); ``` -------------------------------- ### Create a Slider Interface Source: https://github.com/newcat/baklavajs/blob/master/docs/nodes/pre-defined-interfaces.md Use SliderInterface to display a slider for numeric input. Minimum and maximum values are required. ```javascript import { SliderInterface } from "baklavajs"; new SliderInterface("Name", 0.5, 0, 1); ``` -------------------------------- ### Subgraph Toolbar Commands Source: https://github.com/newcat/baklavajs/blob/master/docs/visual-editor/toolbar.md Configure the commands available in the subgraph toolbar. You can include default commands like `SWITCH_TO_MAIN_GRAPH` or add your own custom subgraph-specific commands. ```typescript import { TOOLBAR_SUBGRAPH_COMMANDS } from "@baklavajs/renderer-vue"; // Default subgraph commands include: // - SAVE_SUBGRAPH: Save changes to the subgraph // - SWITCH_TO_MAIN_GRAPH: Return to the main graph // You can customize the subgraph toolbar: baklavaView.settings.toolbar.subgraphCommands = [ TOOLBAR_SUBGRAPH_COMMANDS.SWITCH_TO_MAIN_GRAPH, // Add your custom subgraph commands here ]; ``` -------------------------------- ### Create a Text Interface Source: https://github.com/newcat/baklavajs/blob/master/docs/nodes/pre-defined-interfaces.md Use TextInterface to display a value as read-only text. The name may change in future versions. ```javascript import { TextInterface } from "baklavajs"; new TextInterface("Name", "Hello World!"); ``` -------------------------------- ### Forward Engine Source: https://context7.com/newcat/baklavajs/llms.txt Executes the graph following explicit execution-flow connections, similar to Unreal Blueprints. It supports branching, loops, and event-driven execution. ```APIDOC ## Forward Engine — Execution-Flow Graph Executes the graph following explicit execution-flow connections (like Unreal Blueprints). Supports branching, loops, and event-driven execution. ```ts import { Editor } from "@baklavajs/core"; import { ForwardEngine, ExecutionFlowInterface, ForwardCalculationContext } from "@baklavajs/engine"; import { defineNode, NodeInterface } from "baklavajs"; // A branch node: routes execution based on a boolean condition const BranchNode = defineNode({ type: "BranchNode", inputs: { execIn: () => new ExecutionFlowInterface("Exec"), condition: () => new NodeInterface("Condition", false), }, outputs: { trueOut: () => new ExecutionFlowInterface("True"), falseOut: () => new ExecutionFlowInterface("False"), }, calculate({ condition }) { return { trueOut: !!condition, falseOut: !condition }; }, }); // A for-loop node using executeOutput const ForLoopNode = defineNode({ type: "ForLoopNode", inputs: { execIn: () => new ExecutionFlowInterface("Exec"), start: () => new NodeInterface("Start", 0), end: () => new NodeInterface("End", 5), }, outputs: { loopBody: () => new ExecutionFlowInterface("Loop Body"), completed: () => new ExecutionFlowInterface("Completed"), index: () => new NodeInterface("Index", 0), }, async calculate({ start, end }, context) { const { executeOutput } = context as ForwardCalculationContext; for (let i = start; i < end; i++) { await executeOutput("loopBody", { index: i }); } return { loopBody: false, completed: true, index: end }; }, }); // --- Setup --- const editor = new Editor(); editor.registerNodeType(BranchNode); editor.registerNodeType(ForLoopNode); const engine = new ForwardEngine(editor); // Manual execution starting from a specific node const triggerNode = editor.graph.nodes[0]; const result = await engine.runOnce(undefined, triggerNode, undefined); // Automatic: re-runs from the changed node on every value change engine.start(); ``` ``` -------------------------------- ### Create an Integer Interface Source: https://github.com/newcat/baklavajs/blob/master/docs/nodes/pre-defined-interfaces.md Use IntegerInterface for numeric input accepting only integers. Optional minimum and maximum values can be provided. ```javascript import { IntegerInterface } from "baklavajs"; // without min and max values new IntegerInterface("Name", 5); // with min and max values new IntegerInterface("Name", 5, 0, 10); ``` -------------------------------- ### Configure Visual Editor Settings Source: https://context7.com/newcat/baklavajs/llms.txt Mutate the `settings` property to adjust visual behavior like connection display, line styles, minimap, node resizing, zoom range, and context menu items. ```typescript import { useBaklava } from "@baklavajs/renderer-vue"; const baklava = useBaklava(); // Show connection values on hover baklava.settings.displayValueOnHover = true; // Use straight lines instead of curves for connections baklava.settings.useStraightConnections = true; // Enable the minimap overlay baklava.settings.enableMinimap = true; // Allow nodes to be resized by the user baklava.settings.nodes.resizable = true; // Customize zoom range baklava.settings.panZoom.minScale = 0.1; baklava.settings.panZoom.maxScale = 5; // Add entries to the right-click context menu baklava.settings.contextMenu.additionalItems = [ { label: "Fit to screen", action: () => baklava.commandHandler.executeCommand("ZOOM_TO_FIT") }, ]; ``` -------------------------------- ### Create a Select Interface Source: https://github.com/newcat/baklavajs/blob/master/docs/nodes/pre-defined-interfaces.md Use SelectInterface to display a dropdown for single value selection. It accepts an array of strings or objects with 'text' and 'value' properties. ```javascript import { SelectInterface } from "baklavajs"; new SelectInterface("Name", "Add", ["Add", "Subtract"]); new SelectInterface("Name", 1, [ { text: "A", value: 1 }, { text: "B", value: 2 }, { text: "C", value: 3 }, ]); ``` -------------------------------- ### Create and Register a New BaklavaJS Command Source: https://github.com/newcat/baklavajs/blob/master/docs/visual-editor/commands.md Define and register a custom command with specific execution logic. The command can accept arguments and return a value, with optional 'canExecute' validation. ```typescript import type { ICommandHandler, ICommand } from "../commands"; // first type argument is the return value of the command // second type argument are the inputs to the command type MyCommand = ICommand; viewModel.commandHandler.registerCommand("MyCommand", { canExecute: (id) => !!viewModel.displayedGraph.findNodeById(id), execute: (id) => { const node = viewModel.displayedGraph.findNodeById(id)!; viewModel.displayedGraph.removeNode(node); return node.type; }, }); // for invoking this command: viewModel.commandHandler.executeCommand("MyCommand", true, "myNodeId"); ``` -------------------------------- ### Initialize and Register Interface Types Plugin Source: https://github.com/newcat/baklavajs/blob/master/docs/nodes/interface-types.md Instantiate `BaklavaInterfaceTypes` with the editor instance and register your custom types. This plugin manages the type checking and conversion logic for node interfaces. ```javascript // In your App.vue or wherever you use the import { BaklavaInterfaceTypes, NodeInterfaceType } from "@baklavajs/interface-types"; import { stringType, numberType, booleanType } from "./interfaceTypes"; const baklavaView = useBaklava(); const editor = baklavaView.editor; const nodeInterfaceTypes = new BaklavaInterfaceTypes(editor, { viewPlugin: baklavaView }); nodeInterfaceTypes.addTypes(stringType, numberType, booleanType); ``` -------------------------------- ### Execute Existing BaklavaJS Commands Source: https://github.com/newcat/baklavajs/blob/master/docs/visual-editor/commands.md Invoke a predefined command by its string name using the command handler. Ensure the command exists before execution. ```typescript import { Commands } from "@baklavajs/renderer-vue"; viewModel.commandHandler.executeCommand(Commands.UNDO_COMMAND); ``` -------------------------------- ### Create a TextareaInput Interface Source: https://github.com/newcat/baklavajs/blob/master/docs/nodes/pre-defined-interfaces.md Use TextareaInputInterface to display a textarea field for multi-line user input. ```javascript import { TextareaInputInterface } from "baklavajs"; new TextareaInputInterface("Name", "Edit me"); ``` -------------------------------- ### Subscribe to Node Events with Entity Argument Source: https://github.com/newcat/baklavajs/blob/master/docs/event-system.md Demonstrates subscribing to an event on all nodes using proxied events. The listener receives both the event data and the emitting node. ```typescript const token = Symbol() editor.nodeEvents.update.subscribe(token, (data, node) => { // put your code here }); ``` -------------------------------- ### Provide Global Calculation Data (Manual Mode) Source: https://github.com/newcat/baklavajs/blob/master/docs/execution/setup.md Passes global data to the engine when running calculations manually using `runOnce`. This data is available in the `calculate` function of each node. ```typescript engine.runOnce({ offset: 5 }); ``` -------------------------------- ### Dependency Engine Source: https://context7.com/newcat/baklavajs/llms.txt Topologically sorts the graph and runs every node's `calculate` function in order. This engine is equivalent to the Baklava v1 engine behavior. ```APIDOC ## Dependency Engine — Graph Execution Topologically sorts the graph and runs every node's `calculate` function in order. Equivalent to the Baklava v1 engine behavior. ```ts import { Editor } from "@baklavajs/core"; import { DependencyEngine, applyResult, allowMultipleConnections } from "@baklavajs/engine"; import { defineNode, NodeInterface, NumberInterface } from "baklavajs"; // Node that accepts multiple incoming connections on one input const SumNode = defineNode({ type: "SumNode", inputs: { values: () => new NodeInterface("Values", []).use(allowMultipleConnections), }, outputs: { total: () => new NodeInterface("Total", 0), }, calculate({ values }) { return { total: values.reduce((a, b) => a + b, 0) }; }, }); // --- Setup --- const editor = new Editor(); editor.registerNodeType(SumNode); const engine = new DependencyEngine(editor); // Write results back to node interfaces so they display in the graph const token = Symbol("applyResult"); engine.events.afterRun.subscribe(token, (result) => { engine.pause(); applyResult(result, editor); engine.resume(); }); // Auto-run whenever the graph changes engine.start(); // Or run once manually, with optional global calculation data const result = await engine.runOnce({ timestamp: Date.now() }); // result is a Map ``` ``` -------------------------------- ### Provide Global Calculation Data (Automatic Mode) Source: https://github.com/newcat/baklavajs/blob/master/docs/execution/setup.md Registers a hook to provide global data for every automatic calculation triggered after `engine.start()`. This hook is called before each calculation cycle. ```typescript const token = Symbol("token"); engine.hooks.gatherCalculationData.subscribe(token, () => { return { offset: 5 }; }); engine.start(); ``` -------------------------------- ### Add Custom Toolbar Command Source: https://github.com/newcat/baklavajs/blob/master/docs/visual-editor/toolbar.md Integrate custom functionality into the toolbar. Register a command with the command handler, then define its appearance and add it to the toolbar's command list. ```typescript import { useBaklava, DEFAULT_TOOLBAR_COMMANDS } from "@baklavajs/renderer-vue"; import { defineComponent, h, markRaw } from "vue"; const baklavaView = useBaklava(); // 1. Register a custom command const CLEAR_ALL_COMMAND = "CLEAR_ALL"; baklavaView.commandHandler.registerCommand(CLEAR_ALL_COMMAND, { execute: () => { // Clear all nodes from the graph baklavaView.displayedGraph.nodes.forEach((node) => { baklavaView.displayedGraph.removeNode(node); }); }, // Optional: Define when the command can be executed canExecute: () => baklavaView.displayedGraph.nodes.length > 0, }); // 2. & 3. Add the command to the toolbar baklavaView.settings.toolbar.commands = [ ...DEFAULT_TOOLBAR_COMMANDS, { command: CLEAR_ALL_COMMAND, title: "Clear All", // Tooltip text icon: markRaw( defineComponent(() => { return () => h("div", "Clear All"); }), ), }, ]; ``` -------------------------------- ### Extend Editor Actions with Custom Commands Source: https://context7.com/newcat/baklavajs/llms.txt Register custom commands or invoke built-in commands like undo/redo and zoom-to-fit using the `commandHandler`. Custom commands can define `canExecute` and `execute` logic. ```typescript import { Commands } from "@baklavajs/renderer-vue"; import type { ICommand } from "@baklavajs/renderer-vue"; const baklava = useBaklava(); const { commandHandler, displayedGraph } = baklava; // Execute a built-in command commandHandler.executeCommand(Commands.UNDO_COMMAND); commandHandler.executeCommand(Commands.REDO_COMMAND); // Register a custom command // Type params: type DeleteNodeCommand = ICommand; commandHandler.registerCommand("DELETE_NODE_BY_ID", { canExecute: (id) => !!displayedGraph.findNodeById(id), execute: (id) => { const node = displayedGraph.findNodeById(id)!; displayedGraph.removeNode(node); return node.type; // returned to the caller }, }); // Invoke the custom command const deletedType = commandHandler.executeCommand( "DELETE_NODE_BY_ID", true, // check canExecute before running "node-id-42" ); console.log("Deleted node of type:", deletedType); ``` -------------------------------- ### Custom Icon with SVG Library Source: https://github.com/newcat/baklavajs/blob/master/docs/visual-editor/toolbar.md Utilize icons from an SVG library like Heroicons for custom toolbar command icons. Import the desired icon component and pass it to the `icon` property, wrapped in `markRaw`. ```typescript import { markRaw } from "vue"; import { TrashIcon } from "@heroicons/vue/24/outline"; // Use the imported icon component directly { command: CLEAR_ALL_COMMAND, title: "Clear All", icon: markRaw(TrashIcon) } ``` -------------------------------- ### Forward Engine for Execution-Flow Graphs Source: https://context7.com/newcat/baklavajs/llms.txt The Forward Engine executes graphs based on explicit execution-flow connections, supporting branching and loops. Use `executeOutput` for custom execution logic. ```typescript import { Editor } from "@baklavajs/core"; import { ForwardEngine, ExecutionFlowInterface, ForwardCalculationContext } from "@baklavajs/engine"; import { defineNode, NodeInterface } from "baklavajs"; // A branch node: routes execution based on a boolean condition const BranchNode = defineNode({ type: "BranchNode", inputs: { execIn: () => new ExecutionFlowInterface("Exec"), condition: () => new NodeInterface("Condition", false), }, outputs: { trueOut: () => new ExecutionFlowInterface("True"), falseOut: () => new ExecutionFlowInterface("False"), }, calculate({ condition }) { return { trueOut: !!condition, falseOut: !condition }; }, }); // A for-loop node using executeOutput const ForLoopNode = defineNode({ type: "ForLoopNode", inputs: { execIn: () => new ExecutionFlowInterface("Exec"), start: () => new NodeInterface("Start", 0), end: () => new NodeInterface("End", 5), }, outputs: { loopBody: () => new ExecutionFlowInterface("Loop Body"), completed: () => new ExecutionFlowInterface("Completed"), index: () => new NodeInterface("Index", 0), }, async calculate({ start, end }, context) { const { executeOutput } = context as ForwardCalculationContext; for (let i = start; i < end; i++) { await executeOutput("loopBody", { index: i }); } return { loopBody: false, completed: true, index: end }; }, }); // --- Setup --- const editor = new Editor(); editor.registerNodeType(BranchNode); editor.registerNodeType(ForLoopNode); const engine = new ForwardEngine(editor); // Manual execution starting from a specific node const triggerNode = editor.graph.nodes[0]; const result = await engine.runOnce(undefined, triggerNode, undefined); // Automatic: re-runs from the changed node on every value change engine.start(); ``` -------------------------------- ### Define Node with defineNode() Source: https://context7.com/newcat/baklavajs/llms.txt Define a node type using the `defineNode()` function, providing its type, title, inputs, outputs, and calculation logic. This is the recommended approach for most nodes. ```typescript // MathNode.ts import { defineNode, NodeInterface, NumberInterface, SelectInterface } from "baklavajs"; export default defineNode({ type: "MathNode", title: "Math", inputs: { number1: () => new NumberInterface("Number 1", 1), number2: () => new NumberInterface("Number 2", 10), operation: () => new SelectInterface("Operation", "Add", ["Add", "Subtract", "Multiply"]).setPort(false), }, outputs: { result: () => new NodeInterface("Result", 0), }, calculate({ number1, number2, operation }) { if (operation === "Add") return { result: number1 + number2 }; if (operation === "Subtract") return { result: number1 - number2 }; if (operation === "Multiply") return { result: number1 * number2 }; throw new Error(`Unknown operation: ${operation}`); }, }); ``` -------------------------------- ### Extend NodeInterface Class Source: https://github.com/newcat/baklavajs/blob/master/docs/nodes/interfaces.md Create custom node interface classes by extending `NodeInterface` to encapsulate common configurations like components and middleware. This reduces code duplication. ```javascript import { markRaw } from "vue"; import { NodeInterface, setType } from "baklavajs"; import MyComponent from "MyComponent.vue"; class MyNodeInterface extends NodeInterface { constructor(name: string) { super(name, 0); this.setComponent(markRaw(MyComponent)); // this is just an example, the interface types plugin works a bit different this.use(setType, "number"); } } const i = new MyNodeInterface("My Interface"); i.value; // -> 0 i.component === MyComponent; // -> true i.type; // -> "number" ``` -------------------------------- ### Replace UI Components with Custom Slots Source: https://context7.com/newcat/baklavajs/llms.txt Utilize named slots on `` to replace built-in UI components like node renderers or the entire toolbar with custom Vue components. ```vue ``` -------------------------------- ### Define Dynamic Node with Changing Interfaces Source: https://context7.com/newcat/baklavajs/llms.txt Use `defineDynamicNode` to create nodes where inputs/outputs change at runtime. Requires an `onUpdate` function to specify the dynamic interface state based on static inputs. ```typescript import { defineDynamicNode, NodeInterface, NumberInterface, SelectInterface, TextInputInterface } from "baklavajs"; export default defineDynamicNode({ type: "DynamicMathNode", inputs: { operation: () => new SelectInterface("Operation", "Add", ["Add", "Subtract", "Sine"]).setPort(false), }, outputs: { result: () => new NodeInterface("Result", 0), }, onUpdate({ operation }) { // "Sine" only needs one input; binary operations need two if (operation === "Sine") { return { inputs: { a: () => new NumberInterface("Value", 0) } }; } return { inputs: { a: () => new NumberInterface("A", 0), b: () => new NumberInterface("B", 0), }, }; }, calculate(inputs) { switch (inputs.operation) { case "Add": return { result: inputs.a + inputs.b }; case "Subtract": return { result: inputs.a - inputs.b }; case "Sine": return { result: Math.sin(inputs.a) }; default: throw new Error("Unknown operation"); } }, }); ``` -------------------------------- ### Create a Checkbox Interface Source: https://github.com/newcat/baklavajs/blob/master/docs/nodes/pre-defined-interfaces.md Use CheckboxInterface to display a checkbox. It expects a boolean value. ```javascript import { CheckboxInterface } from "baklavajs"; new CheckboxInterface("Name", true); ``` -------------------------------- ### BaklavaJS Event System Source: https://context7.com/newcat/baklavajs/llms.txt Utilize BaklavaEvent and PreventableBaklavaEvent for a token-based pub/sub system. Subscribe to events with tokens for easy unsubscription and use preventable events to cancel actions. ```typescript import { BaklavaEvent, PreventableBaklavaEvent } from "@baklavajs/events"; // Normal event const onDataChanged = new BaklavaEvent(null); const token = Symbol("myToken"); onDataChanged.subscribe(token, (value) => console.log("Value:", value)); onDataChanged.emit(42); // → "Value: 42" onDataChanged.unsubscribe(token); onDataChanged.emit(99); // (no output — unsubscribed) // Preventable event — fired before the action so it can be cancelled const beforeConnect = new PreventableBaklavaEvent(null); const guardToken = Symbol("guard"); beforeConnect.subscribe(guardToken, (connectionId, prevent) => { if (connectionId === "forbidden") { prevent(); } }); const wasPrevented = beforeConnect.emit("forbidden"); // → true const allowed = beforeConnect.emit("ok"); // → false // Real usage: prevent specific connections in the graph const editor = baklava.editor; editor.graphEvents.beforeAddConnection.subscribe(guardToken, (conn, prevent) => { if (conn.from.id === "restricted-output") { prevent(); } }); // Listen to events on ALL nodes via proxied events const updateToken = Symbol("update"); editor.nodeEvents.update.subscribe(updateToken, (data, node) => { console.log(`Node ${node.id} updated`, data); }); // Global calculation data hook engine.hooks.gatherCalculationData.subscribe(Symbol(), () => ({ frameTime: performance.now(), })); ``` -------------------------------- ### Backend Usage of BaklavaInterfaceTypes Source: https://github.com/newcat/baklavajs/blob/master/docs/nodes/interface-types.md Instantiates BaklavaInterfaceTypes with only the editor instance, omitting the useBaklava return value for backend-only calculations. ```javascript new BaklavaInterfaceTypes(editor); ```