---
title: Writing Node Trees
---

```{python}
from nodebpy import geometry as g
```

## Adding Nodes

Adding nodes must be done inside of a context. We enter a context using the `with` keyword.
While inside of this context, whenever you call a node class (`g.SetPosition()`) a node of that type will be added to the current tree.

This first example creates a new tree and adds two new nodes, linking the `Set Position` node into the `Transform Geometry` node. The output and input sockets for each are inferred based on simple heuristics around socket type and order.

```{python}
with g.tree("NewTree") as tree:
    g.SetPosition() >> g.TransformGeometry()

tree
```

These nodes can be saved as variables for re-use later in the node tree as well. After instantiating a class you can access the input and output sockets through the `.i` and `.o` accessors on the class.

These two approaches are equivalent:

::: {.panel-tabset}

## Individual Socket Access

```{python}
with g.tree("AnotherTree") as tree:
    pos = g.SetPosition()

    g.Position() * 0.5 >> pos.i.position
    g.Vector() >> pos.i.offset
```

## Using Arguments to Class

```{python}
with g.tree("AnotherAnotherTree") as tree:
    g.SetPosition(
        offset = g.Vector(),
        position = g.Position() * 0.5
    )
```

:::

```{python}
#| echo: false
tree
```

## Interface Sockets

The tree's interface defines what sockets are available as inputs and outputs of the node tree.

We declare them with `tree.inputs` and `tree.outputs` — for example `tree.inputs.geometry()` or `tree.outputs.float("Result")` — which add the interface socket and return it for linking with other nodes.

```{python}
with g.tree("NewTree") as tree:
    geom_inputs = [tree.inputs.geometry(f"Geometry_{i}") for i in range(5)]
    g.JoinGeometry(geom_inputs) >> tree.outputs.geometry("The Output Socket")

tree

```


```{python}
with g.tree() as tree:
    (
        tree.inputs.integer("Count", 10)
        >> g.Points(position=g.RandomValue.vector(min=(-0.1,-0.1,-0.2)))
        >> tree.outputs.geometry()
    )

tree
```

```{python}
with g.tree() as tree:
    count = tree.inputs.integer("Count", 10)
    pos = g.RandomValue.vector() * 0.5 * g.Position()
    g.Points(count, pos) >> tree.outputs.geometry()

tree
```

## Zones

Zones like the repeat and simulation zone are initialized with their `SimulationZone()` and `RepeatZone()` constructors. You can add individual `RepeatInput()` and output nodes, but they require additional setup to be actually linked. The repeat zone can be initialized with a repeat count, which can also be linked to from elsewhere.

We can access the input and output nodes with `zone.input` and `zone.output`. The repeat zone has `zone.iteration`, which is the iteration number of the current zone. The simulation zone has `zone.delta_time`, which is the time between the previous and current simulation loop.

Because of the complexity of zones, we have the `Item` helper which gives access to the input & output sockets on the input and output nodes (4 sockets total). For the Simulation and Repeat zones, we have the:

| Code | Socket|
| --- | --- |
 |`item.initial`| `zone.input.i["Geometry"]`|
 |`item.current`| `zone.input.o["Geometry"]`|
 |`item.next`| `zone.output.i["Geometry"]`|
 |`item.result`| `zone.output.o["Geometry"]`|


```{python}
with g.tree() as tree:
    zone = g.RepeatZone(10)
    random_pos = g.RandomValue.vector(seed=zone.iteration)
    geo = zone.item("Geometry", type="GEOMETRY")
    g.JoinGeometry([geo.current, g.Points(10, random_pos)]) >> geo.next
    geo.result >> tree.outputs.geometry()

tree
```


```{python}
with g.tree() as tree:
    # this initializes the zone with two socket inputs for each of the values
    # we manually specify the socket names
    zone = g.SimulationZone({"Value": g.Value(), "Vector": g.Vector()})
    zone.input.o["Value"] + 10 >> zone.output

    # this should automatically pick the vector input socket because we are
    # explicit about the VectorMath and it will be the most compatible
    zone.input >> g.VectorMath.add(..., (0.2, 0.4, 0.6)) >> zone.output

tree
```
