Abgespalten aus #78 (Entscheidung 2026-09-13): die UV-Nodes kommen auf die Fragment-Seite (UV, Sample texture, Texture size, Time, Sin/Floor/Fract/Step). Echte Vertex-Nodes bleiben ein eigener Schritt, der erst nach vorn rückt, wenn ein konkreter Effekt Pixel außerhalb des Sprite-Rechtecks braucht.
Was der Vertex-Stage heute ist
viewport/symbols.ts: ein Unit-Quad mit vier Ecken (UNIT_QUAD, positions = uvs = 0..1, Pivot 0,5, Größe über Scale), geteilt von allen Sprites. Der Vertex-Stage (SPRITE_VERTEX in viewport/shaders.ts) macht Matrix-Transformation und reicht vTextureCoord/vColor durch.
Was Vertex-Nodes brächten — und was nicht
Mit dem Quad: vier Ecken bewegen — Scheren, Strecken, Versetzen. Das kann ein Behavior heute schon über width/height/Position.
Mit unterteiltem Gitter (eigene Geometrie pro Sprite statt des geteilten Quads): Welle, Jelly-Bounce, Fahne — Verformung, die über das Rechteck hinausgeht. Das ist der einzige echte Gewinn.
Nicht: Pixelgenaues (Pixelate, Scanlines, Verzerrung feiner als das Gitter) — bleibt Fragment-Sache. Die beiden Wege sind additiv.
Was zu bauen wäre
Zweiter Compiler-Rahmen: Vertex-Graph mit eigenen Eingängen (Position, UV, Time, Properties), eigenem Vertex output (Position-Versatz, UV-Versatz), Varyings zwischen den Stufen.
Gitter-Geometrie mit Unterteilungs-Parameter (pro Shader-Asset oder pro Sprite), Batching-Folgen messen (tools/perf-shaders.mjs).
Die Fragment-Nodes aus #78 bleiben unverändert gültig: UV liest vTextureCoord, was ein Vertex-Graph dort hineinschreibt, kommt automatisch an.
Beweis beim Schließen
Ein Sprite mit einem Wellen-Vertex-Shader zeigt Pixel außerhalb seines Rechtecks (Pixelmessung im Play), ein Sprite ohne bleibt byte-gleich; Performance-Tabelle mit Gitter gegen das Quad.
Abgespalten aus #78 (Entscheidung 2026-09-13): die UV-Nodes kommen auf die **Fragment-Seite** (`UV`, `Sample texture`, `Texture size`, `Time`, `Sin`/`Floor`/`Fract`/`Step`). Echte Vertex-Nodes bleiben ein eigener Schritt, der erst nach vorn rückt, wenn ein konkreter Effekt **Pixel außerhalb des Sprite-Rechtecks** braucht.
## Was der Vertex-Stage heute ist
`viewport/symbols.ts`: ein **Unit-Quad mit vier Ecken** (`UNIT_QUAD`, positions = uvs = 0..1, Pivot 0,5, Größe über Scale), geteilt von allen Sprites. Der Vertex-Stage (`SPRITE_VERTEX` in `viewport/shaders.ts`) macht Matrix-Transformation und reicht `vTextureCoord`/`vColor` durch.
## Was Vertex-Nodes brächten — und was nicht
- Mit dem Quad: vier Ecken bewegen — Scheren, Strecken, Versetzen. Das kann ein Behavior heute schon über `width`/`height`/Position.
- Mit **unterteiltem Gitter** (eigene Geometrie pro Sprite statt des geteilten Quads): Welle, Jelly-Bounce, Fahne — Verformung, die über das Rechteck hinausgeht. Das ist der einzige echte Gewinn.
- Nicht: Pixelgenaues (Pixelate, Scanlines, Verzerrung feiner als das Gitter) — bleibt Fragment-Sache. Die beiden Wege sind additiv.
## Was zu bauen wäre
1. Zweiter Compiler-Rahmen: Vertex-Graph mit eigenen Eingängen (`Position`, `UV`, `Time`, Properties), eigenem `Vertex output` (Position-Versatz, UV-Versatz), Varyings zwischen den Stufen.
2. Gitter-Geometrie mit Unterteilungs-Parameter (pro Shader-Asset oder pro Sprite), Batching-Folgen messen (`tools/perf-shaders.mjs`).
3. Die Fragment-Nodes aus #78 bleiben unverändert gültig: `UV` liest `vTextureCoord`, was ein Vertex-Graph dort hineinschreibt, kommt automatisch an.
## Beweis beim Schließen
Ein Sprite mit einem Wellen-Vertex-Shader zeigt Pixel **außerhalb** seines Rechtecks (Pixelmessung im Play), ein Sprite ohne bleibt byte-gleich; Performance-Tabelle mit Gitter gegen das Quad.
Antwort auf „Wo wird definiert, ob es ein Quad ist oder ein Gitter mit einer gewünschten Density“
Heute nirgends. Alle Sprites teilen sich ein Quad mit vier Ecken (UNIT_QUAD in src/viewport/symbols.ts). Seit #69 bekommt ein Sprite zwar ein eigenes Quad, sobald sein Shader ein Padding hat, es bleibt aber bei vier Ecken. Der Issue-Text ließ den Punkt offen („pro Shader-Asset oder pro Sprite“).
Entschieden (2026-10-02):
Es gibt keinen eigenen Schalter „Quad oder Gitter“. Es gibt eine Zahl Subdivisions, und 1 heißt Quad.
Die Zahl sitzt am neuen Vertex output-Node, so wie Edge und Padding am Output sitzen. Sie gilt für jedes Objekt, das den Shader trägt.
Ein Shader ohne Vertex output-Node bleibt beim geteilten Quad und kostet nichts extra.
Vorschlag, noch nicht bestätigt:
Die Zahl zählt Felder je Achse: 8 heißt 8 mal 8 Felder, also 81 Ecken. Deckel bei 64.
Warum am Shader und nicht am Sprite:
Wie fein das Gitter sein muss, hängt am Effekt, und den kennt der Shader.
Am Sprite wäre es eine Zeile mehr an jedem Objekt, die ohne Vertex-Shader nichts tut.
Nachteil: Ein sehr großes und ein sehr kleines Sprite mit demselben Shader bekommen gleich viele Ecken.
Gemessen ist dazu noch nichts. Was ein Gitter bei vielen Sprites kostet, zeigt erst die Performance-Tabelle aus „Beweis beim Schließen“.
**Antwort auf „Wo wird definiert, ob es ein Quad ist oder ein Gitter mit einer gewünschten Density“**
Heute nirgends. Alle Sprites teilen sich ein Quad mit vier Ecken (`UNIT_QUAD` in `src/viewport/symbols.ts`). Seit #69 bekommt ein Sprite zwar ein eigenes Quad, sobald sein Shader ein `Padding` hat, es bleibt aber bei vier Ecken. Der Issue-Text ließ den Punkt offen („pro Shader-Asset oder pro Sprite“).
**Entschieden (2026-10-02):**
- Es gibt keinen eigenen Schalter „Quad oder Gitter“. Es gibt eine Zahl `Subdivisions`, und 1 heißt Quad.
- Die Zahl sitzt am neuen `Vertex output`-Node, so wie `Edge` und `Padding` am `Output` sitzen. Sie gilt für jedes Objekt, das den Shader trägt.
- Ein Shader ohne `Vertex output`-Node bleibt beim geteilten Quad und kostet nichts extra.
**Vorschlag, noch nicht bestätigt:**
- Die Zahl zählt Felder je Achse: 8 heißt 8 mal 8 Felder, also 81 Ecken. Deckel bei 64.
**Warum am Shader und nicht am Sprite:**
- Wie fein das Gitter sein muss, hängt am Effekt, und den kennt der Shader.
- Am Sprite wäre es eine Zeile mehr an jedem Objekt, die ohne Vertex-Shader nichts tut.
- Nachteil: Ein sehr großes und ein sehr kleines Sprite mit demselben Shader bekommen gleich viele Ecken.
Gemessen ist dazu noch nichts. Was ein Gitter bei vielen Sprites kostet, zeigt erst die Performance-Tabelle aus „Beweis beim Schließen“.
Gebaut. Die Frage aus dem Kommentar oben (wo wird Quad oder Gitter definiert) ist in Kommentar 2959 beantwortet: Es gibt keinen Schalter, nur die Zahl Subdivisions am neuen Node Vertex output.
Was sich ändert
Node Vertex output im Shader-Graph, höchstens einer je Graph. Die Eingänge x und y verschieben jede Ecke des Gitters, in Pixeln des Bildes (Antwort 1). Die UV bleiben an der Ecke, das Bild verformt sich also mit. Einen UV-Versatz gibt es nicht, dafür ist Sample texture im Fragment da.
Subdivisions am Node: Felder je Achse, 1 bis 64, Standard 8 (Antwort 4). 1 ist das Quad. Ein Shader ohne den Node bleibt beim geteilten Quad aller Sprites.
Speisen dürfen ihnUV, Time, Property, Number und die Rechen-Nodes (Antwort 2). Ein Node darf beide Outputs speisen.
Nicht erlaubt sind Texture color, Texture alpha, Sample texture und Color. Der Node meldet „Not available per corner: …“, und der Shader kompiliert nicht.
Träger (Antwort 3): Sprites, Texte und die Vorschau im Shader-Tab. 9-Slice und Partikel zeichnen so, als gäbe es den Node nicht.
Anklicken, Auswahlrahmen, Größe und Collider bleiben beim Rechteck ohne Verformung.
Was ich selbst festgelegt habe
Texture size ist am Vertex output ebenfalls gesperrt. Der Node stand in der Auswahl weder bei den erlaubten noch bei den gesperrten.
Ein Objekt mit Vertex output wird nie ausgeblendet, auch wenn sein Rechteck außerhalb des Bildes liegt, wie bei Padding (#69).
Mit Padding deckt das Gitter auch den Rand ab.
Ein unverbundener Vertex output kostet trotzdem das Gitter, weil Subdivisions auf 8 steht.
Performance (stein2, Intel HD 630, Bilder je Sekunde)
Sprites
200
400
800
1600
ohne Shader
60
60
60
41
Shader ohne Vertex output
60
60
58
36
Subdivisions 8
59
58
46
27
Subdivisions 32
54
57
41
23
Bis 400 Sprites fällt ein Gitter kaum auf, bei 800 kostet es rund ein Viertel der Bildrate.
Das ist ein Lauf je Zeile, nicht drei. Der Wert 54 bei 200 Sprites liegt unter dem bei 400, einzelne Werte sind also nur auf ein paar Bilder genau.
Jedes Sprite hält dabei sein eigenes Gitter. Gleiche Gitter zu teilen wäre eine mögliche Verbesserung, gebaut ist sie nicht.
Nachmessen: tools/perf-shaders.mjs mit GM_PERF_SUBDIVISIONS=8.
Under the hood
ShaderVertexOutput, subdivisionsOf und das Merkmal perPixel in src/core/shader/nodes.ts. Der Compiler startet einen zweiten Durchlauf vom Vertex output und gibt vertex (Code und Subdivisions) mit zurück.
gridQuad in src/viewport/quadPadding.ts (ohne Pixi): dasselbe Rechteck in Felder geschnitten, Positionen und UV sind wie am Quad dieselben Zahlen.
src/viewport/shaders.ts setzt den Versatz in den Vertex-Stage. symbols.ts wählt je Sprite Quad, Rand-Quad oder Gitter. Ein 9-Slice-Sprite bekommt den Vertex-Teil nicht.
WorldViewport nimmt Träger eines Shaders mit Vertex output vom Ausblenden aus.
Ein fester Versatz von 16 verschiebt das Bild um ein halbes Sprite.
Ein Schnitt auf v biegt mit 8 Feldern nur die untere Hälfte, mit 1 Feld schert das ganze Bild.
Texture alpha wird am Node abgelehnt.
Ein Text steht 6 Einheiten weiter rechts.
Die e2e-Summe 1699 ist gerechnet (1695 + 4). Volle Suite und Smokes liefen nicht.
Das Gate lief am Ende des Baus, vor dem Commit habe ich es nicht noch einmal gefahren.
Gegenproben habe ich keine gefahren, Screenshots keine angesehen.
Nicht geprüft:
die Vorschau im Shader-Tab
Time am Vertex output im Browser (nur Unit-Test)
gespiegelte Sprites
die Kombination mit Padding im Browser
alles nach dem Build
Nicht dabei
9-Slice und Partikel (Antwort 3).
Ein UV-Versatz am Vertex output, wie ihn der Issue-Text nennt (Antwort 1).
Ein Node Position, und Bildlesen im Vertex-Teil (Antwort 2).
Commit: 4716726. Wiki: Shaders (neuer Abschnitt „Moving the corners“, Tabelle, Node-Zeile) und Development (Summe), 8a9c36f.
Gebaut. Die Frage aus dem Kommentar oben (wo wird Quad oder Gitter definiert) ist in Kommentar 2959 beantwortet: Es gibt keinen Schalter, nur die Zahl *Subdivisions* am neuen Node `Vertex output`.
## Was sich ändert
- **Node `Vertex output`** im Shader-Graph, höchstens einer je Graph. Die Eingänge `x` und `y` verschieben jede Ecke des Gitters, in Pixeln des Bildes (Antwort 1). Die UV bleiben an der Ecke, das Bild verformt sich also mit. Einen UV-Versatz gibt es nicht, dafür ist `Sample texture` im Fragment da.
- **Subdivisions** am Node: Felder je Achse, 1 bis 64, Standard 8 (Antwort 4). 1 ist das Quad. Ein Shader ohne den Node bleibt beim geteilten Quad aller Sprites.
- **Speisen dürfen ihn** `UV`, `Time`, `Property`, `Number` und die Rechen-Nodes (Antwort 2). Ein Node darf beide Outputs speisen.
- **Nicht erlaubt** sind `Texture color`, `Texture alpha`, `Sample texture` und `Color`. Der Node meldet „Not available per corner: …“, und der Shader kompiliert nicht.
- **Träger** (Antwort 3): Sprites, Texte und die Vorschau im Shader-Tab. 9-Slice und Partikel zeichnen so, als gäbe es den Node nicht.
- **Anklicken, Auswahlrahmen, Größe und Collider** bleiben beim Rechteck ohne Verformung.
## Was ich selbst festgelegt habe
- **`Texture size` ist am `Vertex output` ebenfalls gesperrt.** Der Node stand in der Auswahl weder bei den erlaubten noch bei den gesperrten.
- **Ein Objekt mit `Vertex output` wird nie ausgeblendet**, auch wenn sein Rechteck außerhalb des Bildes liegt, wie bei `Padding` (#69).
- **Mit `Padding` deckt das Gitter auch den Rand ab.**
- **Ein unverbundener `Vertex output` kostet trotzdem das Gitter**, weil *Subdivisions* auf 8 steht.
## Performance (stein2, Intel HD 630, Bilder je Sekunde)
| Sprites | 200 | 400 | 800 | 1600 |
| --- | --- | --- | --- | --- |
| ohne Shader | 60 | 60 | 60 | 41 |
| Shader ohne `Vertex output` | 60 | 60 | 58 | 36 |
| Subdivisions 8 | 59 | 58 | 46 | 27 |
| Subdivisions 32 | 54 | 57 | 41 | 23 |
- Bis 400 Sprites fällt ein Gitter kaum auf, bei 800 kostet es rund ein Viertel der Bildrate.
- **Das ist ein Lauf je Zeile, nicht drei.** Der Wert 54 bei 200 Sprites liegt unter dem bei 400, einzelne Werte sind also nur auf ein paar Bilder genau.
- Jedes Sprite hält dabei sein eigenes Gitter. Gleiche Gitter zu teilen wäre eine mögliche Verbesserung, gebaut ist sie nicht.
- Nachmessen: `tools/perf-shaders.mjs` mit `GM_PERF_SUBDIVISIONS=8`.
## Under the hood
- `ShaderVertexOutput`, `subdivisionsOf` und das Merkmal `perPixel` in `src/core/shader/nodes.ts`. Der Compiler startet einen zweiten Durchlauf vom `Vertex output` und gibt `vertex` (Code und Subdivisions) mit zurück.
- `gridQuad` in `src/viewport/quadPadding.ts` (ohne Pixi): dasselbe Rechteck in Felder geschnitten, Positionen und UV sind wie am Quad dieselben Zahlen.
- `src/viewport/shaders.ts` setzt den Versatz in den Vertex-Stage. `symbols.ts` wählt je Sprite Quad, Rand-Quad oder Gitter. Ein 9-Slice-Sprite bekommt den Vertex-Teil nicht.
- `WorldViewport` nimmt Träger eines Shaders mit `Vertex output` vom Ausblenden aus.
## Tests (auf `melektaus-atx`)
```
Gate → 220 Files, 3416 Tests, CHECK EXIT 0 (3401 + 15)
e2e 28,30 → ALL PASSED – 110 checks (106 + 4)
```
- **15 neue Unit-Tests** für Compiler und Gitter.
- **Vier neue e2e-Checks:**
- Ein fester Versatz von 16 verschiebt das Bild um ein halbes Sprite.
- Ein Schnitt auf `v` biegt mit 8 Feldern nur die untere Hälfte, mit 1 Feld schert das ganze Bild.
- `Texture alpha` wird am Node abgelehnt.
- Ein Text steht 6 Einheiten weiter rechts.
- Die e2e-Summe **1699** ist gerechnet (1695 + 4). Volle Suite und Smokes liefen nicht.
- Das Gate lief am Ende des Baus, vor dem Commit habe ich es nicht noch einmal gefahren.
- Gegenproben habe ich keine gefahren, Screenshots keine angesehen.
- **Nicht geprüft:**
- die Vorschau im Shader-Tab
- `Time` am `Vertex output` im Browser (nur Unit-Test)
- gespiegelte Sprites
- die Kombination mit `Padding` im Browser
- alles nach dem Build
## Nicht dabei
- 9-Slice und Partikel (Antwort 3).
- Ein UV-Versatz am `Vertex output`, wie ihn der Issue-Text nennt (Antwort 1).
- Ein Node `Position`, und Bildlesen im Vertex-Teil (Antwort 2).
Commit: `4716726`. Wiki: *Shaders* (neuer Abschnitt „Moving the corners“, Tabelle, Node-Zeile) und *Development* (Summe), `8a9c36f`.
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.
Abgespalten aus #78 (Entscheidung 2026-09-13): die UV-Nodes kommen auf die Fragment-Seite (
UV,Sample texture,Texture size,Time,Sin/Floor/Fract/Step). Echte Vertex-Nodes bleiben ein eigener Schritt, der erst nach vorn rückt, wenn ein konkreter Effekt Pixel außerhalb des Sprite-Rechtecks braucht.Was der Vertex-Stage heute ist
viewport/symbols.ts: ein Unit-Quad mit vier Ecken (UNIT_QUAD, positions = uvs = 0..1, Pivot 0,5, Größe über Scale), geteilt von allen Sprites. Der Vertex-Stage (SPRITE_VERTEXinviewport/shaders.ts) macht Matrix-Transformation und reichtvTextureCoord/vColordurch.Was Vertex-Nodes brächten — und was nicht
width/height/Position.Was zu bauen wäre
Position,UV,Time, Properties), eigenemVertex output(Position-Versatz, UV-Versatz), Varyings zwischen den Stufen.tools/perf-shaders.mjs).UVliestvTextureCoord, was ein Vertex-Graph dort hineinschreibt, kommt automatisch an.Beweis beim Schließen
Ein Sprite mit einem Wellen-Vertex-Shader zeigt Pixel außerhalb seines Rechtecks (Pixelmessung im Play), ein Sprite ohne bleibt byte-gleich; Performance-Tabelle mit Gitter gegen das Quad.
Wo wird definiert ob es ein Quad ist oder ein Gitter mit einer gewünschten Density.
Antwort auf „Wo wird definiert, ob es ein Quad ist oder ein Gitter mit einer gewünschten Density“
Heute nirgends. Alle Sprites teilen sich ein Quad mit vier Ecken (
UNIT_QUADinsrc/viewport/symbols.ts). Seit #69 bekommt ein Sprite zwar ein eigenes Quad, sobald sein Shader einPaddinghat, es bleibt aber bei vier Ecken. Der Issue-Text ließ den Punkt offen („pro Shader-Asset oder pro Sprite“).Entschieden (2026-10-02):
Subdivisions, und 1 heißt Quad.Vertex output-Node, so wieEdgeundPaddingamOutputsitzen. Sie gilt für jedes Objekt, das den Shader trägt.Vertex output-Node bleibt beim geteilten Quad und kostet nichts extra.Vorschlag, noch nicht bestätigt:
Warum am Shader und nicht am Sprite:
Gemessen ist dazu noch nichts. Was ein Gitter bei vielen Sprites kostet, zeigt erst die Performance-Tabelle aus „Beweis beim Schließen“.
Gebaut. Die Frage aus dem Kommentar oben (wo wird Quad oder Gitter definiert) ist in Kommentar 2959 beantwortet: Es gibt keinen Schalter, nur die Zahl Subdivisions am neuen Node
Vertex output.Was sich ändert
Vertex outputim Shader-Graph, höchstens einer je Graph. Die Eingängexundyverschieben jede Ecke des Gitters, in Pixeln des Bildes (Antwort 1). Die UV bleiben an der Ecke, das Bild verformt sich also mit. Einen UV-Versatz gibt es nicht, dafür istSample textureim Fragment da.UV,Time,Property,Numberund die Rechen-Nodes (Antwort 2). Ein Node darf beide Outputs speisen.Texture color,Texture alpha,Sample textureundColor. Der Node meldet „Not available per corner: …“, und der Shader kompiliert nicht.Was ich selbst festgelegt habe
Texture sizeist amVertex outputebenfalls gesperrt. Der Node stand in der Auswahl weder bei den erlaubten noch bei den gesperrten.Vertex outputwird nie ausgeblendet, auch wenn sein Rechteck außerhalb des Bildes liegt, wie beiPadding(#69).Paddingdeckt das Gitter auch den Rand ab.Vertex outputkostet trotzdem das Gitter, weil Subdivisions auf 8 steht.Performance (stein2, Intel HD 630, Bilder je Sekunde)
Vertex outputtools/perf-shaders.mjsmitGM_PERF_SUBDIVISIONS=8.Under the hood
ShaderVertexOutput,subdivisionsOfund das MerkmalperPixelinsrc/core/shader/nodes.ts. Der Compiler startet einen zweiten Durchlauf vomVertex outputund gibtvertex(Code und Subdivisions) mit zurück.gridQuadinsrc/viewport/quadPadding.ts(ohne Pixi): dasselbe Rechteck in Felder geschnitten, Positionen und UV sind wie am Quad dieselben Zahlen.src/viewport/shaders.tssetzt den Versatz in den Vertex-Stage.symbols.tswählt je Sprite Quad, Rand-Quad oder Gitter. Ein 9-Slice-Sprite bekommt den Vertex-Teil nicht.WorldViewportnimmt Träger eines Shaders mitVertex outputvom Ausblenden aus.Tests (auf
melektaus-atx)vbiegt mit 8 Feldern nur die untere Hälfte, mit 1 Feld schert das ganze Bild.Texture alphawird am Node abgelehnt.TimeamVertex outputim Browser (nur Unit-Test)Paddingim BrowserNicht dabei
Vertex output, wie ihn der Issue-Text nennt (Antwort 1).Position, und Bildlesen im Vertex-Teil (Antwort 2).Commit:
4716726. Wiki: Shaders (neuer Abschnitt „Moving the corners“, Tabelle, Node-Zeile) und Development (Summe),8a9c36f.