BaklavaJS Documentation
repository·master·Indexed 24 days ago
https://github.com/newcat/baklavajsA web-based graph and node editor built with VueJS and TypeScript. BaklavaJS features a modular plugin system allowing for visual UI editing and headless graph execution. It provides a core engine for node-based programming, a Vue renderer, and specialized packages for event management, interface types, and calculation execution.
What's inside BaklavaJS
- BaklavaJS is a graph and node editor designed for the web, built using VueJS. It provides a user-friendly editor interface and a highly extensible plugin system that allows developers to create custom nodes. The entire ecosystem is written in TypeScript to ensure type safety.
What is the Forward Engine and when to use it
masterThe Forward Engine is an execution model where execution flows forward through explicit connections, while data dependencies are resolved backward on demand. This is similar to Unreal Engine Blueprints or Unity Visual Scripting.
Use the Forward Engine when you need:
- Explicit execution flow: Control the order and selection of running nodes.
- Branching: Conditionally execute different paths.
- Loops: Execute a subchain of nodes multiple times.
- Event-driven execution: Start execution from a specific trigger node.
Use the Dependency Engine instead if: You only need a simple dataflow graph where all nodes are always calculated based on their dependencies.
What is a Graph in BaklavaJS?
masterAGraphis a collection of nodes and the connections (edges) between them. It acts as a workspace that provides specific functions to modify the set of nodes and connections, and allows users to listen to graph-specific events.Cycle handling in the Forward Engine
masterThe Forward Engine has different rules for connection types:
- Execution-flow connections: Cycles are allowed (required for implementing loops).
- Data connections: Cycles are not allowed. The engine will prevent the creation of data connections that would introduce a cycle.
Use normal and preventable events
masterBaklavaJS distinguishes between two types of events:
- Normal Events: Fired after an action occurs, typically used for reacting to changes.
- Preventable Events: Fired before an action occurs. Listeners can call a
prevent()function provided in the callback arguments to cancel the action. These events often use thebeforeprefix (e.g.,beforeAddConnection).
When using a
PreventableBaklavaEvent, the.emit()method returns a boolean indicating whether the action was prevented.import { PreventableBaklavaEvent } from "@baklavajs/events"; const ev = new PreventableBaklavaEvent<string, null>(null); const token = Symbol(); ev.subscribe(token, (data, prevent) => { if (data === "prevent me") { prevent(); return; } console.log(data); }); function emit(data: string) { if (ev.emit(data)) { console.log("prevented"); } } emit("prevent me"); emit("this works");How BaklavaJS plugins work
masterBaklavaJS uses a modular architecture where the core logic is separated from rendering and execution. This allows you to build different types of applications (e.g., a visual editor, a headless calculation engine, or a type-safe logic builder) by composing different packages.
- Core: Manages the graph structure and node logic.
- Engine: Extends the core to allow the graph to actually execute logic/calculations.
- Interface Types: Adds a layer of validation to the graph, ensuring connections only occur between compatible types and handling conversions.
- Renderer: The visual layer (specifically
@baklavajs/renderer-vuefor Vue users) that turns the graph data into an interactive UI.
Understand the BaklavaJS Editor model
masterThe
Editoris the central model class in BaklavaJS and serves as the primary container for all other components. Everything in a Baklava application lives inside an editor instance.Key responsibilities of the
Editorinclude:- Managing the lifecycle of graphs.
- Providing functions for saving and loading state.
- Registering node types.
- Providing a subscription mechanism for the event system.
An editor instance always contains exactly one main graph, known as the root graph, which is accessible via
editor.graph. The editor also maintains a collection of all graph instances (including subgraphs) viaeditor.graphs.What are Commands in BaklavaJS
masterCommands are an abstraction used to extend actions within BaklavaJS. They allow you to encapsulate logic (like undo/redo or custom node manipulations) into named, executable units. All command-related functionality is managed via thecommandHandlerinterface (specificallyICommandHandler).Understand the `onUpdate` return structure for Dynamic Nodes
masterThe
onUpdate(inputValues, outputValues)function determines the target state of a dynamic node's interfaces. It returns aDynamicNodeUpdateResultobject.If a key is present in the returned
inputsoroutputsobject, the interface is created or updated. If a key is missing from the returned object, the corresponding interface is removed from the node. This allows the node to automatically synchronize its interface state with the returned definition.type DynamicNodeDefinition = Record<string, () => NodeInterface<any>>; interface DynamicNodeUpdateResult { inputs?: DynamicNodeDefinition; outputs?: DynamicNodeDefinition; forceUpdateInputs?: string[]; forceUpdateOutputs?: string[]; }How Subgraph Instances and Templates Work
masterSubgraphs operate through a relationship between a
GraphNodeand aGraphTemplate:- GraphTemplate: The source of truth containing the nodes and connections.
- GraphNode: An instance in a parent graph that contains an internal graph instance.
- Relationship: Each
GraphNodeholds an internal graph that is based on theGraphTemplateof the subgraph.
When you edit a subgraph, you are modifying the
GraphTemplate. TheGraphNodeinstances in the root graph reference this template. Changes to the template are propagated to the instances when the template is saved.How graph execution works with Engines
masterBaklavaJS uses Engines to execute compute graphs. While the Editor is used for editing, Engines handle the actual computation logic. There are two primary engine types:
- Dependency Engine: Executes based on dependency tracking. Use this if you want the behavior of Baklava V1.
- Forward Engine: Executes in a forward-pass manner.
Regardless of the engine type, all nodes must implement a
calculatefunction to participate in execution.How the BaklavaJS event system works
masterBaklavaJS uses a custom event system designed for extensibility and plugin support. Classes supporting this system expose
eventsand/orhookproperties.To support inline arrow functions (which cannot be easily removed via function reference), BaklavaJS uses
tokens. A token can be any reference type (object, array,this) or aSymbol. You provide the token when calling.subscribe()and must provide the same token when calling.unsubscribe()to remove the listener.import { BaklavaEvent } from "@baklavajs/events"; const ev = new BaklavaEvent<string, null>(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");