frontend: Treppe für aufeinanderfolgende optionale Endknoten
Im horizontalen Fächer kostet jedes optionale Geschwister eine eigene Spalte — Breite für gerade das, was am entbehrlichsten ist. Zwei oder mehr aufeinanderfolgende optionale ENDknoten werden deshalb als Kaskade gestapelt: erste Stufe am Stiel von oben wie ein gewöhnliches Kind, jede weitere eine Stufe tiefer und weiter rechts, an einem gestrichelten Winkel, der an der linken Kante der vorigen Stufe herabfällt und waagerecht in ihren Kreis einbiegt. Verworfen: die naheliegendere SENKRECHTE Spalte unter einem Anschlusspunkt. Schmaler und in einem Bruchteil der Zeit gebaut — sähe aber fast genau aus wie eine any-of-Gruppe (gestapelte Spalte an gestrichelter Leiste), unterschieden nur durch Tinte statt Grau. Genau diese Verwechslung zu vermeiden ist der Zweck von Kreis und Farbgebung. Ebenfalls verworfen: eine echte Diagonale — Rahmenkanten sind achsenparallel, sie bräuchte die SVG-Ebene und wäre eine zweite Zeichenebene neben allen anderen Linien, nachzuführen bei jedem Rendern, Moduswechsel und Zoom. Rechte Winkel geben denselben Kaskaden-Eindruck im vorhandenen Mechanismus. - Nur Endknoten: Der Platzgewinn entsteht gerade daraus, dass kein Teilbaum mitgestapelt wird — ein optionaler Knoten MIT Kindern spart nichts und behält seine Spalte. Technisch dasselbe: die Stufengeometrie setzt Zellenhöhe == Knotenhöhe voraus. Geprüft wird genau das (ein Element-Kind, und das ist der Knoten) — schließt auch den Geister-Knoten aus. - Gruppiert wird in app.js, nicht im Renderer. Die DOM-Ebene gibt es semantisch nicht und müsste in den drei übrigen Anordnungen (vertikal, kompakt, all-of unter any-of) wieder neutralisiert werden, jede mit hand-getunter Geometrie. `display:contents` löst das nicht: richtet die Boxen, aber die >-Selektoren jener Regeln greifen weiter auf dem DOM. applyOptStairs() baut die Gruppe nur im Fächer und löst sie beim Moduswechsel auf — dieselbe Kategorie wie alignStems() und drawCheapPath(); SPEC §9 bleibt für den RENDERER wörtlich wahr, Lese- und Fokusreihenfolge unberührt. - Der Export folgt der Kaskade. Erste Fassung reihte alle Stufen flach als Kinder ein und ließ den Export selbst routen — die Linie zur dritten Stufe lief dann HINTER der zweiten hindurch und las sich wie eine Eltern-Kind- Beziehung. Keine Schönheitsfrage, sondern eine falsche Aussage über die Struktur. Jetzt hängt nur die erste Stufe an der Sammelleiste. Nicht durch Tests gedeckt: applyOptStairs() arbeitet auf dem DOM, und für app.js gibt es keine Testumgebung (die Suite prüft die headless-Module). Verifiziert im Browser: Kaskade in horizontal (drei Stufen, Winkel treffen die Kreise), Moduswechsel horizontal↔kompakt↔vertikal mehrfach hin und zurück — Gruppe entsteht und löst sich rückstandsfrei auf, Knotenzahl (9) und Dokumentordnung in allen drei Modi unverändert, keine übrig gebliebenen --i-Variablen. SVG-Export gerendert geprüft: drei Kreise, Winkelkette statt kreuzender Linien. Vitest 60/60 (Renderer unverändert). Im mitgelieferten Werkbaum-Plan stehen die beiden Editor-Zugaben jetzt nebeneinander und zeigen die Treppe. Reihenfolgeänderung ist für „Was ist neu?" folgenlos — die Knoten-Identität ist der Label-Pfad (D28), test-abgedeckt. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
091e8849d8
commit
56c18cb8cb
@@ -850,3 +850,57 @@ Rückfallwert 50 % hält alle übrigen Zellen ohne Messung richtig, und die
|
||||
transponierten Modi setzen `left`/`right` ohnehin fest und bleiben unberührt.
|
||||
Gemessen wird — wie in `drawCheapPath()` — durch `zoom` zurückgerechnet, sodass
|
||||
der Wert beim Zoomen gültig bleibt.
|
||||
|
||||
**Nachtrag 3 — Treppe für mehrere optionale Endknoten.** Im horizontalen Fächer
|
||||
kostet jedes optionale Geschwister eine eigene Spalte — Breite für gerade das,
|
||||
was am entbehrlichsten ist. Aufeinanderfolgende optionale Endknoten werden
|
||||
deshalb als **Kaskade** gestapelt (Nutzerwunsch: „mehrere optionale Knoten in
|
||||
einer diagonalen Linie an eine Anschlussstelle").
|
||||
|
||||
Verworfen wurde die naheliegendere **senkrechte Spalte** unter einem
|
||||
Anschlusspunkt: Sie wäre schmaler und in einem Bruchteil der Zeit gebaut, sähe
|
||||
aber fast genau aus wie eine **any-of-Gruppe** (gestapelte Spalte an
|
||||
gestrichelter Leiste), unterschieden nur durch Tinte statt Grau. Genau diese
|
||||
Verwechslung zu vermeiden ist der Zweck von Kreis und Farbgebung. Die Treppe
|
||||
kauft Eindeutigkeit für etwas Breite — schon die Form ist eine andere.
|
||||
|
||||
Ebenfalls verworfen: eine **echte** Diagonale. Rahmenkanten sind achsenparallel;
|
||||
sie bräuchte die SVG-Ebene (die es für den Pfad-Spline gibt) und wäre damit eine
|
||||
**zweite Zeichenebene** neben allen anderen Linien, nachzuführen bei jedem
|
||||
Rendern, Moduswechsel und Zoom. Der gestufte Anschluss aus rechten Winkeln gibt
|
||||
denselben Kaskaden-Eindruck im vorhandenen Mechanismus.
|
||||
|
||||
**Nur Endknoten.** Der Platzgewinn entsteht gerade daraus, dass kein Teilbaum
|
||||
mitgestapelt werden muss — ein optionaler Knoten *mit* Kindern spart in der
|
||||
Treppe nichts und behält seine Spalte. Technisch kommt dasselbe heraus: Die
|
||||
Stufengeometrie rechnet mit einem festen Abstand von Knotenunterkante zur
|
||||
nächsten Stufe und setzt deshalb voraus, dass die Zelle so hoch ist wie ihr
|
||||
Knoten (kein Teilbaum, kein Geister-Knoten). Geprüft wird genau das: das `<li>`
|
||||
hat exakt ein Element-Kind, und das ist der Knoten.
|
||||
|
||||
**Gruppiert wird in app.js, nicht im Renderer.** Die Gruppierung
|
||||
(`li.opt-group > ul.opt-stair`, Stufennummer als `--i`) ist reine Darstellung.
|
||||
Im Renderer hätte sie eine DOM-Ebene erzeugt, die es semantisch nicht gibt —
|
||||
und die in den **drei übrigen Anordnungen** (vertikal, kompakt, all-of unter
|
||||
any-of) wieder hätte neutralisiert werden müssen, jede mit hand-getunter
|
||||
Geometrie. `display:contents` löst das nicht: Es richtet die Boxen, aber die
|
||||
`>`-Selektoren jener Regeln greifen weiter auf dem DOM und passen dann nicht
|
||||
mehr. `applyOptStairs()` baut die Gruppe deshalb nur im Fächer und löst sie beim
|
||||
Moduswechsel wieder auf — dieselbe Kategorie wie `alignStems()` und
|
||||
`drawCheapPath()`, und SPEC §9 („der Modus ändert nur die Anordnung") bleibt für
|
||||
den **Renderer** wörtlich wahr. Lese- und Fokusreihenfolge bleiben unberührt,
|
||||
weil nur umgehängt und nichts umsortiert wird.
|
||||
|
||||
**Der Export folgt der Kaskade.** Erste Fassung reihte alle Stufen flach als
|
||||
Kinder ein und ließ den Export selbst routen (er zieht Linien ohnehin unabhängig
|
||||
vom Darstellungsmodus neu). Ergebnis: Die Linie zur dritten Stufe lief **hinter
|
||||
der zweiten hindurch** und las sich wie eine Eltern-Kind-Beziehung — keine
|
||||
Schönheitsfrage, sondern eine falsche Aussage über die Struktur. Jetzt hängt nur
|
||||
die **erste** Stufe an der Sammelleiste, die übrigen bekommen denselben Winkel
|
||||
wie am Bildschirm.
|
||||
|
||||
**Nicht durch Tests gedeckt:** `applyOptStairs()` arbeitet auf dem DOM, und für
|
||||
`app.js` gibt es keine Testumgebung (die Vitest-Suite prüft die headless-Module).
|
||||
Geprüft wurde im Browser — auch der Moduswechsel hin und zurück, mehrfach: Die
|
||||
Gruppe entsteht und löst sich rückstandsfrei auf, Knotenzahl und Dokumentordnung
|
||||
bleiben in allen drei Modi gleich.
|
||||
|
||||
Reference in New Issue
Block a user