Modly Workflow Node Types: Source-Only vs Sink-Only Nodes Explained

Modly defines five specialized node types: three source-only nodes (imageNode, textNode, meshNode) that initiate workflows without consuming inputs, and two sink-only nodes (outputNode, previewNode) that terminate workflows by consuming data without producing further output.

Modly is an open-source visual workflow editor for 3D content processing maintained in the lightningpixel/modly repository. The application organizes processing pipelines as directed graphs where data flows from entry points through processing steps to terminal outputs. Understanding the distinction between source-only and sink-only node types is essential for constructing valid workflows that execute correctly from initiation to termination.

Source-Only Nodes in Modly

Source-only nodes function as workflow entry points. According to the node catalog in src/areas/workflows/WorkflowsPage.tsx (lines 98-100), these nodes have no incoming edges and serve as the starting points for any processing pipeline. The runner logic treats them as origins where data first enters the system.

Image Source Node (imageNode)

The imageNode supplies a local image file that becomes the initial input for downstream processing. Defined at line 98 of WorkflowsPage.tsx, this node is labeled "Image" in the UI palette and is implemented in src/areas/workflows/nodes/ImageNode.tsx. It requires no predecessor nodes and outputs image data to connected extensions.

Text Source Node (textNode)

The textNode provides a text prompt that can be fed to extensions expecting string inputs. Listed at line 99 of WorkflowsPage.tsx with the UI label "Text", this node is implemented in TextNode.tsx. It allows users to input literal text values or prompts that initiate AI-driven processing steps.

Mesh Source Node (meshNode)

The meshNode supplies 3D mesh data including .glb, .obj, .stl, .ply, and .splat files, or the model currently displayed in the viewer. Defined at line 100 of WorkflowsPage.tsx under the label "Load 3D Mesh", this node is implemented in MeshNode.tsx. It serves as the entry point for geometry-based workflows.

Sink-Only Nodes in Modly

Sink-only nodes function as workflow termination points. These nodes consume data from upstream processing but never emit output to subsequent steps. In src/areas/workflows/nodeBehaviors.ts (lines 26-28), these nodes are flagged with sceneOutput: true, indicating they represent final destinations in the control flow graph.

Scene Output Node (outputNode)

The outputNode consumes a mesh and pushes it directly into the 3D scene when the workflow finishes. Defined at line 101 of WorkflowsPage.tsx with the UI label "Add to Scene", this node is implemented in OutputNode.tsx. The behavior registry marks this node with both sceneOutput: true and branchConsumer: true, identifying it as a terminal consumer that terminates execution branches.

Preview Node (previewNode)

The previewNode consumes image data (or sets of images) and displays them in a 2×3 grid for quick inspection. Listed at line 102 of WorkflowsPage.tsx under the label "Preview Views" and implemented in PreviewNode.tsx, this node provides visual feedback without modifying the scene graph or passing data downstream.

How Node Behaviors Are Defined

The workflow runner's control-flow logic relies on predicates defined in src/areas/workflows/nodeBehaviors.ts to classify nodes. The registry uses boolean flags to determine execution behavior:

  • isSceneOutput: Identifies sink-only nodes that terminate data flow
  • isBranchConsumer: Marks nodes (like outputNode) that consume entire branches
  • isPassthrough and isBranchStarter: Classify intermediate processing nodes

Only the three source nodes lack predecessors in the valid graph structure, and only the two sink nodes are flagged as scene outputs. This strict typing prevents the runner from traversing terminal nodes as intermediate processing steps.

Programmatically Creating Source and Sink Nodes

When building workflows programmatically using the React Flow API that Modly wraps, you instantiate these node types by their string identifiers. Below is a complete example creating an image source connected to a scene output sink:

// 1️⃣ Create a new image source node
const imageNode = {
  id: newId(),
  type: 'imageNode',          // ← source-only
  data: { /* optional metadata */ },
  position: { x: 100, y: 100 },
};

// 2️⃣ Create a sink node that will receive the mesh
const outputNode = {
  id: newId(),
  type: 'outputNode',         // ← sink-only
  data: {},
  position: { x: 400, y: 100 },
};

// 3️⃣ Wire the nodes together (image → output)
const edge = {
  id: newId(),
  source: imageNode.id,
  target: outputNode.id,
  type: 'workflowEdge',
};

setNodes((ns) => [...ns, imageNode, outputNode]);
setEdges((es) => [...es, edge]);

Running this workflow starts execution at imageNode (source) and completes when outputNode receives the produced data (sink). The runner validates that no edges extend from sink nodes and that source nodes have no incoming connections.

Summary

  • Source-only nodes (imageNode, textNode, meshNode) initiate workflows by supplying initial data without consuming inputs.
  • Sink-only nodes (outputNode, previewNode) terminate workflows by consuming data and pushing results to the scene or preview grid without downstream output.
  • Node classifications are defined in WorkflowsPage.tsx (lines 98-102) and enforced by the behavior registry in nodeBehaviors.ts using flags like sceneOutput and branchConsumer.
  • The workflow runner uses these classifications to validate graph topology and control execution flow from entry points to terminal nodes.

Frequently Asked Questions

What makes a node "source-only" in Modly?

A source-only node has no incoming edges and serves as a workflow entry point. According to the explanatory paragraphs at lines 616-632 of WorkflowsPage.tsx, these nodes are explicitly listed in the palette as source nodes because they provide initial data (images, text, or 3D meshes) without requiring upstream processing. The runner identifies them by their lack of predecessors in the directed graph.

Can sink-only nodes produce output for downstream processing?

No. Sink-only nodes are terminal endpoints marked with sceneOutput: true in nodeBehaviors.ts. They consume data from upstream nodes but do not emit values to subsequent steps. Attempting to connect an edge from a sink node like outputNode to another node would violate the workflow topology constraints enforced by the runner's validation logic.

How does the workflow runner identify terminal nodes?

The runner checks the node-behaviors registry (nodeBehaviors.ts) for predicates such as isSceneOutput and isBranchConsumer. Nodes flagged with these properties are treated as terminal sinks. For example, outputNode carries both sceneOutput: true and branchConsumer: true, signaling the runner to terminate the execution branch when reaching this node.

Where are node types defined in the Modly codebase?

Built-in node types are cataloged in src/areas/workflows/WorkflowsPage.tsx (lines 98-102) where the UI palette lists each node's type string, label, and description. The concrete implementations reside in src/areas/workflows/nodes/ (e.g., ImageNode.tsx, OutputNode.tsx), while execution behaviors are declared separately in src/areas/workflows/nodeBehaviors.ts to decouple UI presentation from runtime logic.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →