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:
1 parent
9e8b2ea607
commit
d4feaa175b
4 files changed
+231
-88
No files matched your search
@@ -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.
|
||||
@@ -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
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user