Bewegtbild: die Kurven von GSAP, der Zeiger faehrt einen Bogen

Die Website macht ihre Bewegungen mit gsap 3.14.2. Uebernommen sind die
Kurven, nicht das Paket: was GSAP darueber hinaus kann -- Zeitleisten,
ScrollTrigger, MotionPath -- setzt voraus, dass etwas laeuft. Hier
laeuft nichts, animChat(i, t) bekommt seinen Fortschritt von aussen und
ist damit selbst schon die Zeitleiste. Ein paused timeline mit
.progress(t) waere dieselbe Konstruktion mit 70 KB darunter, und ein
Easing ist eine Zeile.

Zwei der Kurven waren ohnehin GSAPs: daempfen ist Wort fuer Wort
power2.inOut, rueck ist back.out(1,70158). Die Namen stehen jetzt
daneben, dazu kommen raus (power2.out) und knall (expo.out).

  Der Zeiger fuhr auf power2.inOut, also langsam an, in der Mitte
  schnell, wieder abbremsend -- die Bewegung eines Schlittens. Eine
  Hand ist sofort schnell und wird zum Ziel hin langsam.

  Und er fuhr auf der Geraden. Jetzt auf einer quadratischen Bezier,
  Stuetzpunkt 13 % der Strecke quer nach aussen, vom Verlauf weg. Rund
  27 px Ausbuchtung auf 410 px Weg: es faellt nicht auf, das ist der
  Punkt.

  Der Klickring geht auf zwei Kurven, Radius auf expo.out und die
  Deckung linear hinterher. Beides auf derselben sah aus wie eine
  Blase, die sich aufblaest.

  Der Anlauf ist von 0,6 s auf 0,18 s geschrumpft. Am Ende steht das
  Bild eine halbe Sekunde still, damit man das Ergebnis liest; lief
  vorn nochmal eine halbe, waren das ueber den Schleifenstoss hinweg
  1,2 von 6 Sekunden Stillstand am Stueck.

MP4 neu gebaut, Werte unveraendert: H.264, 1080x1350, 30 fps, 6,0 s,
stumme AAC-Spur. Geprueft ist das an Kontaktabzuegen ueber die 180
Bilder, nicht am Lauf.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U7RZ6ZpLD8Dp84Rtt4KHfv
This commit is contained in:
dejanandClaude Opus 5 committed 2026-08-28 20:37:21 +02:00
1 parent 7804587ca0
commit e8f5686f30
3 files changed
+119 -14

No files matched your search

+59 -11
View File
@@ -3537,8 +3537,12 @@ if (location.search.indexOf("nur=anim") >= 0)
'<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 Ring geht auf einer anderen Kurve als er verblasst: der Radius mit
knall, also fast sofort draussen, die Deckung linear hinterher. Beides auf
derselben Kurve sah aus wie eine Blase, die sich aufblaest -- ein Klick
ist ein Stoss und kein Aufpumpen. */
const klickRing = (x, y, p) => p <= 0 || p >= 1 ? "" :
'<circle cx="' + n1(x) + '" cy="' + n1(y) + '" r="' + n1(7 + 17 * p) +
'<circle cx="' + n1(x) + '" cy="' + n1(y) + '" r="' + n1(7 + 17 * knall(p)) +
'" fill="none" stroke="#24242B" stroke-width="' + n1(2.4 * (1 - p)) +
'" opacity="' + n1(.55 * (1 - p)) + '"/>';
@@ -3577,20 +3581,29 @@ if (location.search.indexOf("nur=anim") >= 0)
const innenB = B - 2 * RAND;
const bahnO = KOPF + 8, bahnU = H - FELD - 8;
const zeigerAn = stufe(t, .10, .22);
const pfeil = daempfen(stufe(t, .16, .24)); // der Pfeil an der Blase
const klick1 = stufe(t, .22, .27);
/* Der Zeiger faehrt bei 0,03 los und nicht mehr bei 0,10. Am Ende steht
das Bild eine halbe Sekunde still, damit man das Ergebnis liest -- lief
vorn nochmal eine halbe Sekunde nichts, waren das ueber den
Schleifenstoss hinweg 1,2 von 6 Sekunden Stillstand am Stueck, und die
Schleife sah aus, als haenge sie. Der Halt am Ende bleibt, der am
Anfang ist auf ein Achtel geschrumpft. */
const zeigerAn = stufe(t, .03, .19);
const pfeil = daempfen(stufe(t, .13, .21)); // der Pfeil an der Blase
const klick1 = stufe(t, .21, .26);
/* rueck statt daempfen, und kuerzer: gedaempft war die Deckung nach
fuenf Bildern fertig, waehrend die Skalierung noch eine halbe Sekunde
von 0,96 auf 1,00 weiterkroch. Sichtbar war davon fast nichts, zu
spueren war es als Haenger. Jetzt schnappt es in einer Drittelsekunde
auf, schwingt einmal ganz leicht ueber und steht. */
const auf = rueck(stufe(t, .26, .34));
const auf = rueck(stufe(t, .25, .33));
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));
/* raus statt daempfen: die Zeile kommt von unten herein und bleibt
liegen. Eine Kurve, die auch langsam anfaengt, laesst sie zaeh
aussehen -- sie soll ankommen, nicht anfahren. */
const system = raus(stufe(t, .80, .90));
const menueAn = Math.max(0, auf - zu);
let g = "";
@@ -3674,9 +3687,25 @@ if (location.search.indexOf("nur=anim") >= 0)
const zAn = zeigerAn * (1 - zWeg);
if (zAn > .01) {
const vonX = B - 60, vonY = H + 40;
const p1 = daempfen(zeigerAn);
let zx = vonX + (chevX - 2 - vonX) * p1;
let zy = vonY + (chevY - 2 - vonY) * p1;
const zuX = chevX - 2, zuY = chevY - 2;
/* raus statt daempfen. Gedaempft faehrt der Zeiger langsam an, wird in
der Mitte schnell und bremst wieder ab -- das ist die Bewegung eines
Schlittens und nicht die einer Hand. Eine Hand ist sofort schnell und
wird zum Ziel hin langsam. */
const p1 = raus(zeigerAn);
/* Und sie faehrt einen Bogen. Auf der Geraden zwischen Start und Ziel
liegt kein Zeiger, den je ein Mensch gefuehrt hat; das faellt nicht
als Fehler auf, aber die Bewegung wirkt gestellt. Der Stuetzpunkt
sitzt quer zur Strecke, um ein Zehntel ihrer Laenge nach aussen --
weg vom Verlauf, damit der Zeiger nicht ueber die Blasen streicht.
Bei p1 = 1 liegt die Bahn exakt auf dem Ziel, das anschliessende
Wandern zur Menuezeile setzt also sauber daran an. */
const bx = zuX - vonX, by = zuY - vonY, BOGEN = .13;
const sx = (vonX + zuX) / 2 - by * BOGEN;
const sy = (vonY + zuY) / 2 + bx * BOGEN;
const u = 1 - p1;
let zx = u * u * vonX + 2 * u * p1 * sx + p1 * p1 * zuX;
let zy = u * u * vonY + 2 * u * p1 * sy + p1 * p1 * zuY;
if (wandern > 0) {
zx += (m.zielX - zx) * wandern;
zy += (m.zielY - 4 - zy) * wandern;
@@ -3707,10 +3736,29 @@ if (location.search.indexOf("nur=anim") >= 0)
/* Ein paar Verlaeufe. Linear sieht nach Maschine aus, deshalb sind Ein-
und Ausgang gedaempft. `stufe` blendet einen Abschnitt zwischen zwei
Zeitpunkten ein und liefert 0 davor und 1 danach. */
const daempfen = x => x <= 0 ? 0 : x >= 1 ? 1 : x < .5
/* Die Kurven sind die von GSAP, mit dem die Website ihre Bewegungen macht --
als Formel und nicht als Bibliothek. Ein Verlauf ist eine Zeile Rechnung;
was GSAP darueber hinaus koennte (Zeitleisten, Motion-Path, ScrollTrigger),
braucht hier nichts: die Zeichenfunktion bekommt ihr t von aussen und ist
damit selbst schon die Zeitleiste. Die Namen stehen daneben, damit
nachvollziehbar bleibt, welche Kurve gemeint ist.
daempfen und rueck standen vorher unbenannt hier und sind Wort fuer Wort
GSAPs power2.inOut und back.out(1,70158) -- die Datei sprach die Sprache
also schon, sie sagte es nur nicht. */
const daempfen = x => x <= 0 ? 0 : x >= 1 ? 1 : x < .5 // power2.inOut
? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2;
const rueck = x => x <= 0 ? 0 : x >= 1 ? 1
const rueck = x => x <= 0 ? 0 : x >= 1 ? 1 // back.out(1.7)
: 1 + 2.7 * Math.pow(x - 1, 3) + 1.7 * Math.pow(x - 1, 2);
/* Schnell los, lang aus. Alles, was ankommt und liegen bleibt -- ein Zeiger,
der ins Bild faehrt, eine Zeile, die einlaeuft -- gehoert hierher und
nicht auf eine Kurve, die auch langsam anfaengt. */
const raus = x => x <= 0 ? 0 : x >= 1 ? 1 // power2.out
: 1 - Math.pow(1 - x, 3);
/* Noch schaerfer: schnappt heraus und ist praktisch sofort fertig. Fuer den
Klickring, der einem Fingertipp folgt. */
const knall = x => x <= 0 ? 0 : x >= 1 ? 1 // expo.out
: 1 - Math.pow(2, -10 * x);
const stufe = (t, von, bis) => t <= von ? 0 : t >= bis ? 1 : (t - von) / (bis - von);
const VIS = {