Bewegtbild: der richtige Weg von der Nachricht zur Aufgabe

Die erste Fassung hatte den Ablauf im Kreis: getippt wurde "Danke. Ich habe
dazu direkt eine Aufgabe erstellt.", abgeschickt -- und *danach* wuchs an
dieser Nachricht eine Aufgabenkarte. Sie meldete also eine Aufgabe, die es
noch gar nicht gab, und wurde anschliessend selbst zu einer.

Nachgesehen in GeneralTeamChatPage.tsx: eine Aufgabe entsteht ueber das Menue
hinter dem Pluszeichen ("Aufgabe erstellen", Zeile 275). 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; eine Umwandlung "Nachricht -> Aufgabe" zu zeigen waere eine Funktion,
die wir nicht haben.

Jetzt also: Notiz tippen, Pluszeichen, "Aufgabe erstellen" waehlen, und beides
geht zusammen als eine Nachricht raus, danach die Bestaetigung im Projekt. Der
Satz im Perfekt stimmt damit auch -- wenn die Nachricht ankommt, haengt die
Aufgabe daran.

Am Ende wird nichts mehr 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.

Dazu ein Mauszeiger, der die Bedienung erzaehlt -- ohne ihn geht ein Menue
auf und man weiss nicht, warum -- und acht statt fuenf Sekunden: der Ablauf
hat jetzt fuenf Schritte, und jeder braucht seinen Moment.

Was ein Standbild traegt, traegt eine Animation nicht automatisch mit: auf
Slide 3 liest sich dieselbe Nachricht einwandfrei, weil dort ein Zustand steht
und keine Reihenfolge.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
dejanandClaude Opus 5 committed 2026-08-26 00:09:45 +02:00
1 parent 9e8b2ea607
commit d4feaa175b
4 files changed
+231 -88

No files matched your search

+55 -20
View File
@@ -36,7 +36,7 @@ Dazu, außerhalb des Streifens:
| Schlüssel | Tag | Überschrift | Was zu sehen ist |
|---|---|---|---|
| `animChat` | Bewegtbild | Getippt, **und schon im Projekt.** | 5 s Animation: die Nachricht wird geschrieben, abgeschickt und landet mit ihrer Aufgabe im Verlauf |
| `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 |
**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. Vierzehn Fallen aus diesem Bau
## 6. Fünfzehn 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
@@ -429,42 +429,77 @@ Spalte aus zwei Zeilen — oben eine neu eingezogene `#stageflaeche` mit Scrolle
und Fußleiste, darunter die Leiste. Eingezogen wird sie beim Start per Skript,
damit der HTML-Rumpf jeder Datei unverändert bleibt.
**Eine Animation deckt auf, was ein Standbild verdeckt.** Auf Slide 3 steht
die Nachricht „Danke. Ich habe dazu direkt eine Aufgabe erstellt." mit
angehängter Aufgabenkarte, und das liest sich einwandfrei: ein Zustand, eine
Momentaufnahme. Sobald derselbe Inhalt einen Ablauf bekommt, fällt auf, dass
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.
---
## 7. Das Bewegtbild
Fünf Sekunden, 150 Bilder, `animation/post6-animChat.mp4`. Gezeichnet wird es
Acht Sekunden, 240 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`.
| Zeit | Was passiert |
|---|---|
| 0,3 – 2,2 s | Die Antwort wird Zeichen für Zeichen ins Eingabefeld getippt, der Cursor blinkt. Sobald Text darin steht, wird aus dem Mikrofon der Senden-Knopf |
| 2,2 – 2,5 s | Das Feld leert sich |
| 2,4 – 3,3 s | Die Blase wächst von unten in den Verlauf, der Verlauf schiebt sich nach oben |
| 3,2 – 4,0 s | Die Aufgabenkarte klappt in der Blase auf, die Blase wächst mit |
| 3,9 – 4,6 s | Die Systemzeile „Aufgabe „Materialliste prüfen" im Projekt erstellt" erscheint darunter |
| 4,6 – 5,0 s | Alles blendet zurück auf den Anfangsstand, damit die Schleife schließt |
| 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 |
Vier Entscheidungen dahinter:
### Der erste Anlauf hatte den Ablauf falsch herum
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.
### 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 erster Anlauf machte sie zur
- **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 aber nicht getrennt einsetzbar.
- **Getippt wird ein Satz, der ohnehin im Verlauf steht.** `ANIM_TIPP` ist
`VERLAUF[3].text` — die Nachricht, die im Werkzeug an dieser Stelle folgt.
Kein Text ist für die Animation erfunden worden, auch keine Uhrzeit.
- **Das letzte Bild ist nicht das erste.** Der Fortschritt läuft über
`t = n / anzahl`; bei `n / (anzahl − 1)` wären Anfang und Ende dasselbe Bild
und der Stoß der Schleife stünde eine Dreißigstelsekunde still.
ist im Carousel nicht getrennt einsetzbar.
- **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
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.
Nachgeprüft mit `ffprobe`: H.264 High, `yuv420p`, 1080 × 1350, 30 fps, Dauer
exakt 5,000000 s, stumme AAC-Spur, `moov` am Dateianfang, 1,1 MB.
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.
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.
+1 -1
View File
@@ -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: 5,
{ key: "animChat", type: "feature", dauer: 8,
eyebrow: "Bewegtbild",
head: 'Getippt,<br><span class="a">und schon im Projekt.</span>',
body: "Eine Nachricht, ein Klick, und die Aufgabe hängt am richtigen Projekt.",
Binary file not shown.
+175 -67
View File
@@ -1464,9 +1464,12 @@ if (location.search.indexOf("nur=anim") >= 0)
ist `dauer` und der zweite Wert t, den die Zeichenfunktion bekommt. */
const ANIMS = [
{
/* Fuenf Sekunden: unter drei nimmt Instagram ein Video im Carousel
nicht an, ueber sechs verliert eine Schleife ihren Reiz. */
key: "animChat", type: "feature", dauer: 5,
/* 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,
eyebrow: "Bewegtbild",
head: 'Getippt,<br><span class="a">und schon im Projekt.</span>',
body: "Eine Nachricht, ein Klick, und die Aufgabe hängt am richtigen Projekt.",
@@ -3261,29 +3264,103 @@ if (location.search.indexOf("nur=anim") >= 0)
}
/* ─── Slide 6 · Die Animation ────────────────────────────────────────────
Eine Nachricht entsteht: getippt, abgeschickt, und aus ihr wird eine
Aufgabe im Projekt. Darueber liegen drei Beitraege, die schon da waren --
man sieht also einen laufenden Verlauf und nicht ein leeres Fenster.
/* ─── Das Bewegtbild ────────────────────────────────────────────────────
Wie aus einer Nachricht eine echte Aufgabe wird, in dem Weg, den das
Werkzeug tatsaechlich hat.
Alle Texte sind dieselben wie auf Slide 1 und 3, aus INITIAL_MESSAGES.
Eine Animation ist kein Anlass, etwas zu erfinden.
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.
Der Ablauf, in Anteilen der Laufzeit:
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.
0,00 - 0,06 ruhig, der Verlauf steht, das Feld ist leer
0,06 - 0,44 die Nachricht wird getippt, Zeichen fuer Zeichen
0,44 - 0,50 abgeschickt: das Feld leert sich
0,48 - 0,66 die Blase waechst von unten herein, der Verlauf rutscht hoch
0,64 - 0,80 die Aufgabenkarte darin blendet auf
0,78 - 0,92 die Bestaetigung erscheint, der Verlauf rutscht nach
0,92 - 1,00 zurueck auf Anfang
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.
Der letzte Abschnitt ist wichtig: im Carousel laeuft so ein Bild in
Schleife, und ein harter Schnitt zurueck faellt auf. Deshalb blenden die
beiden neuen Teile am Ende wieder aus und der Verlauf faehrt zurueck --
das letzte Bild ist damit dasselbe wie das erste. */
const ANIM_TIPP = VERLAUF[3].text;
Der Ablauf, in Anteilen der Laufzeit (8 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
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;
/* 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) =>
'<g transform="translate(' + n1(x) + ',' + n1(y) + ') scale(' + n1(gr) + ')" ' +
'filter="url(#hgklein)">' +
'<path d="M0,0 L0,17.5 L4.3,13.4 L7,19.4 L10.1,18 L7.4,12.2 L13,12.2 Z" ' +
'fill="#FFFFFF" stroke="#24242B" stroke-width="1.5" stroke-linejoin="round"/></g>';
/* Der Klick: ein Ring, der einmal aufgeht und dabei verschwindet. */
const klickRing = (x, y, p) => p <= 0 || p >= 1 ? "" :
'<circle cx="' + n1(x) + '" cy="' + n1(y) + '" r="' + n1(7 + 17 * p) +
'" fill="none" stroke="#24242B" stroke-width="' + n1(2.4 * (1 - p)) +
'" opacity="' + n1(.55 * (1 - p)) + '"/>';
/* 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;
let g = "";
let yy = y + PAD, nr = 0;
for (const e of MENUE) {
if (!e) {
g += '<path d="M' + n1(x + PAD + 4) + ',' + n1(yy + TRENN / 2) + 'H' +
n1(x + MW - PAD - 4) + '" stroke="' + CHAT_RAND + '" stroke-width="1.1"/>';
yy += TRENN; continue;
}
/* Die gewaehlte Zeile bekommt den Grund, den sie im Werkzeug beim
Ueberfahren bekommt: hover:bg-surface-neutral-tertiary. */
if (nr === hoverNr)
g += '<rect x="' + n1(x + PAD - 1) + '" y="' + n1(yy) + '" width="' +
n1(MW - 2 * PAD + 2) + '" height="' + ZH + '" rx="7" fill="' + FL_SPALTE + '"/>';
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 opacity="' + n1(Math.min(1, auf * 3.2)) + '" transform="translate(' +
n1(x) + ',' + n1(ay) + ') scale(' + n1(sk) + ') translate(' + n1(-x) + ',' +
n1(-ay) + ')">' +
'<g filter="url(#hgschatten)"><path d="' + rundRechteck(x, y, MW, hoehe, 14) +
'" fill="#FFFFFF" stroke="' + CHAT_RAND + '" stroke-width="1.2"/></g>' +
g + '</g>',
// Mitte der Zeile "Aufgabe erstellen", fuer den Zeiger.
zielY: y + PAD + 5 * ZH + TRENN + ZH / 2, zielX: x + MW / 2 };
}
function animChat(j, t) {
/* 620 x 740: hoeher waere das Fenster oben leer, weil der Verlauf unten
@@ -3292,20 +3369,23 @@ if (location.search.indexOf("nur=anim") >= 0)
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;
/* Die Abschnitte. stufe() liefert 0 davor, 1 danach und dazwischen den
Anteil; daempfen() nimmt der Bewegung die Maschinenhaftigkeit. */
const tippen = stufe(t, .06, .44);
const leeren = stufe(t, .44, .50);
const wachsen = daempfen(stufe(t, .48, .66));
const karte = daempfen(stufe(t, .64, .80));
const system = daempfen(stufe(t, .78, .92));
const zurueck = daempfen(stufe(t, .92, 1));
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));
// Am Ende faehrt alles wieder auf den Anfang.
const neuAn = Math.max(0, wachsen - zurueck);
const karteAn = Math.max(0, karte - zurueck);
const sysAn = Math.max(0, system - zurueck);
const menueAn = Math.max(0, auf - zu);
let g = "";
@@ -3324,37 +3404,33 @@ if (location.search.indexOf("nur=anim") >= 0)
const spalte = innenB;
const hAlt = alt.map(m => blaseHoehe(m, spalte));
// Die neue Blase ohne und mit Karte -- dazwischen wird geblendet.
const mOhne = { autor: neu.autor, kuerzel: neu.kuerzel, mein: true,
zeit: neu.zeit, text: neu.text };
const hOhne = blaseHoehe(mOhne, spalte);
const hMit = blaseHoehe(neu, spalte);
const hNeu = (hOhne + (hMit - hOhne) * karteAn) * neuAn;
const hSys = blaseHoehe(sys, spalte) * sysAn;
const hNeu = blaseHoehe(neu, spalte) * wachsen;
const hSys = blaseHoehe(sys, spalte) * system;
const LUFT = 16;
const gesamt = hAlt.reduce((a, h) => a + h + LUFT, 0) +
(neuAn > .01 ? hNeu + LUFT : 0) + (sysAn > .01 ? hSys + LUFT : 0);
(wachsen > .01 ? hNeu + LUFT : 0) + (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; });
if (neuAn > .01) {
/* Die neue Blase kommt von unten und waechst auf. Sie wird um ihren
unteren Rand skaliert, damit sie sich aus dem Eingabefeld heraus
aufzurichten scheint und nicht aus der Mitte heraus aufplatzt. */
const s = .86 + .14 * neuAn;
const inhalt = karteAn > .01 ? neu : mOhne;
bahn += '<g opacity="' + n1(Math.min(1, neuAn * 1.6)) + '" transform="translate(0,' +
n1((1 - neuAn) * 34) + ') translate(' + n1(B / 2) + ',' + n1(y + hNeu) +
') scale(' + n1(s) + ') translate(' + n1(-B / 2) + ',' + n1(-(y + hNeu)) + ')">' +
blase(RAND, y, spalte, inhalt) + '</g>';
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 += '<g opacity="' + n1(Math.min(1, wachsen * 1.7)) + '" transform="translate(0,' +
n1((1 - wachsen) * 30) + ') translate(' + n1(B / 2) + ',' + n1(y + hNeu) +
') scale(' + n1(sk) + ') translate(' + n1(-B / 2) + ',' + n1(-(y + hNeu)) + ')">' +
blase(RAND, y, spalte, neu) + '</g>';
y += hNeu + LUFT;
}
if (sysAn > .01) {
bahn += '<g opacity="' + n1(sysAn) + '" transform="translate(0,' +
n1((1 - sysAn) * 12) + ')">' + blase(RAND, y, spalte, sys) + '</g>';
if (system > .01) {
bahn += '<g opacity="' + n1(system) + '" transform="translate(0,' +
n1((1 - system) * 12) + ')">' + blase(RAND, y, spalte, sys) + '</g>';
}
// Was ueber die Bahn hinausragt, wird oben abgeschnitten -- wie im Fenster.
@@ -3364,23 +3440,25 @@ if (location.search.indexOf("nur=anim") >= 0)
/* 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 Composer auch. */
Sendeknopf -- so macht es der Composer auch. */
const fy = H - FELD;
const plusX = RAND + 14, plusY = fy + 44;
g += '<path d="M0,' + n1(fy) + 'H' + B + '" stroke="' + CHAT_RAND + '" stroke-width="1.2"/>';
g += feather("plus", RAND + 14, fy + 44, 21, CHAT_TEXT2, 2);
g += feather("plus", plusX, plusY, 21, menueAn > .3 ? CHAT_TEXT : CHAT_TEXT2, 2);
const feldX = RAND + 36, feldB = B - 2 * RAND - 100;
g += '<g filter="url(#hgklein)"><rect x="' + n1(feldX) + '" y="' + n1(fy + 24) +
'" width="' + n1(feldB) + '" height="40" rx="20" fill="' + FL_KARTE + '" stroke="' +
CHAT_RAND + '" stroke-width="1.2"/></g>';
const zeichen = Math.round(ANIM_TIPP.length * tippen);
const getippt = leeren > .5 || zurueck > .5 ? "" : ANIM_TIPP.slice(0, zeichen);
// 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.
const blink = Math.floor(t * (SLIDES[j].dauer || 5) * 2) % 2 === 0;
if (blink && tippen < 1) {
if (tippen < 1 && Math.floor(t * dauer * 2) % 2 === 0) {
const bx = feldX + 20 + messen(passt, 16, 400);
g += '<rect x="' + n1(bx) + '" y="' + n1(fy + 36) + '" width="2" height="18" ' +
'fill="' + CHAT_TEXT + '"/>';
@@ -3388,13 +3466,43 @@ if (location.search.indexOf("nur=anim") >= 0)
} else {
g += uiText(feldX + 18, fy + 50, "Nachricht schreiben …", 16, 400, "#C9C9CE");
}
const senden = getippt.length > 0;
if (senden) {
const px = B - RAND - 24, py = fy + 44;
g += '<circle cx="' + n1(px) + '" cy="' + n1(py) + '" r="19" fill="#24242B"/>';
g += feather("send", px - 1, py, 18, "#FFFFFF", 2);
if (getippt) {
const px = B - RAND - 24;
g += '<circle cx="' + n1(px) + '" cy="' + n1(plusY) + '" r="19" fill="#24242B"/>';
g += feather("send", px - 1, plusY, 18, "#FFFFFF", 2);
} else {
g += feather("mic", B - RAND - 24, fy + 44, 21, CHAT_TEXT2, 2);
g += feather("mic", B - RAND - 24, plusY, 21, CHAT_TEXT2, 2);
}
/* 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);
const zAn = zeigerAn * (1 - zWeg);
if (zAn > .01) {
const vonX = B - 70, vonY = H + 40;
const p1 = daempfen(zeigerAn);
let zx = vonX + (plusX + 2 - vonX) * p1;
let zy = vonY + (plusY + 2 - vonY) * p1;
if (wandern > 0) {
const p2 = wandern;
zx += (m.zielX - 40 - zx) * p2;
zy += (m.zielY - 6 - zy) * p2;
}
g += klickRing(zx - 2, zy - 2, klick1 < 1 ? klick1 : 0);
g += klickRing(zx - 2, zy - 2, klick2 < 1 && klick2 > 0 ? klick2 : 0);
g += '<g opacity="' + n1(Math.min(1, zeigerAn * 2) * (1 - zWeg)) + '">' +
zeiger(zx, zy, 1.5) + '</g>';
}
return stapelKasten(B, H, 22, g);