docs: T5 Bewegungs-Sprache (Spec §17) und Plan-Review 2026-10-16
Spec: Zweck, Stufen Voll/Dezent/Aus über useEffectiveMotionLevel, Tokens aus dem, was Beute und CSS heute nutzen (eine Quelle in lib/motion/tokens.ts), Regeln je Muster, was nie animiert, Performance-Regeln, Abnahme; neue Inhaber-Frage 4. Plan: 22 Korrekturen gegen den aktuellen Code (u. a. 31 statt 17 Checkbox-Stellen, fehlende AREAS, Lebenslinie unter der Beute-Karte, Fokusring auf der Holo-Bühne), neue Tasks A11 (Bewegungs-Sprache durchsetzen) und A12 (Beute-Bühne und Sonne-Modus). Refs #26 Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
362ae7466b
commit
1806255211
2 files changed
+394
-8
No files matched your search
@@ -1,6 +1,6 @@
|
||||
# T5 Optik mit eigener Handschrift — Design
|
||||
|
||||
Stand: 2026-10-14 · Betrifft: ApiCore-Frontend (plus ein kleiner Zusatz am Backend-Endpunkt `GET /autopilot/today`) · Teilprojekt T5 aus `docs/superpowers/specs/2026-10-12-plattform-rueckgrat-und-fahrplan-design.md` §10
|
||||
Stand: 2026-10-14, Nachtrag 2026-10-16 (§17 Bewegungs-Sprache, Frage 4 in §16; Anlass Beute-Spec §12.4, Issue #26) · Betrifft: ApiCore-Frontend (plus ein kleiner Zusatz am Backend-Endpunkt `GET /autopilot/today`) · Teilprojekt T5 aus `docs/superpowers/specs/2026-10-12-plattform-rueckgrat-und-fahrplan-design.md` §10
|
||||
|
||||
## 1. Ziel
|
||||
|
||||
@@ -47,7 +47,7 @@ Technisch heißt das:
|
||||
| Randstärke der Zelle | Wie im Fahrplan zeigt die Randstärke die Tage seit der letzten Durchsicht, aber in **drei Stufen** statt stufenlos: dünn = frisch, mittel = bald fällig, dick und gestrichelt = fällig oder nie durchgesehen. Stufenlose Strichstärken sind draußen nicht unterscheidbar. Die genaue Zahl steht im Namen der Zelle und in der Liste. |
|
||||
| Lebenslinie und Rad: Daten | Nur vorhandene Endpunkte (Volk, Durchsichten, Varroa, Behandlungen, Fütterungen, Schwarmkontrollen, Historie, Königin; ab T4 `next-steps` und Varroa-Bewertung). Einzige Backend-Änderung: `GET /autopilot/today` bekommt **additiv** den Saisonkalender und `segmentSince` je Stand (9.1). |
|
||||
| Diagramm-Bibliothek | Keine. Handgeschriebenes SVG wie `colony-varroa.tsx`. Beim Bau den `dataviz`-Skill laden (wie T3/T4). |
|
||||
| Bewegung | Keine neue Animation. Rad, Lebenslinie und Waben erscheinen sofort. Bewegung gibt es nur, wo sie heute einen Zustand zeigt (Abhaken, nächster Schritt). |
|
||||
| Bewegung | **Geändert 2026-10-16, siehe §17.** Eine Bewegungs-Sprache für die ganze App, abgeleitet aus der Beute: Bewegung nur, wo sie Orientierung gibt (woher kommt das Sheet, was ist weg, was hat geklappt), mit wenigen Tokens und den drei Stufen „Voll“, „Dezent“, „Aus“. Rad, Lebenslinie und Waben bleiben Daten und erscheinen weiter sofort (6.8, 8.5, 9.5). `motion` ist seit der Beute installiert und wird nur dort genutzt, wo CSS es nicht kann. |
|
||||
| Icons | Lucide wie bisher. Eine Tabelle `AREAS` (Abschnitt 11) ist die einzige Quelle für Icon und Farbton je Bereich. Navigation, Kopfzeilen, „+ Neu“ und T4-Vorschläge lesen daraus. |
|
||||
| App-Icons | Ein Master-SVG, daraus erzeugte PNGs (192/512 „any“, 192/512 „maskable“, 512 „monochrome“, 180 Apple, Favicon). Die erzeugten Dateien liegen im Repo; das Skript nutzt `sharp` als neue devDependency. |
|
||||
|
||||
@@ -68,6 +68,7 @@ Technisch heißt das:
|
||||
| Je ein Baustein für Auswahlgruppe, Checkbox, Tabs, Plus/Minus | `ChoiceGroup`, `Checkbox`/`CheckboxField`, `Tabs`, `NumberStepper` | 10 |
|
||||
| Feste Icon- und Farbzuordnung pro Bereich | `AREAS`, `AreaIcon` | 11 |
|
||||
| Fokusstil für alle eigenen Bedienelemente | globale Fokusregel | 4.6, 10.6 |
|
||||
| Nachtrag 2026-10-16: eine Bewegungs-Sprache für die App, passend zur Beute (Beute-Spec §12.4) | Stufen, Tokens, Regeln je Muster, Wächter | 17 |
|
||||
| §11 T5-Befunde: Weiß auf Honig 2,3:1, Eingaberahmen 1,56:1, Dark Mode unerreichbar, Auswahlgruppen von Hand, Checkboxen in 4, Tabs in 3 Varianten | alle behoben | 4.4, 5, 10 |
|
||||
|
||||
### 2.2 Befunde aus dem Code, die T5 zusätzlich behebt
|
||||
@@ -129,7 +130,7 @@ Gemessen mit derselben OKLCH-Rechnung wie `src/lib/forms/rating-contrast.spec.ts
|
||||
- Rad: Wo stehen wir im Bienenjahr, was kommt?
|
||||
4. **Nie nur Farbe.** Jeder Zustand hat ein Icon und ein Wort, jede Grafik einen Text und eine Tabelle. Die Zellen tragen den Volkscode und ein Zustands-Icon. Gestrichelte Ränder und Schraffuren unterscheiden auch ohne Farbsehen.
|
||||
5. **Vertraute Bedienung, eigene Handschrift im Detail.** Knöpfe, Felder, Tabs und Sheets verhalten sich wie überall im Web. Die Handschrift sitzt in Material (Wachs und Honig), Tinte und dem einen Motiv Wabenzelle, nicht in erfundenen Bedienelementen.
|
||||
6. **Ruhe.** Keine Verläufe, kein Glas, keine Zierbewegung, keine Großbuchstaben-Laufschrift. Schatten sind leise und entfallen in Sonne. Die Farbtöne der Bereiche erscheinen nur als Icon-Kachel, nicht als Fläche.
|
||||
6. **Ruhe.** Keine Verläufe, kein Glas, keine Zierbewegung, keine Großbuchstaben-Laufschrift. Schatten sind leise und entfallen in Sonne. Die Farbtöne der Bereiche erscheinen nur als Icon-Kachel, nicht als Fläche. Bewegung folgt §17. Glas, Leuchten und Ruhebewegung gibt es nur auf der Beute-Bühne (§17.8).
|
||||
|
||||
**Verboten** (der Wächter-Test prüft, was sich prüfen lässt):
|
||||
- Weiß auf Honig
|
||||
@@ -139,6 +140,7 @@ Gemessen mit derselben OKLCH-Rechnung wie `src/lib/forms/rating-contrast.spec.ts
|
||||
- Text unter 13 px
|
||||
- Zustand nur über Farbe
|
||||
- eigene `role="radio|checkbox|tab"`-Bauten außerhalb des Baukastens
|
||||
- Bewegung gegen §17: `motion-safe:` für Verschiebung, `transition-all`, animierte Breite, Höhe oder Unschärfe, bewegte Datenwerte
|
||||
|
||||
## 4. Tokens
|
||||
|
||||
@@ -1164,3 +1166,159 @@ Der Fahrplan nannte etwa 5 PT. Mehr wird es durch vier Punkte, die §10 nicht ei
|
||||
- A: Hell, Dunkel nur auf Wunsch.
|
||||
- B: Wie das Gerät. Ein Handy im Dunkelmodus zeigt die App dann auch draußen dunkel.
|
||||
- **Empfehlung: A.** Draußen bei Tag ist hell besser lesbar. Wer abends dunkel will, stellt einmal „Dunkel“ oder „Wie Gerät“ ein, und das Gerät merkt es sich.
|
||||
|
||||
4. **Bewegungs-Sprache (neu 2026-10-16, die Rückfrage aus Beute-Spec §12.4).** Wie viel Bewegung bekommt die App außerhalb der Beute?
|
||||
- A: Wie §17. Die App bleibt ruhig, die Beute ist die eine Bühne. Bewegung zeigt nur, woher etwas kommt, was weg ist und was geklappt hat. Das Abhaken bleibt der eine Moment.
|
||||
- B: Mehr Bewegung in der ganzen App: Karten heben sich, Zahlen zählen hoch, Seitenwechsel mit gleitenden Übergängen (View Transitions). Draußen kostet das Lesezeit und Akku.
|
||||
- C: Keine Bewegung außerhalb der Beute, auch kein Gleiten der Sheets.
|
||||
- **Empfehlung: A.** Hält die Beute als Höhepunkt und die Arbeit am Stand schnell. Die Stufe „Voll“ bleibt Standard; wer am Stand Ruhe will, stellt „Dezent“ ein.
|
||||
|
||||
## 17. Bewegungs-Sprache
|
||||
|
||||
Nachtrag 2026-10-16. Anlass: Die Beute (Spec `2026-10-15-beute-3d-design.md` §9.3, §9.8, §12.4) ist auf Wunsch des Inhabers stark animiert: Glas-Holo, Flug in den Fokus, Heben der Rähmchen, Federn. Die übrige App soll sich wie dieselbe App anfühlen. Dieser Abschnitt ersetzt die Regel „Keine neue Animation“ aus §1. Bestätigung durch den Inhaber: Frage 4 in §16.
|
||||
|
||||
### 17.1 Zweck
|
||||
|
||||
Draußen am Stand hat der Imker Sonne auf dem Display, Handschuhe an und eine Hand frei. Bewegung hat dort genau drei Aufgaben:
|
||||
|
||||
1. **Herkunft zeigen:** Ein Sheet kommt von seiner Kante, ein geöffnetes Teil fliegt aus seinem Stapel. Man sieht, wo man ist.
|
||||
2. **Veränderung zeigen:** Eine Zeile geht weg, die anderen rücken nach. Man sieht, was sich geändert hat.
|
||||
3. **Erfolg bestätigen:** Der Haken zeichnet sich, der Knopf gibt beim Drücken nach. Man weiß, dass der Tipp angekommen ist, auch mit Handschuh.
|
||||
|
||||
Bewegung schmückt nie und hält nie auf. Kein Ziel wartet auf eine Animation, und keine Zahl bewegt sich, während jemand sie liest.
|
||||
|
||||
### 17.2 Stufen
|
||||
|
||||
Es gilt die bestehende Bewegungsstufe je Gerät (`apicore.motion`, §5.1). Die Wörter in der Oberfläche heißen überall „Voll“, „Dezent“ und „Aus“ (die Beute-Spec nennt „Dezent“ an einer Stelle „ruhig“).
|
||||
|
||||
| Stufe | Wann | Ortswechsel (Gleiten, Fliegen, Heben, Nachrücken) | Zustandswechsel (Deckkraft, Farbe) | Ruhebewegung (Beute schwebt, Pegel wogt, Puls) |
|
||||
|---|---|---|---|---|
|
||||
| `full` „Voll“ | Standard, solange das System nicht reduziert | an, mit den Tokens aus 17.3 | an | an, nur sichtbar und im Vordergrund-Tab |
|
||||
| `subtle` „Dezent“ | gewählt, **oder** „Voll“ plus `prefers-reduced-motion: reduce` | aus, Dinge stehen sofort am Ziel | Überblendung `--motion-fade` (150 ms) | aus |
|
||||
| `off` „Aus“ | gewählt | aus | sofort (globale Regel in `globals.css`) | aus |
|
||||
|
||||
- **Eine Quelle für JavaScript:** `useEffectiveMotionLevel()` aus `src/lib/motion/motion-preference.ts`. Den Hook nutzt die Beute schon (`hive-canvas.tsx`, `hive-visual-slot.tsx`). Er verbindet die gewählte Stufe mit `prefers-reduced-motion` und reagiert sofort auf beides. Ab §5 setzt das Inline-Skript `data-motion` vor dem ersten Bild. `useAppearance().setMotion` löst dabei weiter `MOTION_EVENT` aus, damit Szene und DOM sofort mitziehen.
|
||||
- **Eine Quelle für CSS:** die Variante `motion-full:` (gibt es schon in `globals.css`). Jede Verschiebung, Skalierung oder Drehung steht hinter `motion-full:`. `motion-safe:` fragt nur das System und übergeht die Stufe in der App; für Ortswechsel ist es darum verboten. Farb- und Deckkraft-Übergänge brauchen keine Variante, weil „Aus“ ihre Dauer global auf null setzt.
|
||||
- **`motion` (`motion/react`):** Ein `AppMotion`-Rahmen im `(app)`-Layout setzt `MotionConfig` je Stufe. Bei `full` steht `reducedMotion` auf `"never"`, weil der Hook das System schon einrechnet. Bei `subtle` steht es auf `"always"`: Dann laufen nur Deckkraft und Farbe. Bei `off` gilt `transition={{ duration: 0 }}`.
|
||||
- **Sonne ändert keine Bewegung.** Sonne betrifft nur Kontrast und Größen. Das Umschalten von Farbschema, Kontrast und Stufe wirkt sofort und ohne Übergang (§5.3).
|
||||
|
||||
### 17.3 Tokens
|
||||
|
||||
Die Werte kommen aus dem, was die Beute schon ausliefert, und aus den bestehenden CSS-Bewegungen. Darum fühlen sich Bühne und App gleich an. CSS-Variablen stehen in `globals.css` (`:root`). Den Spiegel in TypeScript liefert `src/lib/motion/tokens.ts`. Die Beute liest ihre Feder und ihre Überblendung künftig aus dieser Datei (`quality.ts`, `use-hive-motion.ts`), damit es nur eine Quelle gibt.
|
||||
|
||||
| Token | Wert | Herkunft | Verwendung |
|
||||
|---|---|---|---|
|
||||
| `--motion-fade` | 150 ms | `SUBTLE_FADE_SECONDS` (Beute), Overlay der Sheets | jede Überblendung, jeder Austritt, alle Wechsel bei „Dezent“ |
|
||||
| `--motion-enter` | 200 ms | `ui/sheet.tsx` (200 ms) | Eintritt von Sheet, Dialog, Popover, Menü, Seite und neuer Listenzeile |
|
||||
| `--motion-settle` | 350 ms | `DAMPING = 12` (Beute: nach 350 ms in Ruhe) | Ortswechsel ohne Feder: Zurückfedern, Aufklappen eines Abschnitts |
|
||||
| `--motion-moment` | 420 ms | `.honey-check` (Wabe füllt sich) | der eine Moment: Abhaken |
|
||||
| `--ease-out-expo` | `cubic-bezier(0.16, 1, 0.3, 1)` | Bestand in `globals.css` | alle Eintritte, der Moment |
|
||||
| `--ease-in` **neu** | `cubic-bezier(0.4, 0, 1, 1)` | – | alle Austritte (schneller weg als da) |
|
||||
| `--ease-spring` **neu** | `linear(…)`, aus der Feder unten erzeugt | `SPRING_STIFFNESS 210`, `SPRING_DAMPING 21` (`quality.ts`, Dämpfungsgrad ≈ 0,72, in Ruhe nach ≈ 0,5 s) | CSS-Ortswechsel mit leichtem Überschwingen, Dauer 500 ms |
|
||||
| `SPRING_FLIGHT` (TS) | `{ type: "spring", stiffness: 210, damping: 21, mass: 1 }` | dieselbe Feder | `motion`: Nachrücken (`layout`), Loslassen nach dem Ziehen |
|
||||
| `--motion-shift` **neu** | 8 px | Beute hebt ein Teil 8 mm, `next-step-in` 8 px | Weg beim Eintritt von Inhalt (Seite 6 px bleibt) |
|
||||
| Sheet-Weg | 2,5 rem | Bestand `ui/sheet.tsx` | Sheet gleitet von seiner Kante |
|
||||
|
||||
**Grenzen:**
|
||||
- Kein DOM-Übergang dauert länger als `--motion-moment` (420 ms).
|
||||
- Ausnahmen gibt es nur zwei:
|
||||
- die Beute-Bühne (Federflug ≈ 0,5 s, Ruhebewegung)
|
||||
- das Wegfalten der Heute-Zeile nach dem Abhaken (`EXIT_DELAY_MS.full = 720`). Gespeichert ist dort sofort, „Rückgängig“ steht im Toast.
|
||||
- Austritte sind nie länger als `--motion-fade`.
|
||||
|
||||
### 17.4 Regeln je Muster
|
||||
|
||||
| Muster | Voll | Dezent | Werkzeug |
|
||||
|---|---|---|---|
|
||||
| **Seite** (Routenwechsel) | Eintritt: Deckkraft 0 → 1 und 6 px nach oben, `--motion-enter`, `--ease-out-expo`. Kein Austritt: Die alte Seite verschwindet sofort, die Navigation wartet nicht. | nur Deckkraft, `--motion-fade` | CSS `animate-page-in` (`page-transition.tsx`, Dauer heute 260 ms → Token) |
|
||||
| **Sheet, Dialog, Popover, Menü** (öffnen, schließen) | Sheet gleitet 2,5 rem von seiner Kante, Dialog und Popover blenden mit `scale(0.97 → 1)` ein; Eintritt `--motion-enter` mit `--ease-out-expo`, Austritt `--motion-fade` mit `--ease-in` auf demselben Weg zurück; Hintergrund nur Deckkraft. Der Fokus springt beim Öffnen sofort hinein, nicht erst nach der Animation. Beim Auf- oder Zugehen der Bildschirmtastatur bewegt sich das Sheet nicht. | nur Deckkraft | CSS über `data-starting-style`/`data-ending-style` von Base UI (Muster steht in `ui/sheet.tsx`). Dialog heute 100 ms, Sheet heute `ease-in-out` → Tokens. |
|
||||
| **Listenzeile hinzu** (durch den Nutzer: Eintrag gespeichert, Zeile ergänzt) | nur die neue Zeile: Deckkraft und `--motion-shift`, `--motion-enter`. Kein Stagger, kein Einblenden beim Laden einer Liste. Daten stehen sofort da. | Deckkraft, `--motion-fade` | CSS (`animate-in` aus `tw-animate-css` oder `@starting-style`) |
|
||||
| **Listenzeile weg** | Zeile blendet aus (`--motion-fade`), die übrigen rücken mit `SPRING_FLIGHT` nach. Das läuft über `transform` (`layout`), nicht über die Höhe. | Zeile blendet aus, der Rest steht sofort am Ziel | `motion`: `AnimatePresence` und `m.li layout`. Gilt für Heute-Liste, Aufgaben, Warteschlangen-Sheet und Sprachnotizen. |
|
||||
| **Umsortieren** | `layout` mit `SPRING_FLIGHT` | sofort | `motion` |
|
||||
| **Abschnitt auf/zu** (Aufklapp-Karten, „Als Tabelle“) | Pfeil dreht sich (`--motion-settle`). Der Inhalt erscheint sofort, ohne Höhen-Animation. | Pfeil springt | CSS `motion-full:transition-transform` (Bestand, bisher `motion-safe:`) |
|
||||
| **Erfolg, Bestätigung** | **Abhaken** ist der eine Moment: Wabe füllt sich (`--motion-moment`), Haken zeichnet sich, Zeile faltet weg. **Speichern** endet mit Toast und Navigation; kein Konfetti, kein Knopf, der seine Form ändert. **Knopf-Druck:** Fläche wechselt sofort, bei Voll zusätzlich `scale(0.97)` beim Drücken, 100 ms. | Wabe und Haken blenden in 120 ms (Bestand), Knopf ohne Skalierung | CSS (`.honey-check`, `ui/button.tsx` `motion-full:active:scale-[0.97]`) |
|
||||
| **Fokuswechsel** | Der Fokusring erscheint sofort und wird nie animiert. Programmatischer Fokus (erstes Fehlerfeld, geöffnetes Sheet, Live-Region) springt. Scrollen dorthin ist `smooth` nur bei Voll und bei weniger als einer Bildschirmhöhe, sonst sofort. Auf der Beute-Bühne fliegt die Kamera mit (Beute §9.4). | Scrollen sofort | `scrollBehaviorFor(level, distance)` in `src/lib/motion/tokens.ts` |
|
||||
| **Laden, Skelett** | Das Skelett erscheint erst nach 150 ms, damit kurze Ladezeiten nicht blitzen. Pulsieren nur bei Voll (Deckkraft, 2 s). Spinner nur in Knöpfen ab 300 ms Wartezeit und immer mit Wort („Speichert …“). | Skelett ruhig; der Spinner wird ein ruhendes Icon mit Wort | CSS `motion-full:animate-pulse`, `motion-full:animate-spin` (bisher `motion-safe:`) |
|
||||
| **Läuft gerade** (Aufnahme, Synchronisieren) | Punkt pulsiert (Deckkraft) | ruhiger Punkt; das Wort („Aufnahme läuft“) trägt den Zustand | CSS |
|
||||
| **Hover** (nur `pointer-fine`) | nur Farbe und Rahmen, keine Verschiebung im DOM. Das Heben der Karten (`ui/card.tsx`) und das Vergrößern der Icons in der Seitenleiste entfallen. Auf der Beute-Bühne hebt sich das Teil (Beute §9.4), weil es dort zeigt, was der nächste Klick öffnet. | Farbe | CSS |
|
||||
| **Wabenmotiv** | Die Wabenzelle bewegt sich nur an zwei Stellen: beim Abhaken (`.honey-check`) und auf der Beute-Bühne. Waben-Standkarte, Mini-Waben, Rad, Lebenslinie, `BrandMark` und `AreaIcon` stehen still (6.8, 8.5, 9.5 bleiben). Ein Ladezeichen in Wabenform gibt es nicht. | – | – |
|
||||
| **Toast** | Sonner-Standard (gleitet), Dauer und Kurve auf die Tokens | ohne Gleiten, nur Deckkraft | CSS-Überschreibung an `[data-sonner-toaster]`, falls Sonner das nicht selbst tut |
|
||||
|
||||
### 17.5 Was nie animiert
|
||||
|
||||
- **Datenwerte, die der Imker liest:**
|
||||
- Zahlen, Ampeln, Zählungen, Balken, Kurven, Zellfüllungen, der Rad-Zeiger und die Zahl im Pegel-Etikett.
|
||||
- Nichts zählt hoch, kein Balken wächst, keine Linie zeichnet sich.
|
||||
- Ein neuer Wert nach dem Sync steht sofort da.
|
||||
- Bestand, der das verletzt: `stat-bar-list.tsx` (`transition-[width] duration-700`) verliert den Übergang.
|
||||
- Auf der Beute-Bühne wogt die Oberfläche des Pegels; seine Zahl springt.
|
||||
- **Fehler und Warnungen:**
|
||||
- Feldfehler, `role="alert"`, Warn- und Sperr-Hinweise (Sperrbezirk, Wartezeit, 409) erscheinen sofort.
|
||||
- Kein Schütteln, kein Einblenden, kein verzögertes Erscheinen.
|
||||
- **Während der Eingabe am Stand:**
|
||||
- Das Feld selbst, die Zahl im Stepper (keine rollenden Ziffern), die Umgebung des fokussierten Felds.
|
||||
- Nichts verschiebt sich, kein Toast legt sich über Feld oder Speichern-Leiste, nichts leitet von selbst weiter.
|
||||
- Eine Diktat- oder Sprachnotiz-Aufnahme bewegt nur ihren Status-Punkt.
|
||||
- **Fokusring, Sonne an/aus, Farbschema, Druck und PDF.**
|
||||
- **Warten:**
|
||||
- Kein Ziel ist während eines Eintritts gesperrt (`pointer-events` bleiben an).
|
||||
- Kein Klick wartet auf einen Austritt.
|
||||
- Einzige gewollte Verzögerung ist das Wegfalten der Heute-Zeile (17.3).
|
||||
|
||||
### 17.6 Leistung
|
||||
|
||||
- **Nur `transform` und `opacity`** bewegen sich.
|
||||
- Für Zustandswechsel kommen Farbe (`color`, `background-color`, `border-color`, `fill`, `stroke`) und `clip-path` dazu (`.honey-check`).
|
||||
- Nie animiert werden `width`, `height`, `top`, `left`, `margin`, `padding`, `grid-template-rows`, `box-shadow`, `filter` und `backdrop-filter`.
|
||||
- Bestand, der das verletzt:
|
||||
- `.today-row` faltet über `grid-template-rows` → `motion` `layout` (17.4)
|
||||
- `next-step-in` animiert `filter: blur(6px)` → nur Deckkraft und `--motion-shift`
|
||||
- `stat-bar-list` animiert die Breite → ohne Übergang
|
||||
- **Kein `transition-all`:** Die Übergänge nennen ihre Eigenschaften (`transition-colors`, `transition-[opacity,transform]`). Heute gibt es 8 Stellen, 7 davon in `ui/*`.
|
||||
- **Kein Layout-Thrash:**
|
||||
- Keine Messung (`getBoundingClientRect`, `offsetHeight`) in einem Animationsschritt.
|
||||
- `motion` misst bei `layout` einmal zu Beginn und bewegt dann per `transform`.
|
||||
- Kein React-State pro Bild. DOM-Bewegung läuft über CSS oder über das WAAPI von `motion`.
|
||||
- **`will-change`** setzt nur `motion` selbst, nie dauerhaft in CSS. `backdrop-blur` nur auf ruhenden Flächen, in Sonne gar nicht (§4.3).
|
||||
- **Ziel:** 60 fps auf einem Mittelklasse-Handy. Gemessen wird mit einem Performance-Trace bei 4-facher CPU-Drosselung und 390 px. Bei Sheet auf/zu, Abhaken mit Wegfalten, Zeile entfernen und Seitenwechsel ist kein Frame länger als 32 ms, und während der Bewegung gibt es keinen Layout-Eintrag außer der einen `layout`-Messung.
|
||||
- **Bundle:**
|
||||
- `motion` nur über `LazyMotion` mit `strict`. Elemente kommen als `m.*` aus `motion/react-m`, die Features (`domMax` wegen `layout`) asynchron.
|
||||
- Geladen wird nur im `(app)`-Layout, nicht auf Login und Herkunft.
|
||||
- Budget: höchstens 30 kB gzip, im Build gemessen wie das 3D-Budget.
|
||||
- Die three.js-Szene nutzt `motion` nicht (eigene Federn in `use-animated-node.ts`).
|
||||
|
||||
### 17.7 Abnahme
|
||||
|
||||
1. **Wächter** (`src/styles/baukasten-guard.spec.ts`, Regelgruppe „Bewegung“, Ausnahmen mit Grund):
|
||||
- kein `motion-safe:` vor `translate`, `scale`, `rotate`, `slide-`, `zoom-`, `animate-` (→ `motion-full:`)
|
||||
- kein `transition-all`
|
||||
- kein `transition-[width|height]` und kein `duration-` über 420 ms (Ausnahme `components/hive/**`)
|
||||
- `hover:` mit `translate` oder `scale` nur in `components/hive/**`
|
||||
- `motion/react` liefert nur `LazyMotion`, `MotionConfig`, `AnimatePresence` und Hooks; Elemente nur als `m.*`
|
||||
- Keyframes und Übergänge in `globals.css` animieren keine Eigenschaft aus der Verbotsliste in 17.6 (der Test liest die Datei)
|
||||
2. **Tokens** (`src/lib/motion/tokens.spec.ts`):
|
||||
- Die CSS-Variablen entsprechen den TS-Konstanten.
|
||||
- `SPRING_FLIGHT` hat dieselben Werte wie die Feder der Beute (eine Quelle).
|
||||
- Die Stützpunkte von `--ease-spring` weichen höchstens 0,02 von `springStep` ab.
|
||||
3. **Komponenten:**
|
||||
- `AppMotion` setzt `reducedMotion` je Stufe.
|
||||
- Bei „Aus“ ist eine entfernte Zeile sofort weg, bei „Dezent“ ohne Verschiebung.
|
||||
- `scrollBehaviorFor` liefert `smooth` nur bei Voll und kurzer Strecke.
|
||||
4. **Browser** (Chrome DevTools):
|
||||
- Jedes Muster aus 17.4 einmal in Voll, Dezent und Aus, dazu `prefers-reduced-motion: reduce` per `emulate`.
|
||||
- Bei Dezent und bei reduce verschiebt sich nichts, bei Aus geht alles sofort.
|
||||
- Dazu der Performance-Trace aus 17.6.
|
||||
5. **Draußen-Test** (13.4) bekommt Aufgabe 6: eine Aufgabe mit Handschuh abhaken. Bestanden, wenn der Haken gesehen wird und niemand auf die Liste wartet.
|
||||
6. **Review:** einmal `review-animations` bzw. `fixing-motion-performance` über den Diff (Skill-Routing: erst Konzept, dann CSS, dann `motion`, GSAP nicht).
|
||||
|
||||
### 17.8 Beute-Bühne im T5-Rahmen
|
||||
|
||||
- Die Bühne ist eine eigene, immer dunkle Fläche mit eigenen Tokens (`--holo-*`).
|
||||
- Nur hier gibt es Glas, Leuchten, Milchglas-Elemente und Ruhebewegung.
|
||||
- §3.6 und die Verbotsliste gelten außerhalb der Bühne. Wächter-Ausnahmen gelten nur für `components/hive/**` und `app/(app)/colonies/[id]/hive/**`.
|
||||
- Bewegung auf der Bühne folgt Beute §9.8. Die Werte stammen aus denselben Tokens (17.3).
|
||||
- Fokus auf der Bühne: Der Ring aus §4.6 in `--primary-ink` hat auf `--holo-bg` weniger als 3:1. Deshalb setzt ein Rahmen `.holo-stage` `--ring: var(--holo-edge-strong)`. `contrast.spec.ts` prüft das Paar (≥ 3) und die Etiketten `--holo-label-fg` auf `--holo-label-bg` (≥ 7).
|
||||
- **Sonne:**
|
||||
- `--holo-*` bekommt Sonne-Sätze (Bühne schwarz, Kanten reinweiß).
|
||||
- Die Szene liest die Tokens beim Wechsel der Darstellung neu ein; heute geschieht das einmalig in `hive-scene/theme.ts`.
|
||||
- Ohne Bloom, Kanten 2 px, Rähmchen-Arten als Schraffur, Etiketten 16 px (Beute §9.3).
|
||||
Reference in new issue
Block a user