Files
posts/POST-6.md
T
dejanandClaude Opus 5 ce87a7fb57 Post 6: fuenfte Slide fuer den mobilen Chat, Tiefe ueber den Stapel
Zwei Nachbesserungen an Post 6: eine Slide mehr und Zeichnungen, die nicht
mehr flach aussehen.

DIE FUENFTE SLIDE KOMMT VON DER WEBSITE
Die App gibt es noch nicht, und die Website sagt das bereits. In
components/sections/ChatDemoSection.tsx steht unter der Fahne comingSoon
genau dieser Zustand: ein Handy-Mockup, verwischt, und darueber ein
Absperrband aus dem Bau -- gedreht um -13 Grad, in accent-yellow F1B729 mit
Kanten in 171106, darauf immer wieder Schutzhelm und BALD VERFUEGBAR.

Ein Zwischenstand hatte hier einen selbst erfundenen gelben Aufkleber
"In Arbeit". Das war eine zweite Bildsprache neben einer vorhandenen.
Uebernommen ist jetzt die der Website, samt Winkel, Farben und Wortlaut.

Auch der Inhalt des Schirms kommt von dort und nicht aus dem Pitch-Paket:
Heizungsprojekt Schulz, "4 Mitglieder · 2 online", die vier Nachrichten aus
seedMessages, die Blasenfarben 0D6E6E fuer eigene und FFFFFF mit Rand E9E7E5
fuer fremde, der warme Grund hsl(30 17% 95.5%). Ueberschrift und Fliesstext
ebenso: "Der Chat fuer unterwegs wird gerade gebaut."

Das Geraet selbst ist eine bewusste Abweichung. Die Website zeichnet nur
einen hellen Umriss, border 4px D1D5DB; auf einer Slide, die selbst hell ist,
faellt der in sich zusammen und sieht nach Platzhalter aus. Hier steht ein
richtiges Geraet: dunkler Korpus, heller Grat, Schirm eingelassen, Insel und
Tasten. Die Abweichung betrifft den Rahmen, nicht den Inhalt. Verwischt wird
schwaecher als dort -- auf der Website liegt das Handy gross neben Fliesstext
und darf unlesbar sein, hier ist es klein, und bei voller Staerke blieb Brei.

DIE TIEFE
Zwei Anlaeufe waren falsch. Der erste legte graue Flaechen hinter die
Elemente: das nimmt den Zeichnungen ihre Durchsichtigkeit und setzt einen
Kasten auf den Punktgrund, der dort nicht hingehoert. Wieder raus, die
Zeichnungen sind wieder durchsichtig.

Der zweite waren bessere Schatten allein. Richtig, aber zu wenig. Die
Schatten des Produkts sind in ui/theme.css gestaffelt und nicht einlagig:

  --shadow-md  0 4px 16px -2px  +  0 2px 4px -1px
  --shadow-lg  0 12px 32px -4px +  0 4px 8px -2px

Zwei Lagen, weil eine allein nicht beides kann: die enge dunkle Kante setzt
das Element auf die Flaeche, die weite helle hebt es davon ab. In SVG zwei
feDropShadow im selben Filter. Vorher stand dort einer mit dy 7.

Gebracht hat es der Stapel. post1.html hat ihn als Bildrahmen im CSS, fuer
Screenshots; hier ist er in SVG nachgebaut, mit denselben Werten:

  .sheet-mid   rotate(-2.4deg) translate(-2.2%, 3%)  scale(.975)
  .sheet-back  rotate( 3.2deg) translate( 3%,  5.5%) scale(.95)

Er gibt Tiefe, die ein Schatten allein nicht schafft, und sagt, dass hinter
der einen Ansicht weitere liegen. Die hinteren Blaetter sind leer --
Andeutung, keine Kopie. Auf Slide 1 und 2, wo ein Bildschirm zu sehen ist;
nicht auf Slide 3, wo ein Ausschnitt einer Unterhaltung steht, und nicht auf
Slide 4, die eine Ueberlagerung ist.

AUS DER QUELLE NACHGEHOLT
Beim gruendlichen Durchgang durch GeneralTeamChatPage.tsx sind drei Dinge
aufgefallen, die vorher fehlten oder falsch waren:

- Die Datumsmarke "Heute · 30.07.2026" ueber dem ersten Beitrag und die Zeile
  "Maike Berger schreibt gerade ..." ueber dem Eingabefeld. Beides gibt der
  Unterhaltung Struktur, ohne eine Flaeche zu behaupten.
- Der offene Kanal ist grau hinterlegt mit Rand und shadow-sm, nicht violett.
- Die Blase muss so breit sein, wie ihr Anhang es braucht. Vorher richtete
  sie sich nur nach dem Fliesstext, und "Materialliste pruefen · faellig
  31.07.2026" wurde abgeschnitten -- an einer Stelle, an der der Titel die
  Aussage traegt.

ZWEI FALLEN
Gedrehte Blaetter ragen aus dem Kasten. Das hinterste steht um 3,2 Grad
gedreht und um 3 und 5,5 Prozent verschoben; seine Ecken lagen bis zu 24 px
ausserhalb der 92-px-Schutzzone. Der Ueberstand wird jetzt gerechnet:
stapelRand() schickt die vier Ecken durch dieselbe Kette wie das Blatt.

getBBox() kennt keine Beschneidung. Das Absperrband war erst auf die 175 %
der Website gezogen und am Geraet abgeschnitten -- im Bild richtig, in der
Messung ein Ueberstand von 146 px, den es nicht gab. Es ist jetzt nur so
lang, wie es bei -13 Grad quer ueber das Geraet sein muss.

GEPRUEFT
Raender 93 / 227 / 110 / 140 / 350, Luft 116 / 79 / 190 / 141 / 77 px, alle
Ueberschriften innerhalb der Schutzzone, 214 CSS-Regeln, Konsole ohne Fehler,
fuenf PNGs aus dem echten Ausgabeweg bei 2160 x 2700. Downloads blieb leer,
der Projektstand unveraendert.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-24 17:24:45 +02:00

12 KiB
Raw Blame History

Post 6 · Team-Chat

Fünfter Beitrag der Produktreihe, Termin Mi 26.08. laut Redaktionsplan (von Mo 24.08. verschoben). Stichwort dort: „Ein Kanal pro Projekt, Foto rein, Aufgabe raus."

Hell, Theme modern, Punktgrund, Text zentriert — dieselbe Anlage wie Post 4 und 5. Datei post6.html, Stand in state/post6.json, erreichbar über das Projektmenü jeder Seite und über uebersicht.html.

Fünf Slides. DSGVO und deutsche Server hätten einen sechsten Punkt ergeben, dafür gibt es aber keinen Bildschirm. Der steht in der Bildunterschrift, wo eine Aussage ohne Bild hingehört.


1. Die vier Slides

# Tag Überschrift Was zu sehen ist
1 Team-Chat Büro und Baustelle, endlich im selben Chat. Kanalliste und Verlauf nebeneinander, mit Filterzeile und Eingabefeld
2 Die Kanäle Ein Kanal pro Projekt. Die Chatliste groß: Projektkanäle, Direktnachrichten, Gruppe
3 Die Aufgabe Foto rein, Aufgabe raus. Baustellenfotos, die Aufgabe daraus, die Bestätigung im Projekt
4 Das Pluszeichen Nicht nur Text. Das Menü hinter dem Plus im Eingabefeld
5 Bald verfügbar Der Chat für unterwegs wird gerade gebaut. Das Handy-Mockup der Website, verwischt, mit Absperrband

Slide 3 ist der Kern. Der Redaktionsplan verlangt „Foto rein, Aufgabe raus", und genau das liegt im Werkzeug als Abfolge vor: Tobias schickt die Baustellenfotos, darauf folgt eine Nachricht mit angehängter Aufgabe, darauf eine Systemzeile „Aufgabe „Materialliste prüfen" im Projekt erstellt". Die letzte Zeile macht den Unterschied: die Aufgabe liegt danach im Projekt und nicht nur im Verlauf.

Slide 1 trägt den ganzen Chat, weil sie im Profilraster eine Kachel von rund 150 px ist. Dort ist kein Wort lesbar; was ankommt, sind zwei Spalten mit Blasen.


2. Die Bildunterschrift

Im Handwerk läuft die halbe Baustelle über WhatsApp. Das Foto von letzter Woche findet trotzdem keiner wieder.

In HiveGrid hat jedes Projekt seinen eigenen Kanal, mit Projektnummer. Daneben stehen Direktnachrichten und Gruppen, aber eben nicht alles in einem Verlauf.

Ein Foto von der Baustelle geht rein, alle sehen es sofort. Aus „mach das mal“ wird mit einem Klick eine echte Aufgabe: mit Frist, mit Namen, im Projekt.

Dokument, Sprachnachricht, Kontakt, Termin. Was sonst im Chat-Verlauf verschwindet, hängt hier am Projekt.

Kundendaten gehören nicht in eine WhatsApp-Gruppe. Bei HiveGrid liegen sie verschlüsselt auf deutschen Servern.

#handwerk #shk #handwerksbetrieb #digitalisierungimhandwerk #teamchat #baustelle #kommunikation #hivegrid
Vorgabe Ist
Haken in den ersten 125 Zeichen erster Absatz, 110
300 bis 800 Zeichen 644
5 bis 10 Hashtags, unten abgesetzt 8
Suchwörter zusätzlich im Fließtext Handwerk, Baustelle, Projekt, Kanal, Aufgabe, Chat, Kontakt, Termin

Der letzte Absatz steht wörtlich so als Merkmal „DSGVO-konform" in lib/produkt-daten.ts der Website. „Aus „mach das mal" wird mit einem Klick eine echte Aufgabe" ebenfalls, als Merkmal „Aufgaben-Integration".


3. Woher die Angaben kommen

Quelle ist components/general/GeneralTeamChatPage.tsx aus dem Pitch-Paket (fertig bombo · Kundentermin 30.07.2026).

Was Woher
Alle acht Kanäle: Titel, Vorschau, Zeit, Zuordnung, Nadel, Ungelesen CHATS, wörtlich
Der Verlauf: Autoren, Texte, Zeiten, Anhänge INITIAL_MESSAGES.waermepumpe, wörtlich
Aufbau einer Listenzeile (drei Zeilen) die Zeilen 170 bis 172 der Quelle
Aufbau einer Nachricht, Anhangkarte, Systemzeile MessageBubble und AttachmentCard
Sinnbild je Kanalsorte (Koffer, Personen, Kürzel) ChatAvatar
Kopfzeile „P-2026-0042 · 8 Mitglieder · aktiv" ChatHeader
Filterzeile Alle / Projekte / Direkt / Ungelesen der Typ ChatFilter
Das Menü hinter dem Plus, samt Trenner Composer
Eingabefeld „Nachricht schreiben …" derselbe Ort
Farben, Ränder, Plättchentöne ui/theme.css
Alle Symbole @subframe/core, Pfade aus dem Paket kopiert
„Büro und Baustelle, endlich im selben Chat." Überschrift in lib/produkt-daten.ts

Vom Chat gibt es nur eine Fassung. Anders als bei der Pipeline, die mit Board, Liste, Detail und Schablone vier eigene SHK-Bildschirme hat, liegt der Chat allein unter /allgemein/team-chat. Die Inhalte darin sind trotzdem aus dem Gewerk: Wärmepumpe Müller, Montagetermin, Baustellenfotos.


4. Wo bewusst abgewichen wird

Slide 1 zeigt drei von sechs Nachrichten, Slide 2 fünf von acht Kanälen. Was nicht ins Bild passt, fällt weg; ein Chat und eine Liste scrollen beide. Slide 2 behält alle drei Sorten: Projektkanal, Direktnachricht, Gruppe.

Die Bildergalerie ist eine Anhangkarte, kein Bild. Im Werkzeug zeigt GalleryPreview zwei Fotos, geladen von Unsplash. Fremde Fotos in einen Beitrag zu setzen, der von der eigenen Baustelle spricht, wäre eine Behauptung über Material, das wir nicht haben. Stattdessen steht dort die Karte „2 Baustellenfotos · Galerie · heute" — der Text ist der der Quelle.


5. Stand der Dinge

Slides 5
Format 1080 × 1350, Ausgabe zweifach: 2160 × 2700
Luft zwischen Text und Zeichnung 116 / 79 / 190 / 141 / 77 px (Grenze 40)
Zeichnung ragt über die Seite nein, alle innerhalb der 92-px-Schutzzone
Breiteste Überschriftzeile 818 px von 896
Stylesheet vollständig 214 Regeln, [data-edit] vorhanden
Konsole keine Fehler
Ausgabeweg geprüft, 01-chat-hell.png bis 05-handy-hell.png

Geprüft wird mit den Hilfsskripten aus dem Sitzungsordner: pruef.mjs misst über getBBox() die tatsächlich gezeichnete Fläche je Slide und die Breite jeder Überschriftzeile, zählt die Regeln im Stylesheet und liest die Konsole mit; schuss.mjs rendert einzelne Slides; export.mjs fährt den echten Ausgabeweg und fängt /save ab.


5a. Slide 5 kommt von der Website, nicht von mir

Das Gerät ist eine bewusste Abweichung. Die Website zeichnet nur einen hellen Umriss (border: 4px solid #D1D5DB). Auf einer Slide, die selbst hell ist, fällt der in sich zusammen und sieht nach Platzhalter aus. Hier steht deshalb ein richtiges Gerät: dunkler Korpus, heller Grat, Schirm eingelassen, Tasten an der Seite. Die Abweichung betrifft den Rahmen, nicht den Inhalt. Der Schirm wird auch schwächer verwischt als dort: auf der Website liegt das Handy groß neben Fließtext und darf unlesbar sein, hier ist es klein, und bei voller Stärke blieb nur Brei.

Die App gibt es noch nicht, und die Website sagt das bereits. In components/sections/ChatDemoSection.tsx steht unter der Fahne comingSoon genau dieser Zustand: ein Handy-Mockup, das mit blur(3px) saturate(0.92) verwischt wird, und darüber ein Absperrband aus dem Bau, gedreht um -13°, in --accent-yellow #F1B729 mit Kanten in #171106, darauf immer wieder Schutzhelm und BALD VERFÜGBAR.

Ein Zwischenstand hatte hier einen selbst erfundenen gelben Aufkleber „In Arbeit". Das war eine eigene Bildsprache neben einer vorhandenen. Übernommen ist jetzt die der Website, samt Winkel, Farben und Wortlaut.

Auch der Inhalt des Schirms kommt von dort und nicht aus dem Pitch-Paket: Heizungsprojekt Schulz, „4 Mitglieder · 2 online", die vier Nachrichten aus seedMessages, die Blasenfarben #0D6E6E für eigene und #FFFFFF mit Rand #E9E7E5 für fremde, der warme Grund hsl(30 17% 95.5%). Auf der Website steht dieses Handy für den mobilen Chat, also zeigt es hier dasselbe.

Überschrift und Fließtext sind ebenfalls die der Website: „Der Chat für unterwegs wird gerade gebaut." und „Die mobile App legen wir gerade auf die Baustelle. Am Desktop bist du schon voll dabei, die Version fürs Handy folgt in Kürze." Der Em-Dash der Vorlage ist durch ein Komma ersetzt, rules.md §4.


5b. Woher die Tiefe kommt

Zwei Anläufe waren falsch, bevor es saß.

Erster Versuch: graue Flächen hinter die Elemente. Das nimmt den Zeichnungen ihre Durchsichtigkeit und setzt einen Kasten auf den Punktgrund, der dort nicht hingehört. Wieder raus.

Zweiter Versuch: nur bessere Schatten. Richtig, aber zu wenig. Die Schatten des Produkts sind in ui/theme.css gestaffelt und nicht einlagig, und das war tatsächlich ein Fehler im ersten Nachbau:

--shadow-sm  0 1px 2px            rgb(0 0 0 / .08)
--shadow-md  0 4px 16px -2px  +  0 2px 4px -1px
--shadow-lg  0 12px 32px -4px +  0 4px 8px -2px

Zwei Lagen, weil eine allein nicht beides kann: die enge dunkle Kante setzt das Element auf die Fläche, die weite helle hebt es davon ab. In SVG zwei feDropShadow im selben Filter. Vorher stand dort einer mit dy 7 und stdDeviation 10.

Was es gebracht hat: der Stapel. post1.html hat ihn als Bildrahmen stapel im CSS, für Screenshots. Hier ist er in SVG nachgebaut, mit genau denselben Werten, damit die Reihe zusammenpasst:

.sheet-mid   rotate(-2.4deg) translate(-2.2%, 3%)  scale(.975)
.sheet-back  rotate( 3.2deg) translate( 3%,  5.5%) scale(.95)

Er trägt zwei Aufgaben: er gibt Tiefe, die ein Schatten allein nicht schafft, und er sagt, dass hinter der einen Ansicht weitere liegen. Die hinteren Blätter sind deshalb leer — Andeutung, keine Kopie.

Auf Slide 1 und 2 liegt er, weil dort ein Bildschirm zu sehen ist. Auf Slide 3 nicht: ein Ausschnitt aus einer Unterhaltung ist kein Blatt, dort tragen die Blasen ihre eigene Erhebung. Slide 4 ist eine Überlagerung und trägt --shadow-overlay.

Dazu zwei Dinge aus der Quelle, die der Unterhaltung Struktur geben, ohne eine Fläche zu behaupten: die Datumsmarke Heute · 30.07.2026 über dem ersten Beitrag und die Zeile „Maike Berger schreibt gerade …" über dem Eingabefeld. Beides steht so in GeneralTeamChatPage.tsx.

Nebenbei richtiggestellt: der offene Kanal ist grau hinterlegt, nicht violett. Im Original steht dort bg-surface-neutral-primary mit Rand und shadow-sm.


6. Fünf Fallen aus diesem Bau

Die Listenzeile hat drei Zeilen, nicht zwei. Der erste Anlauf setzte Titel und Vorschau untereinander und schob Nadel und Ungelesen-Punkt rechts neben die Vorschau. Dort stießen sie an den Text — und die Zuordnung fehlte ganz. Im Original steht sie als dritte Zeile: P-2026-0042 links, die Nadel rechts. Das war nicht nur ein Layoutfehler: der Fließtext behauptete „Jeder Kanal hängt an seiner Projektnummer", und die Nummer war nirgends zu sehen.

Eine feste Obergrenze für die Blasenbreite hat ein Zitat gekürzt. Für die Titelslide musste sie klein sein, damit die Unterhaltung neben die Liste passt. Auf Slide 3 stand deshalb „Materialliste prüfen · fälli…" statt „… · fällig 31.07.2026". Die Grenze hängt jetzt an der Spalte, in der die Blase steht.

Beinahe hätte ich ein Zitat ohne Grund gekürzt. Die Website-Überschrift lautet „Büro und Baustelle, endlich im selben Chat." Ich hatte das „endlich" gestrichen mit der Begründung, die Zeile laufe sonst über die Schutzzone, und diese Begründung sogar mit einer Zahl versehen, die ich nicht gemessen hatte. Nachgemessen sind es 818 px von 896 erlaubten: sie passt. Das Wort ist wieder drin. Dafür gibt es jetzt breite.mjs, das eine Formulierung misst, bevor sie in die Datei kommt.

Gedrehte Blätter ragen aus dem Kasten. Der Stapel dreht das hinterste Blatt um 3,2° und verschiebt es um 3 % und 5,5 % der eigenen Größe. Die Ecken stehen damit über das vordere Blatt hinaus, und die Zeichnung lag bis zu 24 px außerhalb der 92-px-Schutzzone. Der Überstand wird jetzt gerechnet statt geschätzt: stapelRand() schickt die vier Ecken durch dieselbe Kette wie das Blatt und nimmt den größten Wert. stapelKasten() macht den Kasten entsprechend größer.

getBBox() kennt keine Beschneidung. Das Absperrband war zuerst auf die 175 % der Website gezogen und per clip-path am Gerät abgeschnitten. Im Bild stimmte das, die Randmessung meldete aber einen Überstand von 146 px, den es gar nicht gab: getBBox() liefert die Geometrie, nicht das Sichtbare. Das Band ist jetzt nur so lang, wie es bei -13° quer über das Gerät sein muss, also B / cos(13°) plus Zugabe. Messung und Bild sagen wieder dasselbe.

Das Prüfskript nahm eine leere Slide auf. schuss.mjs stellte für eine einzelne Slide ein Fenster von 1400 px. Im durchgehenden Blatt liegt Seite 3 aber bei x = 2160, und captureBeyondViewport fing das nicht zuverlässig ab. Die Bühne steht jetzt immer auf 7000 px.