Welcome to BLOKIST

BLOKIST is a portable rapid prototyping tool for developers and non-developers. How? By keeping things visual & clickable from the start.

Usecases:

Getting started

Eventhough BLOKIST should run fine using touch, an keyboard & mouse is adviced for serious work. Basically the workflow is:

1. open the graph-view

2. add nodes (right-click mouse or double-tap)

3. connect by click+drag connectors

NOTE: there are 2 types of connectors, (JS) events & simple values.

4. write javascript (for advanced users)

Extend or create nodes programmatically using javascript:

4. share or embed!

Press the < > icon in the topbar.

Tutorials

The best way to start is looking at examples (click book-icon in the topbar, next to the cpu-meters)

JS Reference

Here you can find documentation concerning nodes, javascript function etc. Every existing function can be extended like so:

Global objects:

variable type description
graph LGraph the graph instance with 'alive' nodes
graph.framedelay LGraph usually unset, but setting it to 1000 will limit graph-mainloop to 1 fps. Useful to save cpu.
graphcanvas LGraphCanvas renders a graph to a html canvas
graphcanvas.canvas attached html canvas
viewport domelement a dom object which can be used for fullpage purposes (equals document.querySelector('#viewport'))
_ object contains utility functions like _.wrap (tip: add your own)

Node events

Event
onAdded
onRemoved
onExecute
onAction
onConnectInput
onConnectionsChange
onOutputDblClick
onOutputClick
onInputDblClick
onInputClick
onDblClick
onMouseDown
onMouseEnter
onMouseMove
onDropFile
onDropData
onDropItem
onSelected
onDeselected
onDrawForeground
onDrawCollapsed
onDrawBackground
onGetInputs
onGetOutputs
onStart
onStop

Each node can be extended using javascript, just create a script node and copy/paste this into the editor:

    // note: this runs every frame
    this.var = this.getInputDataByName("var", !this.var)
    this.setOutputData("var", this.var * 2 )

    this.onLoad  = () => {
      // this runs before nodes are added to the graph (pageload etc)
      require('./stdnodes.js')
      window.padstring = require('https://unpkg.com/padstring@1.0.0/padString.js')
    }

    this.onInit = () => {
        // this runs once a node is added to the graph
        // custom io instead of default inputs/outputs (rightclick node to enable)
        this.addInput("in2",LiteGraph.EVENT)
        this.addInput("var")
        this.addOutput("out2",LiteGraph.EVENT)
        this.addOutput("var")
    }

    this.onEvent = (action,args) => {
        // called when 'in2' or 'in' input is triggered
        this.trigger(false,{action,args}) // forward data to all (=false) outputs
    }

    return this.onEvent // optional: return promise for async support

The above demonstrates:

NOTE 1: In case you want to modify global node-behaviour see the Global modifications section.

NOTE 2: This would overwrite functions for certain nodes, in such case wrapping is better:

    _.wrap(node, 'onMouseDown', function(onMouseDown){
        // do stuff before
        onMouseDown()
        // do stuff after
    })

Global modifications

In case eventlisteners are too limited, here's how you monkeypatch the whole editor / engine:

// extend graph-function
_.wrap( graph, 'createNode', (createNode, type, title, opts) => {
    // do stuff before
    createNode(type, title, opts)
    // do stuff later
})

Same goes for nodes:

// inspect node functions
var nodes = LiteGraph.registered_node_types
console.dir(nodes["graphics/image"])

// extend node prototype function
_.wrap( nodes["graphics/image"].prototype, 'collapse', (collapse) => {
    alert("don't collapse this one!")
    // collapse()
})

NOTE: the wrapping-technique above will affect all newly created nodes. To modify the behaviour of already created nodes, Node events section above

FAQ

Contributing / Bugs

Nodes

LiteGraph

The Global Scope. It contains all the registered node classes.

LiteGraph = new LiteGraph()

LiteGraph.registerNodeType(type,base_class)

Register a node class so it can be listed when the user wants to create a new one

param type description
type String name of the node and path
base_class Class class containing the structure of a node

LiteGraph.wrapFunctionAsNode(name,func,param_types,return_type,properties)

Create a new nodetype by passing a function, it wraps it with a proper class and generates inputs according to the parameters of the function. Useful to wrap simple methods that do not require properties, and that only process some input to generate an output.

param type description
name String node name with namespace (p.e.: 'math/sum')
func Function
param_types Array [optional] an array containing the type of every parameter, otherwise parameters will accept any type
return_type String [optional] string with the return type, otherwise it will be generic
properties Object [optional] properties to be configurable

LiteGraph.addNodeMethod(func)

Adds this method to all nodetypes, existing and to be created (You can add it to LGraphNode.prototype but then existing node types wont have it)

param type description
func Function

LiteGraph.createNode(type,name,options)

Create a node of a given type with a name. The node is not attached to any graph yet.

param type description
type String full name of the node class. p.e. "math/sin"
name String a name to distinguish from other nodes
options Object to set options

LiteGraph.getNodeType(type)

Returns a registered node type with a given name

param type description
type String full name of the node class. p.e. "math/sin"

returns Class: the node class

LiteGraph.getNodeType(category)

Returns a list of node types matching one category

param type description
category String category name

returns Array: array with all the node classes

LiteGraph.getNodeTypesCategories()

Returns a list with all the node type categories

param type description

returns Array: array with all the names of the categories

LGraph

LGraph is the class that contain a full graph. We instantiate one and add nodes to it, and then we can run the execution loop.

graph = new LGraph()

graph.clear()

Removes all nodes from this graph

graph.attachCanvas(graph_canvas)

Attach Canvas to this graph

param type description
graph_canvas GraphCanvas

graph.detachCanvas(graph_canvas)

Detach Canvas from this graph

param type description
graph_canvas GraphCanvas

graph.start(interval)

Starts running this graph every interval milliseconds.

param type description
interval number amount of milliseconds between executions, if 0 then it renders to the monitor refresh rate

graph.stop()

Stops the execution loop of the graph

graph.runStep(num)

Run N steps (cycles) of the graph

param type description
num number number of steps to run, default is 1

graph.updateExecutionOrder()

Updates the graph execution order according to relevance of the nodes (nodes with only outputs have more relevance than nodes with only inputs.

graph.getAncestors()

Returns all the nodes that could affect this one (ancestors) by crawling all the inputs recursively. It doesn't include the node itself

param type description

returns Array: an array with all the LGraphNodes that affect this node, in order of execution

graph.arrange()

Positions every node in a more readable manner

graph.getTime()

Returns the amount of time the graph has been running in milliseconds

param type description

returns number: number of milliseconds the graph has been running

graph.getFixedTime()

Returns the amount of time accumulated using the fixedtime_lapse var. This is used in context where the time increments should be constant

param type description

returns number: number of milliseconds the graph has been running

graph.getElapsedTime()

Returns the amount of time it took to compute the latest iteration. Take into account that this number could be not correct if the nodes are using graphical actions

param type description

returns number: number of milliseconds it took the last cycle

graph.sendEventToAllNodes(eventname,params)

Sends an event to all the nodes, useful to trigger stuff

param type description
eventname String the name of the event (function to be called)
params Array parameters in array format

graph.add(node)

Adds a new node instance to this graph

param type description
node LGraphNode the instance of the node

graph.remove(node)

Removes a node from the graph

param type description
node LGraphNode the instance of the node

graph.getNodeById(id)

Returns a node by its id.

param type description
id Number

graph.findNodesByClass(classObject)

Returns a list of nodes that matches a class

param type description
classObject Class the class itself (not an string)

returns Array: a list with all the nodes of this type

graph.findNodesByType(type)

Returns a list of nodes that matches a type

param type description
type String the name of the node type

returns Array: a list with all the nodes of this type

graph.findNodeByTitle(name)

Returns the first node that matches a name in its title

param type description
name String the name of the node to search

returns Node: the node or null

graph.findNodesByTitle(name)

Returns a list of nodes that matches a name

param type description
name String the name of the node to search

returns Array: a list with all the nodes with this name

graph.getNodeOnPos(x,y,nodes_list)

Returns the top-most node in this position of the canvas

param type description
x number the x coordinate in canvas space
y number the y coordinate in canvas space
nodes_list Array a list with all the nodes to search from, by default is all the nodes in the graph

returns LGraphNode: the node at this position or null

graph.getGroupOnPos(x,y)

Returns the top-most group in that position

param type description
x number the x coordinate in canvas space
y number the y coordinate in canvas space

returns LGraphGroup: the group or null

graph.checkNodeTypes()

Checks that the node type matches the node type registered, used when replacing a nodetype by a newer version during execution this replaces the ones using the old version with the new version

graph.addGlobalInput(name,type,value)

Tell this graph it has a global graph input of this type

param type description
name String
type String
value undefined [optional]

graph.setGlobalInputData(name,data)

Assign a data to the global graph input

param type description
name String
data undefined

graph.getInputData(name)

Returns the current value of a global graph input

param type description
name String

returns undefined: the data

graph.renameInput(old_name,new_name)

Changes the name of a global graph input

param type description
old_name String
new_name String

graph.changeInputType(name,type)

Changes the type of a global graph input

param type description
name String
type String

graph.removeInput(name,type)

Removes a global graph input

param type description
name String
type String

graph.addOutput(name,type,value)

Creates a global graph output

param type description
name String
type String
value undefined

graph.setOutputData(name,value)

Assign a data to the global output

param type description
name String
value String

graph.getOutputData(name)

Returns the current value of a global graph output

param type description
name String

returns undefined: the data

graph.renameOutput(old_name,new_name)

Renames a global graph output

param type description
old_name String
new_name String

graph.changeOutputType(name,type)

Changes the type of a global graph output

param type description
name String
type String

graph.removeOutput(name)

Removes a global graph output

param type description
name String

graph.isLive()

returns if the graph is in live mode

graph.clearTriggeredSlots()

clears the triggered slot animation in all links (stop visual animation)

Destroys a link

param type description
link_id Number

graph.serialize()

Creates a Object containing all the info about this graph, it can be serialized

param type description

returns Object: value of the node

graph.configure(str,returns)

Configure a graph from a JSON string

param type description
str String configure a graph from a JSON string
returns Boolean if there was any error parsing

LGraphNode

myLGraphNode.method(name)

Base Class for all the node type classes

param type description
name String a name for the node

myLGraphNode.configure()

configure a node from an object containing the serialized info

myLGraphNode.serialize()

serialize the content

myLGraphNode.toString()

serialize and stringify

myLGraphNode.getTitle()

get the title string

myLGraphNode.setProperty(name,value)

sets the value of a property

param type description
name String
value undefined

myLGraphNode.setOutputData(slot,data)

sets the output data

param type description
slot number
data undefined

myLGraphNode.setOutputDataType(slot,datatype)

sets the output data type, useful when you want to be able to overwrite the data type

param type description
slot number
datatype String

myLGraphNode.getInputData(slot,force_update)

Retrieves the input data (data traveling through the connection) from one slot

param type description
slot number
force_update boolean if set to true it will force the connected node of this slot to output data into this link

returns undefined: data or if it is not connected returns undefined

myLGraphNode.getInputDataType(slot)

Retrieves the input data type (in case this supports multiple input types)

param type description
slot number

returns String: datatype in string format

myLGraphNode.getInputDataByName(slot_name,force_update)

Retrieves the input data from one slot using its name instead of slot number

param type description
slot_name String
force_update boolean if set to true it will force the connected node of this slot to output data into this link

returns undefined: data or if it is not connected returns null

myLGraphNode.isInputConnected(slot)

tells you if there is a connection in one input slot

param type description
slot number

returns boolean:

myLGraphNode.getInputInfo(slot)

tells you info about an input connection (which node, type, etc)

param type description
slot number

returns Object: object or null { link: id, name: string, type: string or 0 }

myLGraphNode.getInputNode(slot)

returns the node connected in the input slot

param type description
slot number

returns LGraphNode: node or null

myLGraphNode.getInputOrProperty(name)

returns the value of an input with this name, otherwise checks if there is a property with that name

param type description
name string

returns undefined: value

myLGraphNode.getOutputData(slot)

tells you the last output data that went in that slot

param type description
slot number

returns Object: object or null

myLGraphNode.getOutputInfo(slot)

tells you info about an output connection (which node, type, etc)

param type description
slot number

returns Object: object or null { name: string, type: string, links: [ ids of links in number ] }

myLGraphNode.isOutputConnected(slot)

tells you if there is a connection in one output slot

param type description
slot number

returns boolean:

myLGraphNode.isAnyOutputConnected()

tells you if there is any connection in the output slots

param type description

returns boolean:

myLGraphNode.getOutputNodes(slot)

retrieves all the nodes connected to this output slot

param type description
slot number

returns array:

myLGraphNode.trigger(event,param)

Triggers an event in this node, this will trigger any output with the same name

param type description
event String name ( "on_play", ... ) if action is equivalent to false then the event is send to all
param undefined

Triggers an slot event in this node

param type description
slot Number the index of the output slot
param undefined
link_id Number [optional] in case you want to trigger and specific output link in a slot

clears the trigger slot animation

param type description
slot Number the index of the output slot
link_id Number [optional] in case you want to trigger and specific output link in a slot

myLGraphNode.addProperty(name,default_value,type,extra_info)

add a new property to this node

param type description
name string
default_value undefined
type string string defining the output type ("vec3","number",...)
extra_info Object this can be used to have special properties of the property (like values, etc)

myLGraphNode.addOutput(name,type,extra_info)

add a new output slot to use in this node

param type description
name string
type string string defining the output type ("vec3","number",...)
extra_info Object this can be used to have special properties of an output (label, special color, position, etc)

myLGraphNode.addOutputs(array)

add a new output slot to use in this node

param type description
array Array of triplets like [[name,type,extra_info],[...]]

myLGraphNode.removeOutput(slot)

remove an existing output slot

param type description
slot number

myLGraphNode.addInput(name,type,extra_info)

add a new input slot to use in this node

param type description
name string
type string string defining the input type ("vec3","number",...), it its a generic one use 0
extra_info Object this can be used to have special properties of an input (label, color, position, etc)

myLGraphNode.addInputs(array)

add several new input slots in this node

param type description
array Array of triplets like [[name,type,extra_info],[...]]

myLGraphNode.removeInput(slot)

remove an existing input slot

param type description
slot number

myLGraphNode.addConnection(name,type,pos,direction)

add an special connection to this node (used for special kinds of graphs)

param type description
name string
type string string defining the input type ("vec3","number",...)
pos undefined position of the connection inside the node
direction string if is input or output

myLGraphNode.computeSize(minHeight)

computes the size of a node according to its inputs and output slots

param type description
minHeight number

returns number: the total size

myLGraphNode.addWidget()

Allows to pass

param type description

returns Object: the created widget

myLGraphNode.getBounding()

returns the bounding of the object, used for rendering purposes bounding is: [topleft_cornerx, topleft_cornery, width, height]

param type description

returns Float32Array: the total size

myLGraphNode.isPointInside(x,y)

checks if a point is inside the shape of a node

param type description
x number
y number

returns boolean:

myLGraphNode.getSlotInPosition(x,y)

checks if a point is inside a node slot, and returns info about which slot

param type description
x number
y number

returns Object: if found the object contains { input|output: slot object, slot: number, link_pos: [x,y] }

myLGraphNode.findInputSlot(name)

returns the input slot with a given name (used for dynamic slots), -1 if not found

param type description
name string the name of the slot

returns number: the slot (-1 if not found)

myLGraphNode.findOutputSlot(name)

returns the output slot with a given name (used for dynamic slots), -1 if not found

param type description
name string the name of the slot

returns number: the slot (-1 if not found)

myLGraphNode.connect(slot,node,target_slot)

connect this node output to the input of another node

param type description
slot number_or_string (could be the number of the slot or the string with the name of the slot)
node LGraphNode the target node
target_slot number_or_string the input slot of the target node (could be the number of the slot or the string with the name of the slot, or -1 to connect a trigger)

returns Object: the link_info is created, otherwise null

myLGraphNode.disconnectOutput(slot,target_node)

disconnect one output to an specific node

param type description
slot number_or_string (could be the number of the slot or the string with the name of the slot)
target_node LGraphNode the target node to which this slot is connected [Optional, if not target_node is specified all nodes will be disconnected]

returns boolean: if it was disconnected successfully

myLGraphNode.disconnectInput(slot)

disconnect one input

param type description
slot number_or_string (could be the number of the slot or the string with the name of the slot)

returns boolean: if it was disconnected successfully

myLGraphNode.getConnectionPos(is_input,slot,out)

returns the center of a connection point in canvas coords

param type description
is_input boolean true if if a input slot, false if it is an output
slot number_or_string (could be the number of the slot or the string with the name of the slot)
out vec2 [optional] a place to store the output, to free garbage

returns undefined: the position

myLGraphNode.collapse()

Collapse the node to make it smaller on the canvas

myLGraphNode.pin()

Forces the node to do not move or realign on Z

LGraphCanvas

This class is in charge of rendering one graph inside a canvas. And provides all the interaction required. Valid callbacks are: onNodeSelected, onNodeDeselected, onShowNodePanel, onNodeDblClicked

myLGraphCanvas = new LGraphCanvas()

myLGraphCanvas.clear()

clears all the data inside

myLGraphCanvas.setGraph(graph)

assigns a graph, you can reassign graphs to the same canvas

param type description
graph LGraph

myLGraphCanvas.openSubgraph(graph)

opens a graph contained inside a node in the current graph

param type description
graph LGraph

myLGraphCanvas.closeSubgraph(assigns)

closes a subgraph contained inside a node

param type description
assigns LGraph a graph

myLGraphCanvas.getCurrentGraph()

returns the visualy active graph (in case there are more in the stack)

param type description

returns LGraph: the active graph

myLGraphCanvas.setCanvas(assigns)

assigns a canvas

param type description
assigns Canvas a canvas (also accepts the ID of the element (not a selector)

myLGraphCanvas.bindEvents()

binds mouse, keyboard, touch and drag events to the canvas

myLGraphCanvas.unbindEvents()

unbinds mouse events from the canvas

myLGraphCanvas.enableWebGL()

this function allows to render the canvas using WebGL instead of Canvas2D this is useful if you plant to render 3D objects inside your nodes, it uses litegl.js for webgl and canvas2DtoWebGL to emulate the Canvas2D calls in webGL

LGraphCanvas

myLGraphCanvas.setDirty(fgcanvas,bgcanvas)

marks as dirty the canvas, this way it will be rendered again

param type description
fgcanvas bool if the foreground canvas is dirty (the one containing the nodes)
bgcanvas bool if the background canvas is dirty (the one containing the wires)

myLGraphCanvas.getCanvasWindow()

Used to attach the canvas in a popup

param type description

returns window: returns the window where the canvas is attached (the DOM root node)

myLGraphCanvas.startRendering()

starts rendering the content of the canvas when needed

myLGraphCanvas.stopRendering()

stops rendering the content of the canvas (to save resources)

myLGraphCanvas.processMouseMove()

Called when a mouse move event has to be processed

myLGraphCanvas.processMouseUp()

Called when a mouse up event has to be processed

myLGraphCanvas.processMouseWheel()

Called when a mouse wheel event has to be processed

myLGraphCanvas.isOverNodeBox()

returns true if a position (in graph space) is on top of a node little corner box

myLGraphCanvas.isOverNodeInput()

returns true if a position (in graph space) is on top of a node input slot

myLGraphCanvas.processKey()

process a key event

myLGraphCanvas.processDrop()

process a item drop event on top the canvas

myLGraphCanvas.selectNode()

selects a given node (or adds it to the current selection)

myLGraphCanvas.selectNodes()

selects several nodes (or adds them to the current selection)

myLGraphCanvas.deselectNode()

removes a node from the current selection

myLGraphCanvas.deselectAllNodes()

removes all nodes from the current selection

myLGraphCanvas.deleteSelectedNodes()

deletes all nodes in the current selection from the graph

myLGraphCanvas.centerOnNode()

centers the camera on a given node

myLGraphCanvas.adjustMouseEvent()

adds some useful properties to a mouse event, like the position in graph coordinates

myLGraphCanvas.setZoom()

changes the zoom level of the graph (default is 1), you can pass also a place used to pivot the zoom

myLGraphCanvas.convertOffsetToCanvas()

converts a coordinate from graph coordinates to canvas2D coordinates

myLGraphCanvas.convertCanvasToOffset()

converts a coordinate from Canvas2D coordinates to graph space

myLGraphCanvas.bringToFront()

brings a node to front (above all other nodes)

myLGraphCanvas.sendToBack()

sends a node to the back (below all other nodes)

myLGraphCanvas.computeVisibleNodes()

checks which nodes are visible (inside the camera area)

myLGraphCanvas.draw()

renders the whole canvas content, by rendering in two separated canvas, one containing the background grid and the connections, and one containing the nodes)

myLGraphCanvas.drawFrontCanvas()

draws the front canvas (the one containing all the nodes)

myLGraphCanvas.renderInfo()

draws some useful stats in the corner of the canvas

myLGraphCanvas.drawBackCanvas()

draws the back canvas (the one containing the background and the connections)

myLGraphCanvas.drawNode()

draws the given node inside the canvas

myLGraphCanvas.drawNodeShape()

draws the shape of the given node in the canvas

myLGraphCanvas.drawConnections()

draws every connection visible in the canvas OPTIMIZE THIS: pre-catch connections position instead of recomputing them every time

draws a link between two points

param type description
a vec2 start pos
b vec2 end pos
link Object the link object with all the link info
skip_border boolean ignore the shadow of the link
flow boolean show flow animation (for events)
color string the color for the link
start_dir number the direction enum
end_dir number the direction enum
num_sublines number number of sublines (useful to represent vec3 or rgb)

myLGraphCanvas.drawNodeWidgets()

draws the widgets stored inside a node

myLGraphCanvas.processNodeWidgets()

process an event on widgets

myLGraphCanvas.drawGroups()

draws every group area in the background

myLGraphCanvas.resize()

resizes the canvas to a given size, if no size is passed, then it tries to fill the parentNode

myLGraphCanvas.switchLiveMode()

switches to live mode (node shapes are not rendered, only the content) this feature was designed when graphs where meant to create user interfaces

ContextMenu

ContextMenu from LiteGUI

myContextMenu = new ContextMenu()