Was damit gemeint ist?
=> Ein Behavior Asset als Node innerhalb eines Graph
Grundsätzlich soll so ein Behavior Node im Graf mit einem Execution Flow ausgestattet sein, sprich wir brauchen einen Start/End Node:
Start Node ist ähnlich wie ein Event Node mit exec output port und dort soll man auch ouput "variablen" festlegen können (quasi wie variablen)
End Node ähnlich, hat als Input ein exec port + inputs die als output gelten, wenn man es als node in einen anderen graphen eines behavior assets einbindet.
wenn alles verstanden, direkt loslegen, ansonsten warte ich auf rückfragen :)
Umgesetzt
Verstanden war alles — gebaut ist genau die beschriebene Form. Drei neue Node-Typen:
Start
exec-Ausgang plus die Eingaenge, die das Behavior von aussen bekommt. Was hier deklariert wird, ist ein Eingang des aufrufenden Nodes
End
exec-Eingang plus die Werte, die zurueckgehen. Was hier deklariert wird, ist ein Ausgang des aufrufenden Nodes
Run behavior
der Aufruf selbst. Seine Ports gibt es nicht in seiner Typdefinition — sie werden aus Start- und End-Node des Ziels abgeleitet, bei jedem Zeichnen neu
Deklariert wird im Inspector des Start-/End-Nodes: + Input bzw. + Output, Art waehlbar
(Number, Boolean, Text, Object), Name direkt editierbar, × zum Entfernen — dieselbe Bauform
wie die Variablen eines Behaviors.
Der Node traegt den Namen des Behaviors, nicht "Run behavior", und die Palette listet
Behaviors ebenfalls namentlich. Ein Aufruf ist damit ein Griff statt Node einfuegen + Dropdown.
Die eine Entscheidung, die du mir ueberlassen hast
Ein eingebettetes Behavior hat kein Objekt in der Szene — also auch keinen Ort fuer seine
Variablen. Ich habe (A) reine Funktion gewaehlt: jeder Aufruf startet die Variablen auf den
Asset-Defaults, rein geht es ueber den Start-Node, raus ueber den End-Node.
Der Grund ist dein eigener naechster Schritt: du willst den Tetris-Graphen zerlegen. Dabei
sollen die Teile rechnen, waehrend der Zustand (grid, pieceX, …) im Haupt-Behavior
bleibt — genau das, was du mit "kann man ueber input/output loesen" gemeint hast. (A) ist
ausserdem die konservative Wahl: daraus laesst sich spaeter Zustand machen, umgekehrt nicht,
ohne bestehende Graphen zu brechen.
Die Tuer ist nicht zu: Zustand gibt es weiterhin ueber ein Behavior-Objekt in der Szene
(Object by name → Get/Set property) — der Weg, den dein Jump and Run fuer den Punktestand
schon geht. Lokale Variablen im eingebetteten Graphen funktionieren als Zwischenspeicher
innerhalb eines Aufrufs unveraendert; sie werden nur am Ende verworfen.
Was ich selbst entschieden habe
Ein Start, ein End
ein zweiter machte "welche Ports hat dieses Behavior" mehrdeutig. Der Command lehnt ihn ab, die Palette bietet ihn nicht mehr an
Selbstaufruf = Fehler
mit Namen im Log (Behavior "X" runs itself), statt still in die Tiefenbegrenzung zu laufen. Die Palette bietet das eigene Behavior gar nicht erst an
self/owner bleiben
der eingebettete Graph sieht dasselbe Objekt wie der Aufrufer — sonst waeren Self/Owner darin wertlos
Toter Verweis ist still
ein Node ohne gewaehltes Behavior (oder eines ohne Start-Node) tut nichts und laesst den Fluss weiterlaufen, statt den Lauf abzubrechen
Zwei Dinge, die der Bau erzwungen hat
Eigener Pulse-Cache pro Aufruf. Node-Ids sind nur pro Graph eindeutig. Liefe der
eingebettete Graph im Cache des Aufrufers, koennte er dessen Werte ueberschreiben. Der
Interpreter arbeitet deshalb auf Frames — der Aufruf schiebt einen neuen auf und nimmt ihn
danach wieder weg. Dafuer gibt es einen eigenen Test, der eine Id-Kollision erzwingt; ohne
Frames liefert er 99 statt 7.
Ports aufraeumen ueber Graphgrenzen. Einen Port umzubenennen oder zu entfernen betrifft
nicht nur den eigenen Graphen, sondern jeden anderen, der das Behavior aufruft. Beides
raeumt dort mit auf — und ein Rename nimmt den eingetippten Inline-Wert mit, sonst faellt er
still auf den Default zurueck. Das ist mir erst beim Gegenpruefen aufgefallen: der Test stand
auf 0 statt auf 6.
Live-Highlight: der Trace eines laufenden Behaviors deckt jetzt auch die Graphen ab, die es
als Node aufruft — sonst bliebe ein eingebettetes Behavior beim Zusehen dunkel.
Belegt
Zehn Unit-Tests (tests/core/nested-behavior.test.ts) und elf E2E-Checks in Modul 19.
Der staerkste ist der erste: das aufrufende Behavior rechnet nichts selbst — die
Geschwindigkeit, mit der die Kiste laeuft, ist der zurueckgegebene Wert.
PASS a behavior used as a node runs, and what it returns is what drives the caller
– moved 200.0 px in ~1 s – 2 × 100 means the returned value arrived, 0 would mean nothing came back
PASS the calling node grows the ports the other behavior declares
PASS and it is drawn under that behavior's name, not as "Run behavior" – title="Double"
PASS adding an input declares it on the start node – [{"key":"in1",…},{"key":"in2",…}]
PASS and the node in the other graph grew that input without being touched
PASS undo removes it in both graphs – [{"key":"in1","kind":"number"}]
PASS picking a behavior in the palette drops in a node already set to it
– {"type":"RunBehavior","params":{"behavior":"nb-double"}}
200.0 statt 100 beweist, dass der verdoppelte Wert ankam, nicht bloss irgendeiner; 0 waere "nichts kam zurueck". Die drei Port-Checks in Folge sind der Nachweis, dass die
Portliste wirklich abgeleitet und nicht kopiert ist: deklariert wird im einen Graphen,
gewachsen ist der Node im anderen, ohne dass er angefasst wurde.
Gegenprobe gefahren: ohne die frische Variablenkopie und ohne die Selbstaufruf-Sperre fallen
zwei Unit-Tests; ohne getrennte Frames faellt der Kollisionstest (expected 99 to be 7) — der
war beim ersten Versuch faelschlich gruen und musste geschaerft werden, bevor er etwas taugte.
volle E2E-Suite, remote
ALL PASSED – 379 Checks, 0 FAIL
npm run check lokal
gruen, 524 Tests
Übernommen aus todo-notes/done/nested-behavior.md beim Umzug auf das Issue-System (2026-09-12).
Angelegt: 2026-09-09 · 64e034f — Note down two more wishes
Abgeschlossen: 2026-09-09 · 6702ff8 — Let a behavior be a node in another graph
Gemeldet von: admin
## Nested Behavior / Behavior als Node in Graph
Was damit gemeint ist?
=> Ein Behavior Asset als Node innerhalb eines Graph
Grundsätzlich soll so ein Behavior Node im Graf mit einem Execution Flow ausgestattet sein, sprich wir brauchen einen Start/End Node:
- Start Node ist ähnlich wie ein Event Node mit exec output port und dort soll man auch ouput "variablen" festlegen können (quasi wie variablen)
- End Node ähnlich, hat als Input ein exec port + inputs die als output gelten, wenn man es als node in einen anderen graphen eines behavior assets einbindet.
wenn alles verstanden, direkt loslegen, ansonsten warte ich auf rückfragen :)
---
## Umgesetzt
Verstanden war alles — gebaut ist genau die beschriebene Form. Drei neue Node-Typen:
| | |
|---|---|
| **`Start`** | exec-Ausgang plus die Eingaenge, die das Behavior von aussen bekommt. Was hier deklariert wird, ist ein **Eingang des aufrufenden Nodes** |
| **`End`** | exec-Eingang plus die Werte, die zurueckgehen. Was hier deklariert wird, ist ein **Ausgang des aufrufenden Nodes** |
| **`Run behavior`** | der Aufruf selbst. Seine Ports gibt es nicht in seiner Typdefinition — sie werden aus Start- und End-Node des Ziels **abgeleitet**, bei jedem Zeichnen neu |
Deklariert wird im Inspector des Start-/End-Nodes: `+ Input` bzw. `+ Output`, Art waehlbar
(Number, Boolean, Text, Object), Name direkt editierbar, `×` zum Entfernen — dieselbe Bauform
wie die Variablen eines Behaviors.
**Der Node traegt den Namen des Behaviors**, nicht "Run behavior", und die Palette listet
Behaviors ebenfalls namentlich. Ein Aufruf ist damit ein Griff statt Node einfuegen + Dropdown.
## Die eine Entscheidung, die du mir ueberlassen hast
Ein eingebettetes Behavior hat kein Objekt in der Szene — also auch keinen Ort fuer seine
Variablen. Ich habe **(A) reine Funktion** gewaehlt: jeder Aufruf startet die Variablen auf den
Asset-Defaults, rein geht es ueber den Start-Node, raus ueber den End-Node.
Der Grund ist dein eigener naechster Schritt: du willst den Tetris-Graphen zerlegen. Dabei
sollen die Teile *rechnen*, waehrend der Zustand (`grid`, `pieceX`, …) im Haupt-Behavior
bleibt — genau das, was du mit "kann man ueber input/output loesen" gemeint hast. (A) ist
ausserdem die konservative Wahl: daraus laesst sich spaeter Zustand machen, umgekehrt nicht,
ohne bestehende Graphen zu brechen.
**Die Tuer ist nicht zu:** Zustand gibt es weiterhin ueber ein Behavior-Objekt in der Szene
(`Object by name` → `Get/Set property`) — der Weg, den dein Jump and Run fuer den Punktestand
schon geht. Lokale Variablen im eingebetteten Graphen funktionieren als Zwischenspeicher
innerhalb eines Aufrufs unveraendert; sie werden nur am Ende verworfen.
## Was ich selbst entschieden habe
| | |
|---|---|
| **Ein Start, ein End** | ein zweiter machte "welche Ports hat dieses Behavior" mehrdeutig. Der Command lehnt ihn ab, die Palette bietet ihn nicht mehr an |
| **Selbstaufruf = Fehler** | mit Namen im Log (`Behavior "X" runs itself`), statt still in die Tiefenbegrenzung zu laufen. Die Palette bietet das eigene Behavior gar nicht erst an |
| **`self`/`owner` bleiben** | der eingebettete Graph sieht dasselbe Objekt wie der Aufrufer — sonst waeren `Self`/`Owner` darin wertlos |
| **Toter Verweis ist still** | ein Node ohne gewaehltes Behavior (oder eines ohne Start-Node) tut nichts und **laesst den Fluss weiterlaufen**, statt den Lauf abzubrechen |
## Zwei Dinge, die der Bau erzwungen hat
**Eigener Pulse-Cache pro Aufruf.** Node-Ids sind nur *pro Graph* eindeutig. Liefe der
eingebettete Graph im Cache des Aufrufers, koennte er dessen Werte ueberschreiben. Der
Interpreter arbeitet deshalb auf **Frames** — der Aufruf schiebt einen neuen auf und nimmt ihn
danach wieder weg. Dafuer gibt es einen eigenen Test, der eine Id-Kollision erzwingt; ohne
Frames liefert er 99 statt 7.
**Ports aufraeumen ueber Graphgrenzen.** Einen Port umzubenennen oder zu entfernen betrifft
nicht nur den eigenen Graphen, sondern **jeden anderen, der das Behavior aufruft**. Beides
raeumt dort mit auf — und ein Rename nimmt den eingetippten Inline-Wert mit, sonst faellt er
still auf den Default zurueck. Das ist mir erst beim Gegenpruefen aufgefallen: der Test stand
auf 0 statt auf 6.
**Live-Highlight:** der Trace eines laufenden Behaviors deckt jetzt auch die Graphen ab, die es
als Node aufruft — sonst bliebe ein eingebettetes Behavior beim Zusehen dunkel.
## Belegt
**Zehn Unit-Tests** (`tests/core/nested-behavior.test.ts`) und **elf E2E-Checks** in Modul 19.
Der staerkste ist der erste: das aufrufende Behavior rechnet **nichts** selbst — die
Geschwindigkeit, mit der die Kiste laeuft, *ist* der zurueckgegebene Wert.
```
PASS a behavior used as a node runs, and what it returns is what drives the caller
– moved 200.0 px in ~1 s – 2 × 100 means the returned value arrived, 0 would mean nothing came back
PASS the calling node grows the ports the other behavior declares
PASS and it is drawn under that behavior's name, not as "Run behavior" – title="Double"
PASS adding an input declares it on the start node – [{"key":"in1",…},{"key":"in2",…}]
PASS and the node in the other graph grew that input without being touched
PASS undo removes it in both graphs – [{"key":"in1","kind":"number"}]
PASS picking a behavior in the palette drops in a node already set to it
– {"type":"RunBehavior","params":{"behavior":"nb-double"}}
```
`200.0` statt `100` beweist, dass der **verdoppelte** Wert ankam, nicht bloss irgendeiner;
`0` waere "nichts kam zurueck". Die drei Port-Checks in Folge sind der Nachweis, dass die
Portliste wirklich *abgeleitet* und nicht kopiert ist: deklariert wird im einen Graphen,
gewachsen ist der Node im anderen, ohne dass er angefasst wurde.
Gegenprobe gefahren: ohne die frische Variablenkopie und ohne die Selbstaufruf-Sperre fallen
zwei Unit-Tests; ohne getrennte Frames faellt der Kollisionstest (`expected 99 to be 7`) — der
war beim ersten Versuch faelschlich gruen und musste geschaerft werden, bevor er etwas taugte.
| | |
|---|---|
| volle E2E-Suite, remote | **ALL PASSED – 379 Checks**, 0 FAIL |
| `npm run check` lokal | gruen, **524 Tests** |
---
*Übernommen aus `todo-notes/done/nested-behavior.md` beim Umzug auf das Issue-System (2026-09-12).*
- **Angelegt:** 2026-09-09 · `64e034f` — Note down two more wishes
- **Abgeschlossen:** 2026-09-09 · `6702ff8` — Let a behavior be a node in another graph
- **Gemeldet von:** admin
admin
added the todo-note label 2026-09-12 15:03:52 +02:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Nested Behavior / Behavior als Node in Graph
Was damit gemeint ist?
=> Ein Behavior Asset als Node innerhalb eines Graph
Grundsätzlich soll so ein Behavior Node im Graf mit einem Execution Flow ausgestattet sein, sprich wir brauchen einen Start/End Node:
wenn alles verstanden, direkt loslegen, ansonsten warte ich auf rückfragen :)
Umgesetzt
Verstanden war alles — gebaut ist genau die beschriebene Form. Drei neue Node-Typen:
StartEndRun behaviorDeklariert wird im Inspector des Start-/End-Nodes:
+ Inputbzw.+ Output, Art waehlbar(Number, Boolean, Text, Object), Name direkt editierbar,
×zum Entfernen — dieselbe Bauformwie die Variablen eines Behaviors.
Der Node traegt den Namen des Behaviors, nicht "Run behavior", und die Palette listet
Behaviors ebenfalls namentlich. Ein Aufruf ist damit ein Griff statt Node einfuegen + Dropdown.
Die eine Entscheidung, die du mir ueberlassen hast
Ein eingebettetes Behavior hat kein Objekt in der Szene — also auch keinen Ort fuer seine
Variablen. Ich habe (A) reine Funktion gewaehlt: jeder Aufruf startet die Variablen auf den
Asset-Defaults, rein geht es ueber den Start-Node, raus ueber den End-Node.
Der Grund ist dein eigener naechster Schritt: du willst den Tetris-Graphen zerlegen. Dabei
sollen die Teile rechnen, waehrend der Zustand (
grid,pieceX, …) im Haupt-Behaviorbleibt — genau das, was du mit "kann man ueber input/output loesen" gemeint hast. (A) ist
ausserdem die konservative Wahl: daraus laesst sich spaeter Zustand machen, umgekehrt nicht,
ohne bestehende Graphen zu brechen.
Die Tuer ist nicht zu: Zustand gibt es weiterhin ueber ein Behavior-Objekt in der Szene
(
Object by name→Get/Set property) — der Weg, den dein Jump and Run fuer den Punktestandschon geht. Lokale Variablen im eingebetteten Graphen funktionieren als Zwischenspeicher
innerhalb eines Aufrufs unveraendert; sie werden nur am Ende verworfen.
Was ich selbst entschieden habe
Behavior "X" runs itself), statt still in die Tiefenbegrenzung zu laufen. Die Palette bietet das eigene Behavior gar nicht erst anself/ownerbleibenSelf/Ownerdarin wertlosZwei Dinge, die der Bau erzwungen hat
Eigener Pulse-Cache pro Aufruf. Node-Ids sind nur pro Graph eindeutig. Liefe der
eingebettete Graph im Cache des Aufrufers, koennte er dessen Werte ueberschreiben. Der
Interpreter arbeitet deshalb auf Frames — der Aufruf schiebt einen neuen auf und nimmt ihn
danach wieder weg. Dafuer gibt es einen eigenen Test, der eine Id-Kollision erzwingt; ohne
Frames liefert er 99 statt 7.
Ports aufraeumen ueber Graphgrenzen. Einen Port umzubenennen oder zu entfernen betrifft
nicht nur den eigenen Graphen, sondern jeden anderen, der das Behavior aufruft. Beides
raeumt dort mit auf — und ein Rename nimmt den eingetippten Inline-Wert mit, sonst faellt er
still auf den Default zurueck. Das ist mir erst beim Gegenpruefen aufgefallen: der Test stand
auf 0 statt auf 6.
Live-Highlight: der Trace eines laufenden Behaviors deckt jetzt auch die Graphen ab, die es
als Node aufruft — sonst bliebe ein eingebettetes Behavior beim Zusehen dunkel.
Belegt
Zehn Unit-Tests (
tests/core/nested-behavior.test.ts) und elf E2E-Checks in Modul 19.Der staerkste ist der erste: das aufrufende Behavior rechnet nichts selbst — die
Geschwindigkeit, mit der die Kiste laeuft, ist der zurueckgegebene Wert.
200.0statt100beweist, dass der verdoppelte Wert ankam, nicht bloss irgendeiner;0waere "nichts kam zurueck". Die drei Port-Checks in Folge sind der Nachweis, dass diePortliste wirklich abgeleitet und nicht kopiert ist: deklariert wird im einen Graphen,
gewachsen ist der Node im anderen, ohne dass er angefasst wurde.
Gegenprobe gefahren: ohne die frische Variablenkopie und ohne die Selbstaufruf-Sperre fallen
zwei Unit-Tests; ohne getrennte Frames faellt der Kollisionstest (
expected 99 to be 7) — derwar beim ersten Versuch faelschlich gruen und musste geschaerft werden, bevor er etwas taugte.
npm run checklokalÜbernommen aus
todo-notes/done/nested-behavior.mdbeim Umzug auf das Issue-System (2026-09-12).64e034f— Note down two more wishes6702ff8— Let a behavior be a node in another graph