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 |
|
| 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
|
**Slide 3 ist der Kern.** Der Redaktionsplan verlangt „Foto rein, Aufgabe
|
||||||
raus", und genau das liegt im Werkzeug als Abfolge vor: Tobias schickt die
|
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
|
**Die Listenzeile hat drei Zeilen, nicht zwei.** Der erste Anlauf setzte Titel
|
||||||
und Vorschau untereinander und schob Nadel und Ungelesen-Punkt rechts neben
|
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,
|
und Fußleiste, darunter die Leiste. Eingezogen wird sie beim Start per Skript,
|
||||||
damit der HTML-Rumpf jeder Datei unverändert bleibt.
|
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
|
## 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 —
|
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
|
nur bekommt die Funktion neben der Nummer den Fortschritt `t` und leitet daraus
|
||||||
alles ab. Der Eintrag steht in `ANIMS`, nicht in `SLIDES`.
|
alles ab. Der Eintrag steht in `ANIMS`, nicht in `SLIDES`.
|
||||||
|
|
||||||
| Zeit | Was passiert |
|
| 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 |
|
| 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,2 – 2,5 s | Das Feld leert sich |
|
| 2,9 – 3,8 s | Der Zeiger fährt auf das Pluszeichen und klickt |
|
||||||
| 2,4 – 3,3 s | Die Blase wächst von unten in den Verlauf, der Verlauf schiebt sich nach oben |
|
| 3,6 – 4,5 s | Das Menü klappt nach oben auf, die Zeilen gestaffelt |
|
||||||
| 3,2 – 4,0 s | Die Aufgabenkarte klappt in der Blase auf, die Blase wächst mit |
|
| 4,5 – 5,8 s | Der Zeiger geht auf „Aufgabe erstellen", die Zeile hebt sich, Klick |
|
||||||
| 3,9 – 4,6 s | Die Systemzeile „Aufgabe „Materialliste prüfen" im Projekt erstellt" erscheint darunter |
|
| 5,7 – 6,1 s | Das Menü schließt, das Feld leert sich |
|
||||||
| 4,6 – 5,0 s | Alles blendet zurück auf den Anfangsstand, damit die Schleife schließt |
|
| 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
|
- **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
|
Wachstum das Hochschieben von selbst, ohne eine zweite Rechnung für das
|
||||||
Scrollen. Die drei vorherigen Nachrichten sind dieselben wie auf Slide 1 und
|
Scrollen. Die drei vorherigen Nachrichten sind dieselben wie auf Slide 1 und
|
||||||
stammen aus `GeneralTeamChatPage.tsx`, nicht aus einem erfundenen Szenario.
|
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
|
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
|
Zählung „Carousel, 6 Slides" und in den Bildexport, der sie als Standbild
|
||||||
mitschrieb. Ein Video, das man nur zusammen mit den Bildern herausbekommt,
|
mitschrieb. Ein Video, das man nur zusammen mit den Bildern herausbekommt,
|
||||||
ist im Carousel aber nicht getrennt einsetzbar.
|
ist im Carousel nicht getrennt einsetzbar.
|
||||||
- **Getippt wird ein Satz, der ohnehin im Verlauf steht.** `ANIM_TIPP` ist
|
- **Der Mauszeiger ist erzählerisches Mittel, kein Bestandteil des Werkzeugs.**
|
||||||
`VERLAUF[3].text` — die Nachricht, die im Werkzeug an dieser Stelle folgt.
|
Ohne ihn sieht man ein Menü aufgehen und weiß nicht, warum. Er ist weiß mit
|
||||||
Kein Text ist für die Animation erfunden worden, auch keine Uhrzeit.
|
dunkler Kante, damit er auf dem Verlauf wie auf dem Menü liest, und geht
|
||||||
- **Das letzte Bild ist nicht das erste.** Der Fortschritt läuft über
|
nach dem zweiten Klick zügig weg — ein Zeiger, der ohne Aufgabe über dem
|
||||||
`t = n / anzahl`; bei `n / (anzahl − 1)` wären Anfang und Ende dasselbe Bild
|
Verlauf stehen bleibt, zieht den Blick von der ankommenden Nachricht ab.
|
||||||
und der Stoß der Schleife stünde eine Dreißigstelsekunde still.
|
- **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
|
Kein Text und keine Uhrzeit ist für die Animation erfunden worden. Getippt wird
|
||||||
exakt 5,000000 s, stumme AAC-Spur, `moov` am Dateianfang, 1,1 MB.
|
`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
|
```js
|
||||||
const ANIMS = [
|
const ANIMS = [
|
||||||
{ key: "animChat", type: "feature", dauer: 5,
|
{ key: "animChat", type: "feature", dauer: 8,
|
||||||
eyebrow: "Bewegtbild",
|
eyebrow: "Bewegtbild",
|
||||||
head: 'Getippt,<br><span class="a">und schon im Projekt.</span>',
|
head: 'Getippt,<br><span class="a">und schon im Projekt.</span>',
|
||||||
body: "Eine Nachricht, ein Klick, und die Aufgabe hängt am richtigen Projekt.",
|
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. */
|
ist `dauer` und der zweite Wert t, den die Zeichenfunktion bekommt. */
|
||||||
const ANIMS = [
|
const ANIMS = [
|
||||||
{
|
{
|
||||||
/* Fuenf Sekunden: unter drei nimmt Instagram ein Video im Carousel
|
/* Acht Sekunden. Fuenf waren zu knapp, sobald der Ablauf stimmt:
|
||||||
nicht an, ueber sechs verliert eine Schleife ihren Reiz. */
|
tippen, Menue, waehlen, abschicken, bestaetigen -- das sind fuenf
|
||||||
key: "animChat", type: "feature", dauer: 5,
|
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",
|
eyebrow: "Bewegtbild",
|
||||||
head: 'Getippt,<br><span class="a">und schon im Projekt.</span>',
|
head: 'Getippt,<br><span class="a">und schon im Projekt.</span>',
|
||||||
body: "Eine Nachricht, ein Klick, und die Aufgabe hängt am richtigen Projekt.",
|
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 ────────────────────────────────────────────
|
/* ─── Das Bewegtbild ────────────────────────────────────────────────────
|
||||||
Eine Nachricht entsteht: getippt, abgeschickt, und aus ihr wird eine
|
Wie aus einer Nachricht eine echte Aufgabe wird, in dem Weg, den das
|
||||||
Aufgabe im Projekt. Darueber liegen drei Beitraege, die schon da waren --
|
Werkzeug tatsaechlich hat.
|
||||||
man sieht also einen laufenden Verlauf und nicht ein leeres Fenster.
|
|
||||||
|
|
||||||
Alle Texte sind dieselben wie auf Slide 1 und 3, aus INITIAL_MESSAGES.
|
Das ist der Kern, und ein erster Anlauf hatte ihn falsch: dort wurde die
|
||||||
Eine Animation ist kein Anlass, etwas zu erfinden.
|
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
|
Also die richtige Reihenfolge: Notiz tippen, Pluszeichen, "Aufgabe
|
||||||
0,06 - 0,44 die Nachricht wird getippt, Zeichen fuer Zeichen
|
erstellen", und beides geht zusammen als eine Nachricht raus. Der Satz
|
||||||
0,44 - 0,50 abgeschickt: das Feld leert sich
|
im Perfekt stimmt dann auch -- wenn die Nachricht ankommt, haengt die
|
||||||
0,48 - 0,66 die Blase waechst von unten herein, der Verlauf rutscht hoch
|
Aufgabe daran.
|
||||||
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
|
|
||||||
|
|
||||||
Der letzte Abschnitt ist wichtig: im Carousel laeuft so ein Bild in
|
Der Ablauf, in Anteilen der Laufzeit (8 s):
|
||||||
Schleife, und ein harter Schnitt zurueck faellt auf. Deshalb blenden die
|
|
||||||
beiden neuen Teile am Ende wieder aus und der Verlauf faehrt zurueck --
|
0,00 - 0,05 ruhig, der Verlauf steht, das Feld ist leer
|
||||||
das letzte Bild ist damit dasselbe wie das erste. */
|
0,05 - 0,36 die Notiz wird getippt, Zeichen fuer Zeichen
|
||||||
const ANIM_TIPP = VERLAUF[3].text;
|
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) {
|
function animChat(j, t) {
|
||||||
/* 620 x 740: hoeher waere das Fenster oben leer, weil der Verlauf unten
|
/* 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 B = 620, H = 740, RAND = 22, KOPF = 74, FELD = 96;
|
||||||
const innenB = B - 2 * RAND;
|
const innenB = B - 2 * RAND;
|
||||||
const bahnO = KOPF + 8, bahnU = H - FELD - 8;
|
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
|
const tippen = stufe(t, .05, .36);
|
||||||
Anteil; daempfen() nimmt der Bewegung die Maschinenhaftigkeit. */
|
const zeigerAn = stufe(t, .36, .43); // Zeiger faehrt zum Plus
|
||||||
const tippen = stufe(t, .06, .44);
|
const klick1 = stufe(t, .43, .48);
|
||||||
const leeren = stufe(t, .44, .50);
|
const auf = daempfen(stufe(t, .45, .56)); // Menue klappt auf
|
||||||
const wachsen = daempfen(stufe(t, .48, .66));
|
const wandern = daempfen(stufe(t, .56, .68)); // Zeiger zur Zeile
|
||||||
const karte = daempfen(stufe(t, .64, .80));
|
const klick2 = stufe(t, .68, .73);
|
||||||
const system = daempfen(stufe(t, .78, .92));
|
const zu = daempfen(stufe(t, .71, .76)); // Menue schliesst
|
||||||
const zurueck = daempfen(stufe(t, .92, 1));
|
/* 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 menueAn = Math.max(0, auf - zu);
|
||||||
const neuAn = Math.max(0, wachsen - zurueck);
|
|
||||||
const karteAn = Math.max(0, karte - zurueck);
|
|
||||||
const sysAn = Math.max(0, system - zurueck);
|
|
||||||
|
|
||||||
let g = "";
|
let g = "";
|
||||||
|
|
||||||
@@ -3324,37 +3404,33 @@ if (location.search.indexOf("nur=anim") >= 0)
|
|||||||
|
|
||||||
const spalte = innenB;
|
const spalte = innenB;
|
||||||
const hAlt = alt.map(m => blaseHoehe(m, spalte));
|
const hAlt = alt.map(m => blaseHoehe(m, spalte));
|
||||||
// Die neue Blase ohne und mit Karte -- dazwischen wird geblendet.
|
const hNeu = blaseHoehe(neu, spalte) * wachsen;
|
||||||
const mOhne = { autor: neu.autor, kuerzel: neu.kuerzel, mein: true,
|
const hSys = blaseHoehe(sys, spalte) * system;
|
||||||
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 LUFT = 16;
|
const LUFT = 16;
|
||||||
const gesamt = hAlt.reduce((a, h) => a + h + LUFT, 0) +
|
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 y = bahnU - gesamt;
|
||||||
|
|
||||||
let bahn = "";
|
let bahn = "";
|
||||||
alt.forEach((m, i) => { bahn += blase(RAND, y, spalte, m); y += hAlt[i] + LUFT; });
|
alt.forEach((m, i) => { bahn += blase(RAND, y, spalte, m); y += hAlt[i] + LUFT; });
|
||||||
|
|
||||||
if (neuAn > .01) {
|
if (wachsen > .01) {
|
||||||
/* Die neue Blase kommt von unten und waechst auf. Sie wird um ihren
|
/* Sie kommt von unten und richtet sich auf: skaliert um den eigenen
|
||||||
unteren Rand skaliert, damit sie sich aus dem Eingabefeld heraus
|
unteren Rand, damit sie aus dem Eingabefeld heraus zu wachsen
|
||||||
aufzurichten scheint und nicht aus der Mitte heraus aufplatzt. */
|
scheint und nicht aus der Mitte heraus aufplatzt. Text und
|
||||||
const s = .86 + .14 * neuAn;
|
Aufgabenkarte kommen zusammen -- es ist eine Nachricht, und der
|
||||||
const inhalt = karteAn > .01 ? neu : mOhne;
|
Klick auf "Aufgabe erstellen" hat beides erzeugt. */
|
||||||
bahn += '<g opacity="' + n1(Math.min(1, neuAn * 1.6)) + '" transform="translate(0,' +
|
const sk = .88 + .12 * wachsen;
|
||||||
n1((1 - neuAn) * 34) + ') translate(' + n1(B / 2) + ',' + n1(y + hNeu) +
|
bahn += '<g opacity="' + n1(Math.min(1, wachsen * 1.7)) + '" transform="translate(0,' +
|
||||||
') scale(' + n1(s) + ') translate(' + n1(-B / 2) + ',' + n1(-(y + hNeu)) + ')">' +
|
n1((1 - wachsen) * 30) + ') translate(' + n1(B / 2) + ',' + n1(y + hNeu) +
|
||||||
blase(RAND, y, spalte, inhalt) + '</g>';
|
') scale(' + n1(sk) + ') translate(' + n1(-B / 2) + ',' + n1(-(y + hNeu)) + ')">' +
|
||||||
|
blase(RAND, y, spalte, neu) + '</g>';
|
||||||
y += hNeu + LUFT;
|
y += hNeu + LUFT;
|
||||||
}
|
}
|
||||||
if (sysAn > .01) {
|
if (system > .01) {
|
||||||
bahn += '<g opacity="' + n1(sysAn) + '" transform="translate(0,' +
|
bahn += '<g opacity="' + n1(system) + '" transform="translate(0,' +
|
||||||
n1((1 - sysAn) * 12) + ')">' + blase(RAND, y, spalte, sys) + '</g>';
|
n1((1 - system) * 12) + ')">' + blase(RAND, y, spalte, sys) + '</g>';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Was ueber die Bahn hinausragt, wird oben abgeschnitten -- wie im Fenster.
|
// 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
|
/* Das Eingabefeld. Waehrend des Tippens laeuft der Text mit, dahinter
|
||||||
blinkt der Strich; sobald etwas drinsteht, wird aus dem Mikrofon der
|
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 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 += '<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;
|
const feldX = RAND + 36, feldB = B - 2 * RAND - 100;
|
||||||
g += '<g filter="url(#hgklein)"><rect x="' + n1(feldX) + '" y="' + n1(fy + 24) +
|
g += '<g filter="url(#hgklein)"><rect x="' + n1(feldX) + '" y="' + n1(fy + 24) +
|
||||||
'" width="' + n1(feldB) + '" height="40" rx="20" fill="' + FL_KARTE + '" stroke="' +
|
'" width="' + n1(feldB) + '" height="40" rx="20" fill="' + FL_KARTE + '" stroke="' +
|
||||||
CHAT_RAND + '" stroke-width="1.2"/></g>';
|
CHAT_RAND + '" stroke-width="1.2"/></g>';
|
||||||
|
|
||||||
const zeichen = Math.round(ANIM_TIPP.length * tippen);
|
// Nach dem Klick auf "Aufgabe erstellen" geht die Notiz mit raus.
|
||||||
const getippt = leeren > .5 || zurueck > .5 ? "" : ANIM_TIPP.slice(0, zeichen);
|
const abgeschickt = zu > .45;
|
||||||
|
const zeichen = Math.round(ANIM_NOTIZ.length * tippen);
|
||||||
|
const getippt = abgeschickt ? "" : ANIM_NOTIZ.slice(0, zeichen);
|
||||||
if (getippt) {
|
if (getippt) {
|
||||||
const passt = umbrechen(getippt, feldB - 44, 16, 400, 1)[0];
|
const passt = umbrechen(getippt, feldB - 44, 16, 400, 1)[0];
|
||||||
g += uiText(feldX + 18, fy + 50, passt, 16, 400, CHAT_TEXT);
|
g += uiText(feldX + 18, fy + 50, passt, 16, 400, CHAT_TEXT);
|
||||||
// Der Strich blinkt zweimal je Sekunde, gerechnet auf die Laufzeit.
|
// Der Strich blinkt zweimal je Sekunde, gerechnet auf die Laufzeit.
|
||||||
const blink = Math.floor(t * (SLIDES[j].dauer || 5) * 2) % 2 === 0;
|
if (tippen < 1 && Math.floor(t * dauer * 2) % 2 === 0) {
|
||||||
if (blink && tippen < 1) {
|
|
||||||
const bx = feldX + 20 + messen(passt, 16, 400);
|
const bx = feldX + 20 + messen(passt, 16, 400);
|
||||||
g += '<rect x="' + n1(bx) + '" y="' + n1(fy + 36) + '" width="2" height="18" ' +
|
g += '<rect x="' + n1(bx) + '" y="' + n1(fy + 36) + '" width="2" height="18" ' +
|
||||||
'fill="' + CHAT_TEXT + '"/>';
|
'fill="' + CHAT_TEXT + '"/>';
|
||||||
@@ -3388,13 +3466,43 @@ if (location.search.indexOf("nur=anim") >= 0)
|
|||||||
} else {
|
} else {
|
||||||
g += uiText(feldX + 18, fy + 50, "Nachricht schreiben …", 16, 400, "#C9C9CE");
|
g += uiText(feldX + 18, fy + 50, "Nachricht schreiben …", 16, 400, "#C9C9CE");
|
||||||
}
|
}
|
||||||
const senden = getippt.length > 0;
|
if (getippt) {
|
||||||
if (senden) {
|
const px = B - RAND - 24;
|
||||||
const px = B - RAND - 24, py = fy + 44;
|
g += '<circle cx="' + n1(px) + '" cy="' + n1(plusY) + '" r="19" fill="#24242B"/>';
|
||||||
g += '<circle cx="' + n1(px) + '" cy="' + n1(py) + '" r="19" fill="#24242B"/>';
|
g += feather("send", px - 1, plusY, 18, "#FFFFFF", 2);
|
||||||
g += feather("send", px - 1, py, 18, "#FFFFFF", 2);
|
|
||||||
} else {
|
} 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);
|
return stapelKasten(B, H, 22, g);
|
||||||
|
|||||||
Reference in new issue
Block a user