feat: Cursor-Zeile hebt sich aus der Ebene, plus Puls beim Zeilenwechsel

Die Hervorhebung der Cursor-Zeile (D25) war zu leise. Sie benutzte denselben
Kanal, den schon jeder Knoten belegt — jeder Status hat einen Rahmen (SPEC §4);
ein weiterer Ring darunter ist ein Unterschied im Grad, nicht in der Art.

Dazu kommt jetzt Tiefe: Schlagschatten + scale(1.04). Der einzige Kanal, den im
Diagramm noch nichts belegt, also ohne Konflikt mit einer Farbcodierung. Um die
Mitte skaliert, damit die Knotenmitte erhalten bleibt (alignStems, Stationspunkte
messen genau die — nachgemessen dx=dy=0). Beim Zeilenwechsel meldet sie sich
zusätzlich mit einem einmaligen Puls (Hüpfer + auslaufender Ring auf ::after);
kein Blinken, prefers-reduced-motion schaltet ihn ab.

Behoben dabei: Die Pfad-Inversion (D18) blasste den Ring auf 0,32 aus — die
Ausnahme, die .fresh (D28) und .focusmark (D32) längst haben, fehlte für
.current als einziger, obwohl der Fall der häufigste ist (Umschalter default an,
im Beispiel 7 von 18 Knoten betroffen).

diagramToSvg() muss die Erhebung abschalten (Klasse `exporting`): Der Export
zieht die Live-Geometrie per getBoundingClientRect() nach, anders als beim
box-shadow schlägt eine Vergrößerung dort durch. Nachgemessen: 155,6 statt
161,9 px. Im Druck fällt beides ebenso weg.

SPEC §9 und D25 (Nachtrag) nachgezogen; llms.md unberührt (Notation, keine
Editor-UI, D43).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
mhoennig
2026-08-23 07:24:04 +02:00
co-authored by Claude Fable 5
parent 618149a36d
commit 099ee87bc1
5 changed files with 190 additions and 17 deletions
+16 -1
View File
@@ -211,7 +211,22 @@ verworfene Elemente. Quelle sind ES-Module unter `src/`; `index.html` ist der
`syncCaret()` setzt die Klasse `current` auf den Knoten der Cursor-Zeile;
`render()` stellt sie nach jedem Neubau wieder her (ohne zu scrollen). Die
CSS-Regel braucht den `#out`-Präfix (`ul.or .node{box-shadow:none}` ist
spezifischer). Auffindbarkeit: `setAltMode()` setzt bei gedrückter Alt-Taste
spezifischer) **und** — wie `.fresh`/`.focusmark` — die Ausnahme
`.cheap-on .node:not(.cheap).current{opacity:1;filter:none}`; sie fehlte lange
als einzige, obwohl der Fall der häufigste ist (Pfad-Umschalter default an,
jeder `+`-Knoten und jede nicht gewählte Alternative betroffen).
Zum Ring kommen **Schlagschatten + `scale(1.04)`** (D25-Nachtrag): Tiefe ist der
einzige noch freie Kanal. Um die **Mitte** skalieren ist Bedingung — `alignStems()`
und die Stationspunkte messen die Knotenmitte, die dadurch unverändert bleibt.
**`diagramToSvg()` muss die Erhebung abschalten** (Klasse `exporting` an `#out`,
am Ende wieder ab): Der Export zieht die Live-Geometrie per
`getBoundingClientRect()` nach, anders als beim `box-shadow` schlägt die
Vergrößerung dort durch. Der **Puls** (`pulse`, Hüpfer + Ring auf dem freien
`.node::after`) wird nur bei geändertem `caretLine` gesetzt — sonst pulst es bei
jedem Tastendruck — und braucht das Lesen von `offsetWidth` als Neustart-Trick,
weil dieselbe Aufgabe die Klasse vorher entfernt. Nicht über `box-shadow`
animieren: Das löschte für die Dauer des Pulses den gelben bzw. Petrol-Kranz der
Kombinationen. Auffindbarkeit: `setAltMode()` setzt bei gedrückter Alt-Taste
die Klasse `alt` an `#out` (Cursor + Ring am Knoten unter dem Zeiger) — der
`blur`-Handler ist Pflicht, sonst bleibt der Modus nach Alt+Tab hängen; dazu
`jumpHint` im Knoten-Tooltip und `hint_jump` als letzte Zeile der Legende.