3D - Rete.js

3D

This guide is based on the Basic guide. It is recommended to review it for a comprehensive understanding of this guide.

3DMultiple 3D editorsThree.jsPlugin

This guide outlines how to incorporate the node editor into a 3D scene. It can be achieved by rete-area-3d-plugin, which substitutes the standard rete-area-plugin.

Architecture

Powered by Three.js, this plugin creates a scene that contains a camera and two renderers - CSS3DRenderer and WebGLRenderer. Consequently, 3D objects and native HTML elements are rendered together in a single viewport, enabling overlapping. The primary advantage of utilizing native elements (as opposed to rendering to texture) is the preservation of full interactivity.

Install dependencies

Prior to using this plugin, three peer dependency must be installed separately.

bash
npm i rete-area-3d-plugin three @types/three

Plugin connection

If you have followed the basic guide, you will need to replace the initialization of Area2DPlugin with Area3DPlugin and change some type definitions.

ts
import { Area3D, Area3DPlugin } from 'rete-area-3d-plugin';

type AreaExtra =
  | Area3D<Schemes>

const area = new Area3DPlugin<Schemes, AreaExtra>(container);

editor.use(area);

Consequently, the container will incorporate both the <canvas> element and a container for HTML elements that undergo 3D transformation.

In case your editor has nodes, you can see them in the viewport, but they will not be interactive. To provide visual feedback for node interaction, it should be part of an animation loop and be linked to Object3D, which is directly responsible for dragging.

ts
Area3DExtensions.animate(area)

This extension adopts the typical three.js approach to animation loops, utilizing the render() function along with the requestAnimationFrame().

Additionally, we need to link our nodes and connections with the geometry in the 3D scene to allow for interactive functionality and prevent unwanted overlapping with other objects.

ts
Area3DExtensions.forms.connection(render);
Area3DExtensions.forms.node(area);

During rendering, these extensions produce geometry that accurately replicates the form of nodes and connections.

Now you can interact with the nodes and rotate or move the camera around them. Check out the complete result on the 3D example page.

Additional extensions

Some extensions available in the rete-area-plugin can be utilized solely within the editor, disregarding the viewport and similar factors.

ts
import { AreaExtensions } from 'rete-area-plugin'

AreaExtensions.showInputControl(area)
AreaExtensions.simpleNodesOrder(area)
AreaExtensions.snapGrid(area, { size: 30 })
AreaExtensions.selectableNodes(area, AreaExtensions.selector(), { accumulating: AreaExtensions.accumulateOnCtrl() });

In this plugin, the following extensions are available:

ts
import { Area3DExtensions } from 'rete-area-3d-plugin'

Area3DExtensions.forms.comment(area) // creates geometry for comments plugin
Area3DExtensions.forms.reroute(area) // creates geometry for reroute plugin

Area3DExtensions.lookAt(area, editor.getNodes()) // alternative to zoomAt from rete-area-plugin

Scene management

Scene

As previously stated, this plugin creates a scene complete with camera and renderers. To access them, you can use the following code:

ts
const { scene } = area.area

scene.root // three.js' Scene
scene.camera // PerspectiveCamera
scene.renderer.css3d // CSS3DRenderer
scene.renderer.webgl // WebGLRenderer
scene.orbit // OrbitControls

For instance, you have the option to deactivate orbital control (scene.orbit.enabled = false) and add an alternative one, or adjust the settings of renderers or camera.

You can add 3D objects by accessing the scene.root, which is a Scene instance in Three.js.

Custom HTML elements

If you want to include HTML elements within the scene, specifically within the editor's canvas, use the following code:

ts
area.area.content.add(element)

An HTML element will be added to the editor canvas at position zero. To ensure it doesn't overlap with other scene elements, it should have geometry that mirrors its form.

ts
area.area.content.updateGeometry(element, bufferGeometry)

Check out more examples in the source code

With regard to other HTML elements, it will maintain its own order, and you can modify it as follows:

ts
area.area.content.reorder(element, nextElement)

Removing element:

ts
area.area.content.remove(element)

Customization

In case you have customized your nodes or connections, you might discover that they don't match the placeholder in the 3D scene. To adapt them to new forms, you can either implement your own geometry or reuse existing with various arguments.

Example of modifying the border radius of a node:

ts
Area3DExtensions.forms.node(area, {
  customize(node) {
    return Area3DExtensions.forms.createClassicNodeGeometry(node, {
      borderRadius: 0
    })
  }
})

Example of a connection geometry featuring increased width:

ts
Area3DExtensions.forms.connection(reactRender, {
  customize(path) {
    return Area3DExtensions.forms.createClassicConnectionGeometry(path, 10)
  }
})

Multiple editors

Additionally, the plugin offers the capability to include several editors in a single scene. You can achieve this by creating a main Area3DPlugin instance and sharing it with other editors.

ts
const mainEditor = new NodeEditor<Schemes>();
const mainArea = new Area3DPlugin<Schemes, AreaExtra>(container)

mainEditor.use(mainArea)

const secondaryEditor = new NodeEditor<Schemes>();
const secondaryArea = mainArea.share()

secondaryEditor.use(secondaryArea)

Within a certain scene, you'll encounter two editors, placed in the same plane and overlapping each other. To separate them, you can change the position and orientation of the second editor.

ts
const canvas = secondaryArea.area.getCanvas()

canvas.rotateY(Math.PI / 2)
canvas.get(sharedArea)?.translateX(500)

Check out the complete result on the Multiple 3D editors example page.