diff --git a/POST-6.md b/POST-6.md index 23bd3f8..065c5ec 100644 --- a/POST-6.md +++ b/POST-6.md @@ -36,7 +36,7 @@ Dazu, außerhalb des Streifens: | Schlüssel | Tag | Überschrift | Was zu sehen ist | |---|---|---|---| -| `animChat` | Bewegtbild | Getippt, **und schon im Projekt.** | 8 s Animation: eine Notiz wird getippt, über das Pluszeichen wird „Aufgabe erstellen" gewählt, und beides geht zusammen als eine Nachricht raus | +| `animChat` | Bewegtbild | Getippt, **und schon im Projekt.** | 6 s Animation: eine Nachricht wird angeklickt, im Menü „Aufgabe erstellen" gewählt, und die Aufgabe klappt in der Nachricht auf | **Slide 3 ist der Kern.** Der Redaktionsplan verlangt „Foto rein, Aufgabe raus", und genau das liegt im Werkzeug als Abfolge vor: Tobias schickt die @@ -324,7 +324,7 @@ violett.** Im Original steht dort `bg-surface-neutral-primary` mit Rand und --- -## 6. Fünfzehn Fallen aus diesem Bau +## 6. Sechzehn 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 @@ -437,69 +437,83 @@ Text und Anhang einander bedingen — die Nachricht meldete eine Aufgabe, die im selben Zug erst entstand. Der Fehler lag nicht in der Quelle, sondern darin, eine Momentaufnahme für eine Reihenfolge zu halten. Mehr dazu in §7. +**Das Pitch-Paket ist ein Stand, nicht das Produkt.** Der zweite Anlauf für die +Animation nahm das Menü hinter dem Pluszeichen, weil `GeneralTeamChatPage.tsx` +den einzigen dort ausgezeichneten Weg zu einer Aufgabe so zeigt. Belegt war das +sauber — Datei, Zeile, Grep über beide Repos und über die Staging-API, die eine +Aufgabe nur mit `contact | company | lead | project` verknüpft und eine +Nachricht als Bezug gar nicht kennt. Trotzdem falsch: im laufenden Team-Chat +hängt an jeder Nachricht ein Menü mit „Aufgabe erstellen". + +Die Lehre ist nicht „schlechter prüfen", sondern **wissen, was eine Quelle +belegt.** Ein Pitch-Paket vom Juli belegt, was im Juli gebaut war. Es belegt +nicht, was das Produkt heute kann. Wo eine Aussage der Website (hier: +„Aus „mach das mal" wird mit einem Klick eine echte Aufgabe") keine Entsprechung +im vorliegenden Code hat, ist das ein Grund nachzufragen und nicht, die Aussage +auf den vorhandenen Code zu biegen. + --- ## 7. Das Bewegtbild -Acht Sekunden, 240 Bilder, `animation/post6-animChat.mp4`. Gezeichnet wird es +Sechs Sekunden, 180 Bilder, `animation/post6-animChat.mp4`. Gezeichnet wird es von `animChat(i, t)` in `post6.html`, mit denselben Bausteinen wie jede Slide — nur bekommt die Funktion neben der Nummer den Fortschritt `t` und leitet daraus alles ab. Der Eintrag steht in `ANIMS`, nicht in `SLIDES`. +**Gezeigt wird der Weg, den das laufende Werkzeug hat:** Nachricht anfassen, +Menü öffnet sich, „Aufgabe erstellen", die Aufgabe klappt in der Nachricht auf, +das Projekt bestätigt sie. Das ist die Funktion, die die Website meint mit +„Aus „mach das mal" wird mit einem Klick eine echte Aufgabe." + | Zeit | Was passiert | |---|---| -| 0,4 – 2,9 s | Die Notiz wird Zeichen für Zeichen ins Eingabefeld getippt, der Cursor blinkt. Sobald Text darin steht, wird aus dem Mikrofon der Senden-Knopf | -| 2,9 – 3,8 s | Der Zeiger fährt auf das Pluszeichen und klickt | -| 3,6 – 4,5 s | Das Menü klappt nach oben auf, die Zeilen gestaffelt | -| 4,5 – 5,8 s | Der Zeiger geht auf „Aufgabe erstellen", die Zeile hebt sich, Klick | -| 5,7 – 6,1 s | Das Menü schließt, das Feld leert sich | -| 5,8 – 6,7 s | Die Nachricht wächst in den Verlauf, Text und Aufgabenkarte zusammen | -| 6,7 – 7,4 s | Die Systemzeile „Aufgabe „Materialliste prüfen" im Projekt erstellt" erscheint | -| 7,4 – 8,0 s | Halt auf dem Ergebnis | +| 0,0 – 0,6 s | Ruhe. Der Verlauf steht: Sandra, Maike, Tobias | +| 0,6 – 1,3 s | Der Zeiger fährt auf Tobias' Nachricht, der Pfeil erscheint an ihr | +| 1,3 – 1,6 s | Klick | +| 1,6 – 2,4 s | Das Menü klappt nach oben auf: Reagieren, Antworten, Im Thread antworten, Anpinnen, Aufgabe erstellen, Bearbeiten, Löschen | +| 2,4 – 3,4 s | Der Zeiger geht auf „Aufgabe erstellen", die Zeile hebt sich, Klick | +| 3,6 – 4,8 s | Das Menü schließt, die Aufgabenkarte klappt in Tobias' Nachricht auf, der Verlauf rutscht nach | +| 4,8 – 5,4 s | Die Systemzeile „Aufgabe „Materialliste prüfen" im Projekt erstellt" erscheint | +| 5,4 – 6,0 s | Halt auf dem Ergebnis | -### Der erste Anlauf hatte den Ablauf falsch herum +### Warum Tobias' Nachricht -Dort wurde die Nachricht „Danke. Ich habe dazu direkt eine Aufgabe erstellt." -getippt, abgeschickt, und **danach** wuchs an ihr eine Aufgabenkarte. Die -Nachricht meldete also eine Aufgabe, die es noch gar nicht gab, und wurde -anschließend selbst zu einer. Ein Kreis, kein Ablauf. - -Nachgesehen in `GeneralTeamChatPage.tsx`: eine Aufgabe entsteht über das Menü -hinter dem Pluszeichen („Aufgabe erstellen", Zeile 275), und das Ergebnis ist -Nachricht `m4` — Text **und** angehängte Aufgabenkarte in einem — gefolgt von -der Systemzeile `m5`. **Ein Kontextmenü an einer bestehenden Nachricht gibt es -dort nicht.** Wer eine Umwandlung „Nachricht → Aufgabe" zeigt, zeigt eine -Funktion, die wir nicht haben, auch wenn die Website den Nutzen so beschreibt -(„Aus „mach das mal" wird mit einem Klick eine echte Aufgabe"). - -Die Reihenfolge ist deshalb: Notiz tippen, Pluszeichen, „Aufgabe erstellen", -und beides geht zusammen als eine Nachricht raus. Der Satz im Perfekt stimmt -dann auch: wenn die Nachricht ankommt, hängt die Aufgabe daran. +Nicht irgendeine: die Aufgabenkarte aus der Quelle trägt **„Tobias Wagner · +offen"** als Zuständigkeit. Wer sie an einer fremden Nachricht entstehen lässt, +muss den Namen erfinden. So bleiben alle vier Felder der Karte +(`square-check`, „Materialliste prüfen · fällig 31.07.2026", „Tobias Wagner · +offen", „Offen") genau die aus `GeneralTeamChatPage.tsx`. ### Vier Entscheidungen - **Der Verlauf hängt am unteren Rand, nicht am oberen.** Damit erzeugt jedes Wachstum das Hochschieben von selbst, ohne eine zweite Rechnung für das - Scrollen. Die drei vorherigen Nachrichten sind dieselben wie auf Slide 1 und - stammen aus `GeneralTeamChatPage.tsx`, nicht aus einem erfundenen Szenario. -- **Sie liegt neben den Slides, nicht darin.** Ein Zwischenstand machte sie zur - sechsten Slide im Streifen. Damit wanderte sie in die Slide-Auswahl, in die - Zählung „Carousel, 6 Slides" und in den Bildexport, der sie als Standbild - mitschrieb. Ein Video, das man nur zusammen mit den Bildern herausbekommt, - ist im Carousel nicht getrennt einsetzbar. + Scrollen. Wenn die Aufgabenkarte aufklappt, rutscht der Verlauf nach. +- **Die Karte wird aufgedeckt, nicht gestaucht.** Sie liegt in voller Größe da + und wird über eine `clipPath` von oben freigegeben. Eine gestauchte Karte + sieht kaputt aus, eine aufgedeckte sieht nach Aufklappen aus. - **Der Mauszeiger ist erzählerisches Mittel, kein Bestandteil des Werkzeugs.** - Ohne ihn sieht man ein Menü aufgehen und weiß nicht, warum. Er ist weiß mit - dunkler Kante, damit er auf dem Verlauf wie auf dem Menü liest, und geht - nach dem zweiten Klick zügig weg — ein Zeiger, der ohne Aufgabe über dem - Verlauf stehen bleibt, zieht den Blick von der ankommenden Nachricht ab. -- **Am Ende wird nichts zurückgenommen.** Der erste Anlauf blendete die neue + Ohne ihn öffnet sich ein Menü und man weiß nicht, warum. Weiß mit dunkler + Kante, damit er auf Verlauf wie Menü liest, und nach dem zweiten Klick zügig + weg — sonst zieht er den Blick von der aufklappenden Aufgabe ab. +- **Am Ende wird nichts zurückgenommen.** Ein früherer Stand blendete die neue Nachricht wieder aus, damit der Schleifenstoß unsichtbar wird. Das sah aus, als lösche sich eine abgeschickte Nachricht von selbst. Eine Schleife darf - springen, eine Nachricht darf nicht verschwinden. + springen. -Kein Text und keine Uhrzeit ist für die Animation erfunden worden. Getippt wird -`VERLAUF[3].text`, also genau die Nachricht, die im Werkzeug an dieser Stelle -steht. +### Zur Länge -Nachgeprüft mit `ffprobe`: H.264 High, `yuv420p`, 1080 × 1350, 30 fps, 240 -Bilder, Dauer exakt 8,000000 s, stumme AAC-Spur, `moov` am Dateianfang, 1,5 MB. +Instagram nimmt je Carousel-Element **3 bis 60 Sekunden** an. Sechs liegt weit +von beiden Grenzen weg; die Länge richtet sich also allein nach dem Ablauf. +Vier Schritte — anfassen, wählen, aufklappen, bestätigen — brauchen etwa so +lange. Eine kurze Schleife wiederholt sich außerdem öfter, während jemand liest. +Eine Zwischenfassung lief acht Sekunden, weil dort zusätzlich eine Nachricht +getippt wurde; das fällt mit dem richtigen Weg weg. + +Die Symbole im Menü sind unsere Strichsymbole. Im Werkzeug steht bei +„Reagieren" ein Emoji; ein Emoji zwischen sechs Strichsymbolen bricht die +Bildsprache, und die Slides tragen durchgehend Feather-Symbole. + +Nachgeprüft mit `ffprobe`: H.264 High, `yuv420p`, 1080 × 1350, 30 fps, 180 +Bilder, Dauer exakt 6,000000 s, stumme AAC-Spur, `moov` am Dateianfang, 1,1 MB. diff --git a/README.md b/README.md index 522fcd3..81ada51 100644 --- a/README.md +++ b/README.md @@ -374,7 +374,7 @@ ist sie ein eigenes Element, und ob sie mitkommt, entscheidest du beim Posten. ```js const ANIMS = [ - { key: "animChat", type: "feature", dauer: 8, + { key: "animChat", type: "feature", dauer: 6, eyebrow: "Bewegtbild", head: 'Getippt,
und schon im Projekt.', body: "Eine Nachricht, ein Klick, und die Aufgabe hängt am richtigen Projekt.", diff --git a/animation/post6-animChat.mp4 b/animation/post6-animChat.mp4 index ebec3ea..c0b0463 100644 Binary files a/animation/post6-animChat.mp4 and b/animation/post6-animChat.mp4 differ diff --git a/post6.html b/post6.html index b2bb3c7..5d53b8b 100644 --- a/post6.html +++ b/post6.html @@ -1464,12 +1464,12 @@ if (location.search.indexOf("nur=anim") >= 0) ist `dauer` und der zweite Wert t, den die Zeichenfunktion bekommt. */ const ANIMS = [ { - /* Acht Sekunden. Fuenf waren zu knapp, sobald der Ablauf stimmt: - tippen, Menue, waehlen, abschicken, bestaetigen -- das sind fuenf - Schritte, und jeder braucht seinen Moment. Unter drei Sekunden nimmt - Instagram ein Video im Carousel gar nicht erst an, nach oben sind - sechzig erlaubt. */ - key: "animChat", type: "feature", dauer: 8, + /* Sechs Sekunden. Instagram nimmt im Carousel drei bis sechzig an; das + ist also weit von jeder Grenze weg, und die Laenge richtet sich + allein nach dem Ablauf. Vier Schritte -- anfassen, waehlen, + aufklappen, bestaetigen -- brauchen etwa so lange, und eine kurze + Schleife wiederholt sich oefter, waehrend jemand liest. */ + key: "animChat", type: "feature", dauer: 6, eyebrow: "Bewegtbild", head: 'Getippt,
und schon im Projekt.', body: "Eine Nachricht, ein Klick, und die Aufgabe hängt am richtigen Projekt.", @@ -2051,6 +2051,12 @@ if (location.search.indexOf("nur=anim") >= 0) "workflow": '', "x": '', "zap": '', + /* Fuer das Menue an der Nachricht, aus dem laufenden Team-Chat. */ + "thumbs-up": '', + "corner-up-left": '', + "pencil": '', + "trash-2": '', + "chevron-down": '', "rocket": '' }; @@ -2703,12 +2709,19 @@ if (location.search.indexOf("nur=anim") >= 0) const innen = (max || BLASE_MAX) - 32; const zeilen = m.text ? umbrechen(m.text, innen, 17, 400) : []; const innenB = (max || BLASE_MAX) - 32; + /* Eine Blase kann eine zweite Anhangkarte tragen: die Aufgabe, die aus + ihr entstanden ist. `a2` ist ihr Anteil zwischen 0 und 1 -- damit + waechst die Blase mit, waehrend die Karte aufklappt, und der ganze + Verlauf rutscht von selbst nach. */ + const f2 = m.anhang2 ? (m.a2 == null ? 1 : m.a2) : 0; let h = 14 + (m.mein ? 0 : 22) + zeilen.length * 25 + - (m.anhang ? anhangHoehe(m.anhang, innenB) + 8 : 0) + 24; + (m.anhang ? anhangHoehe(m.anhang, innenB) + 8 : 0) + + (f2 > 0 ? (anhangHoehe(m.anhang2, innenB) + 8) * f2 : 0) + 24; let b = 32 + Math.max( ...zeilen.map(z => messen(z, 17, 400)), m.mein ? 0 : messen(m.autor, 14, 800), - m.anhang ? anhangNoetig(m.anhang) : 0, 90); + m.anhang ? anhangNoetig(m.anhang) : 0, + m.anhang2 ? anhangNoetig(m.anhang2) : 0, 90); return { zeilen, hoehe: Math.round(h), breite: Math.round(Math.min(b, max || BLASE_MAX)) }; } @@ -2717,6 +2730,7 @@ if (location.search.indexOf("nur=anim") >= 0) als die Rechnung ein zweites Mal zu fuehren und sie auseinanderlaufen zu lassen. */ let letzterAnhang = null; + let klappNr = 0; function blase(x, y, b, m) { // Die Systemmeldung ist keine Blase, sondern eine Zeile in der Mitte. @@ -2762,6 +2776,21 @@ if (location.search.indexOf("nur=anim") >= 0) m.anhang[2], m.anhang[3]); cy += ah + 8; } + /* Die zweite Karte klappt auf: sie wird von oben freigegeben, nicht + gestaucht -- eine gestauchte Karte sieht kaputt aus, eine + aufgedeckte sieht nach Aufklappen aus. */ + const f2 = m.anhang2 ? (m.a2 == null ? 1 : m.a2) : 0; + if (f2 > .004) { + const ah = anhangHoehe(m.anhang2, ma.breite - 32); + const sicht = ah * f2; + const id = "anhklapp" + (++klappNr); + g += '' + + '' + + anhangKarte(bx + 16, cy + 4, ma.breite - 32, m.anhang2[0], m.anhang2[1], + m.anhang2[2], m.anhang2[3]) + ''; + cy += sicht + 8 * f2; + } g += uiText(bx + ma.breite - 16, cy + 16, m.zeit + (m.mein ? " ✓✓" : ""), 13, 500, CHAT_TEXT3, { anker: "end" }); return g; @@ -3265,127 +3294,120 @@ if (location.search.indexOf("nur=anim") >= 0) /* ─── Das Bewegtbild ──────────────────────────────────────────────────── - Wie aus einer Nachricht eine echte Aufgabe wird, in dem Weg, den das - Werkzeug tatsaechlich hat. + Wie aus einer Nachricht eine echte Aufgabe wird -- der Weg, den das + laufende Werkzeug hat: Nachricht anklicken, Menue oeffnet sich, + "Aufgabe erstellen". - Das ist der Kern, und ein erster Anlauf hatte ihn falsch: dort wurde die - Nachricht "Danke. Ich habe dazu direkt eine Aufgabe erstellt." getippt, - abgeschickt -- und *dann* wuchs an ihr eine Aufgabenkarte. Die Nachricht - meldete also eine Aufgabe, die es noch gar nicht gab, und wurde - anschliessend selbst zu einer. Ein Kreis, kein Ablauf. + Zwei Anlaeufe lagen davor daneben, beide aus derselben Ursache. Der + erste liess die Nachricht "Danke. Ich habe dazu direkt eine Aufgabe + erstellt." tippen und danach eine Aufgabenkarte an ihr wachsen -- sie + meldete also eine Aufgabe, die es noch nicht gab, und wurde dann selbst + zu einer. Der zweite nahm das Menue hinter dem Pluszeichen, weil das im + Pitch-Paket der einzige Weg ist, der dort ausgezeichnet ist. - Nachgesehen in GeneralTeamChatPage.tsx: eine Aufgabe entsteht ueber das - Menue hinter dem Pluszeichen ("Aufgabe erstellen", Zeile 275), und das - Ergebnis ist Nachricht m4 -- Text *und* angehaengte Aufgabenkarte in - einem -- gefolgt von der Systemzeile m5. Ein Kontextmenue an einer - bestehenden Nachricht gibt es dort nicht; wer eine Umwandlung zeigt, - zeigt eine Funktion, die wir nicht haben. + Beides war zu wenig geprueft. Das Pitch-Paket ist ein Stand vom Juli; + im laufenden Team-Chat haengt an jeder Nachricht ein Menue mit + Reagieren, Antworten, Im Thread antworten, Anpinnen, Aufgabe erstellen, + Bearbeiten, Loeschen. Das ist die Funktion, die die Website meint, wenn + sie schreibt: "Aus 'mach das mal' wird mit einem Klick eine echte + Aufgabe." - Also die richtige Reihenfolge: Notiz tippen, Pluszeichen, "Aufgabe - erstellen", und beides geht zusammen als eine Nachricht raus. Der Satz - im Perfekt stimmt dann auch -- wenn die Nachricht ankommt, haengt die - Aufgabe daran. + Gewaehlt wird Tobias' Nachricht, nicht irgendeine: die Aufgabenkarte aus + der Quelle traegt "Tobias Wagner · offen" als Zustaendigkeit. Wer sie an + einer fremden Nachricht entstehen laesst, muss den Namen erfinden. - Der Ablauf, in Anteilen der Laufzeit (8 s): + Der Ablauf, in Anteilen der Laufzeit (6 s): - 0,00 - 0,05 ruhig, der Verlauf steht, das Feld ist leer - 0,05 - 0,36 die Notiz wird getippt, Zeichen fuer Zeichen - 0,36 - 0,45 der Zeiger faehrt auf das Pluszeichen und klickt - 0,45 - 0,56 das Menue klappt nach oben auf, die Zeilen gestaffelt - 0,56 - 0,71 der Zeiger geht auf "Aufgabe erstellen" und klickt - 0,71 - 0,76 das Menue schliesst, das Feld leert sich - 0,72 - 0,84 die Nachricht mit der Aufgabenkarte waechst in den Verlauf - 0,84 - 0,92 die Bestaetigung im Projekt erscheint - 0,92 - 1,00 Halt auf dem Ergebnis + 0,00 - 0,10 ruhig, der Verlauf steht + 0,10 - 0,22 der Zeiger faehrt auf die Nachricht, der Pfeil erscheint + 0,22 - 0,27 Klick + 0,26 - 0,40 das Menue klappt auf, die Zeilen gestaffelt + 0,40 - 0,56 der Zeiger geht auf "Aufgabe erstellen", die Zeile hebt sich + 0,56 - 0,61 Klick + 0,60 - 0,66 das Menue schliesst, der Zeiger geht + 0,62 - 0,80 die Aufgabenkarte klappt in der Nachricht auf + 0,80 - 0,90 die Bestaetigung im Projekt erscheint + 0,90 - 1,00 Halt auf dem Ergebnis - Am Ende wird nichts zurueckgenommen. Der Vorgaenger blendete die neue - Nachricht wieder aus, damit der Schleifenstoss unsichtbar wird -- das - sah aus, als loesche sich eine abgeschickte Nachricht von selbst. Eine - Schleife darf springen, eine Nachricht darf nicht verschwinden. */ - const ANIM_NOTIZ = VERLAUF[3].text; + Am Ende wird nichts zurueckgenommen. Ein frueherer Stand blendete die + Aufgabe wieder aus, damit der Schleifenstoss unsichtbar wird -- das sah + aus, als loesche sie sich von selbst. Eine Schleife darf springen. */ + + /* Das Menue an der Nachricht, aus dem laufenden Team-Chat. Reihenfolge und + Beschriftung wie dort; die Symbole sind unsere, weil dort ein Emoji + steht und wir durchgehend Strichsymbole benutzen. */ + const NACHRICHT_MENUE = [ + ["thumbs-up", "Reagieren"], + ["corner-up-left", "Antworten"], + ["message-square", "Im Thread antworten"], + ["pin", "Anpinnen"], + ["square-check", "Aufgabe erstellen"], + ["pencil", "Bearbeiten"], + ["trash-2", "Löschen"], + ]; + const MENUE_ZIEL = 4; // "Aufgabe erstellen" + + /* Die Aufgabe, die daraus entsteht. Alle vier Felder stehen so in + GeneralTeamChatPage.tsx an der Nachricht m4. */ + const ANIM_AUFGABE = ["square-check", "Materialliste prüfen · fällig 31.07.2026", + "Tobias Wagner · offen", "Offen"]; - /* Der Mauszeiger. Kein Bestandteil des Werkzeugs, sondern das Mittel, mit - dem eine Bedienung erzaehlt wird -- ohne ihn sieht man ein Menue - aufgehen und weiss nicht, warum. Weiss mit dunkler Kante, damit er auf - dem Verlauf wie auf dem Menue liest. */ const zeiger = (x, y, gr) => '' + ''; - /* Der Klick: ein Ring, der einmal aufgeht und dabei verschwindet. */ const klickRing = (x, y, p) => p <= 0 || p >= 1 ? "" : ''; - /* Das Menue hinter dem Pluszeichen, aus GeneralTeamChatPage.tsx Zeile 275. - Dieselben sieben Eintraege und derselbe Trenner wie auf Slide 4, nur - kleiner gesetzt: hier haengt es im Fenster und steht nicht allein auf - der Slide. side="top" align="start" heisst, es klappt nach oben auf und - sitzt links am Knopf. */ - function animMenue(ax, ay, auf, hoverNr) { - const MW = 306, ZH = 34, PAD = 9, TRENN = 11; - const hoehe = 2 * PAD + MENUE.reduce((a, e) => a + (e ? ZH : TRENN), 0); - const x = ax, y = ay - hoehe; + /* Es klappt nach oben auf, weil die Nachricht unten im Fenster haengt -- + nach unten waere kein Platz, und ein Menue dreht dort um. */ + function animMenue(rechtsX, untenY, auf, hoverNr) { + const MW = 262, ZH = 34, PAD = 8; + const hoehe = 2 * PAD + NACHRICHT_MENUE.length * ZH; + const x = rechtsX - MW, y = untenY - hoehe; let g = ""; - let yy = y + PAD, nr = 0; - for (const e of MENUE) { - if (!e) { - g += ''; - yy += TRENN; continue; - } - /* Die gewaehlte Zeile bekommt den Grund, den sie im Werkzeug beim - Ueberfahren bekommt: hover:bg-surface-neutral-tertiary. */ + NACHRICHT_MENUE.forEach((e, nr) => { + const yy = y + PAD + nr * ZH; if (nr === hoverNr) g += ''; g += feather(e[0], x + PAD + 18, yy + ZH / 2, 16, CHAT_TEXT2, 1.9); g += uiText(x + PAD + 36, yy + ZH / 2 + 5.5, e[1], 15, 500, CHAT_TEXT); - yy += ZH; nr++; - } + }); - /* Es faehrt aus dem Knopf heraus auf: von unten links skaliert, damit es - am Pluszeichen zu haengen scheint. */ const sk = .94 + .06 * auf; - return { hoehe, html: - '' + - '' + - g + '', - // Mitte der Zeile "Aufgabe erstellen", fuer den Zeiger. - zielY: y + PAD + 5 * ZH + TRENN + ZH / 2, zielX: x + MW / 2 }; + return { hoehe, + zielX: x + PAD + 30, + zielY: y + PAD + MENUE_ZIEL * ZH + ZH / 2, + html: + '' + + '' + + g + '' }; } function animChat(j, t) { - /* 620 x 740: hoeher waere das Fenster oben leer, weil der Verlauf unten - haengt, und die Slide stiesse an den Fliesstext. Was nicht mehr - hineinpasst, schiebt sich oben hinaus -- so macht es ein Chat auch. */ const B = 620, H = 740, RAND = 22, KOPF = 74, FELD = 96; const innenB = B - 2 * RAND; const bahnO = KOPF + 8, bahnU = H - FELD - 8; - const dauer = (ANIMS[j] && ANIMS[j].dauer) || 8; - const tippen = stufe(t, .05, .36); - const zeigerAn = stufe(t, .36, .43); // Zeiger faehrt zum Plus - const klick1 = stufe(t, .43, .48); - const auf = daempfen(stufe(t, .45, .56)); // Menue klappt auf - const wandern = daempfen(stufe(t, .56, .68)); // Zeiger zur Zeile - const klick2 = stufe(t, .68, .73); - const zu = daempfen(stufe(t, .71, .76)); // Menue schliesst - /* Die Blase setzt an, waehrend sich das Feld leert. Ein Zwischenstand - hatte dazwischen eine Viertelsekunde Leere: die Notiz war weg, die - Nachricht noch nicht da -- das las sich, als sei sie verschluckt - worden. Die beiden Bewegungen greifen jetzt ineinander. */ - const wachsen = daempfen(stufe(t, .72, .84)); // Nachricht kommt herein - const system = daempfen(stufe(t, .84, .92)); - - const menueAn = Math.max(0, auf - zu); + const zeigerAn = stufe(t, .10, .22); + const pfeil = daempfen(stufe(t, .16, .24)); // der Pfeil an der Blase + const klick1 = stufe(t, .22, .27); + const auf = daempfen(stufe(t, .26, .40)); + const wandern = daempfen(stufe(t, .40, .54)); + const klick2 = stufe(t, .56, .61); + const zu = daempfen(stufe(t, .60, .66)); + const klappen = daempfen(stufe(t, .62, .80)); // die Aufgabe klappt auf + const system = daempfen(stufe(t, .80, .90)); + const menueAn = Math.max(0, auf - zu); let g = ""; @@ -3397,110 +3419,86 @@ if (location.search.indexOf("nur=anim") >= 0) g += uiText(RAND + 52, RAND + 30, "P-2026-0042 · 8 Mitglieder · aktiv", 15, 500, CHAT_TEXT3); g += ''; - /* Der Verlauf haengt unten. Waechst er, schiebt er sich nach oben aus dem - Fenster -- so entsteht das Scrollen von selbst, ohne eigenen Zaehler. */ - const alt = [VERLAUF[0], VERLAUF[1], VERLAUF[2]]; - const neu = VERLAUF[3], sys = VERLAUF[4]; - + /* Der Verlauf haengt unten. Waechst die Blase, schiebt er sich nach oben + aus dem Fenster -- so entsteht das Scrollen von selbst. */ const spalte = innenB; - const hAlt = alt.map(m => blaseHoehe(m, spalte)); - const hNeu = blaseHoehe(neu, spalte) * wachsen; + const m1 = VERLAUF[0], m2 = VERLAUF[1]; + // Tobias' Nachricht bekommt die Aufgabe, die aus ihr entsteht. + const m3 = Object.assign({}, VERLAUF[2], { anhang2: ANIM_AUFGABE, a2: klappen }); + const sys = VERLAUF[4]; + + const h1 = blaseHoehe(m1, spalte), h2 = blaseHoehe(m2, spalte); + const h3 = blaseHoehe(m3, spalte); const hSys = blaseHoehe(sys, spalte) * system; const LUFT = 16; - const gesamt = hAlt.reduce((a, h) => a + h + LUFT, 0) + - (wachsen > .01 ? hNeu + LUFT : 0) + (system > .01 ? hSys + LUFT : 0); + const gesamt = h1 + h2 + h3 + 3 * LUFT + (system > .01 ? hSys + LUFT : 0); let y = bahnU - gesamt; let bahn = ""; - alt.forEach((m, i) => { bahn += blase(RAND, y, spalte, m); y += hAlt[i] + LUFT; }); + bahn += blase(RAND, y, spalte, m1); y += h1 + LUFT; + bahn += blase(RAND, y, spalte, m2); y += h2 + LUFT; + + /* Die gewaehlte Nachricht. Ihre Lage wird gemerkt, damit Pfeil, Zeiger + und Menue daran haengen und nicht an einer zweiten Rechnung. */ + const dritteY = y; + const ma3 = blaseMasse(m3, blaseBreite(spalte)); + const bx3 = RAND + 52, br3 = ma3.breite; + bahn += blase(RAND, y, spalte, m3); + y += h3 + LUFT; - if (wachsen > .01) { - /* Sie kommt von unten und richtet sich auf: skaliert um den eigenen - unteren Rand, damit sie aus dem Eingabefeld heraus zu wachsen - scheint und nicht aus der Mitte heraus aufplatzt. Text und - Aufgabenkarte kommen zusammen -- es ist eine Nachricht, und der - Klick auf "Aufgabe erstellen" hat beides erzeugt. */ - const sk = .88 + .12 * wachsen; - bahn += '' + - blase(RAND, y, spalte, neu) + ''; - y += hNeu + LUFT; - } if (system > .01) { bahn += '' + blase(RAND, y, spalte, sys) + ''; } + /* Der Pfeil an der Blase, wie im Werkzeug: er erscheint, sobald die + Nachricht angefasst wird, und sitzt oben rechts in ihr. */ + if (pfeil > .01 && zu < .5) { + const px = bx3 + br3 - 18, py = dritteY + 16; + bahn += '' + + '' + + feather("chevron-down", px, py + 1, 14, CHAT_TEXT2, 2.2) + ''; + } + // Was ueber die Bahn hinausragt, wird oben abgeschnitten -- wie im Fenster. g += ''; g += '' + bahn + ''; - /* Das Eingabefeld. Waehrend des Tippens laeuft der Text mit, dahinter - blinkt der Strich; sobald etwas drinsteht, wird aus dem Mikrofon der - Sendeknopf -- so macht es der Composer auch. */ + // Das Eingabefeld bleibt ruhig: hier wird nichts geschrieben. const fy = H - FELD; - const plusX = RAND + 14, plusY = fy + 44; g += ''; - g += feather("plus", plusX, plusY, 21, menueAn > .3 ? CHAT_TEXT : CHAT_TEXT2, 2); + g += feather("plus", RAND + 14, fy + 44, 21, CHAT_TEXT2, 2); const feldX = RAND + 36, feldB = B - 2 * RAND - 100; g += ''; + g += uiText(feldX + 18, fy + 50, "Nachricht schreiben …", 16, 400, "#C9C9CE"); + g += feather("mic", B - RAND - 24, fy + 44, 21, CHAT_TEXT2, 2); - // Nach dem Klick auf "Aufgabe erstellen" geht die Notiz mit raus. - const abgeschickt = zu > .45; - const zeichen = Math.round(ANIM_NOTIZ.length * tippen); - const getippt = abgeschickt ? "" : ANIM_NOTIZ.slice(0, zeichen); - if (getippt) { - const passt = umbrechen(getippt, feldB - 44, 16, 400, 1)[0]; - g += uiText(feldX + 18, fy + 50, passt, 16, 400, CHAT_TEXT); - // Der Strich blinkt zweimal je Sekunde, gerechnet auf die Laufzeit. - if (tippen < 1 && Math.floor(t * dauer * 2) % 2 === 0) { - const bx = feldX + 20 + messen(passt, 16, 400); - g += ''; - } - } else { - g += uiText(feldX + 18, fy + 50, "Nachricht schreiben …", 16, 400, "#C9C9CE"); - } - if (getippt) { - const px = B - RAND - 24; - g += ''; - g += feather("send", px - 1, plusY, 18, "#FFFFFF", 2); - } else { - g += feather("mic", B - RAND - 24, plusY, 21, CHAT_TEXT2, 2); - } + /* Das Menue haengt am Pfeil und liegt ueber allem. */ + const chevX = bx3 + br3 - 18, chevY = dritteY + 16; + const m = animMenue(chevX + 14, chevY - 16, Math.max(auf, .001), + wandern > .55 && menueAn > .2 ? MENUE_ZIEL : -1); + /* Unter drei Prozent ist es kein Aufblenden mehr, sondern ein Schemen + ueber dem Verlauf. Dann lieber gar nichts. */ + if (menueAn > .03) g += m.html; - /* Das Menue liegt ueber allem, auch ueber dem Eingabefeld -- es haengt am - Pluszeichen und klappt nach oben auf. Die Zeile "Aufgabe erstellen" - hebt sich, sobald der Zeiger dort angekommen ist. */ - const m = animMenue(RAND + 2, fy - 6, Math.max(auf, .001), - wandern > .55 && menueAn > .2 ? 5 : -1); - if (menueAn > .01) g += m.html; - - /* Der Zeiger. Er kommt von rechts unten herein, faehrt auf das - Pluszeichen, spaeter auf die Zeile, und geht nach dem zweiten Klick - wieder hinaus. */ - /* Nach dem zweiten Klick geht er zuegig weg. Ein Zeiger, der ohne - Aufgabe ueber dem Verlauf stehen bleibt, zieht den Blick auf sich, - waehrend gerade die Nachricht ankommt. */ - const zWeg = stufe(t, .72, .77); + /* Der Zeiger: herein auf den Pfeil, dann auf die Zeile, dann weg. */ + const zWeg = stufe(t, .61, .67); const zAn = zeigerAn * (1 - zWeg); if (zAn > .01) { - const vonX = B - 70, vonY = H + 40; + const vonX = B - 60, vonY = H + 40; const p1 = daempfen(zeigerAn); - let zx = vonX + (plusX + 2 - vonX) * p1; - let zy = vonY + (plusY + 2 - vonY) * p1; + let zx = vonX + (chevX - 2 - vonX) * p1; + let zy = vonY + (chevY - 2 - vonY) * p1; if (wandern > 0) { - const p2 = wandern; - zx += (m.zielX - 40 - zx) * p2; - zy += (m.zielY - 6 - zy) * p2; + zx += (m.zielX - zx) * wandern; + zy += (m.zielY - 4 - zy) * wandern; } - g += klickRing(zx - 2, zy - 2, klick1 < 1 ? klick1 : 0); - g += klickRing(zx - 2, zy - 2, klick2 < 1 && klick2 > 0 ? klick2 : 0); + g += klickRing(zx + 2, zy + 2, klick1 < 1 ? klick1 : 0); + g += klickRing(zx + 2, zy + 2, klick2 > 0 && klick2 < 1 ? klick2 : 0); g += '' + zeiger(zx, zy, 1.5) + ''; }