Slide 5: das Absperrband laeuft hinter die Ausschnitte

Vorher lief es ueber die ganze Zeichnung hinaus und endete an der
Bildkante, quer zur eigenen Laufrichtung abgeschnitten -- das ist das
Zeichen fuer ein Ende, so liest sich ein Aufkleber. Jetzt bricht es an
einer senkrechten Plattenkante ab, waehrend es mit 13 Grad ankommt, und
das ist keines: dort laeuft es hinter die Platte, um den Stapel herum.

Beschnitten wird an der Silhouette beider Ausschnitte. Damit macht es
die Website nach, die ihr Band am Rand des Telefons abschneidet ("so
the ends cut off like real tape"), und der Gegensatz "absperren oder
beschneiden", den der Kommentar hier behauptete, faellt weg: die
Silhouette beider Platten ist die ganze Sache.

Drei Dinge tragen es, keines verbiegt die Form:
  die Schnittkante ist die Plattenkante und steht schraeg zum Band
  sie ist weicher als eine Linie und haerter als die Platten (1,1)
  die letzten 56 Einheiten verlieren Licht, mit dem Hoehepunkt als
    Plateau davor -- auf der Kante selbst blendet die Maske schon aus

Der Verlauf steht dafuer in den Koordinaten der Zeichnung statt in
denen des gedrehten Bandes: er soll parallel zu der Kante stehen, an
der er endet.

Mit weg sind zwei Kommentarbloecke, von denen einer einen Stand
beschrieb, der einen Commit vorher zurueckgenommen worden war, und mit
ihnen WEB.bandKnick und WEB.bandSpitze.

Geprueft ueber beide Wege, Browser-Screenshot und html-to-image: die
Maske ueberlebt den Export, das Bild ist identisch.

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:05 +02:00
1 parent d8b010fbdc
commit 7804587ca0
3 files changed
+198 -57

No files matched your search

+120 -39
View File
@@ -3237,9 +3237,6 @@ if (location.search.indexOf("nur=anim") >= 0)
der Chat auf den Ausschnitten kommt aus dem Pitch-Paket. */
const WEB = {
band: "#F1B729", bandDunkel: "#171106",
/* Die Enden knicken nach hinten weg und liegen damit im Schatten. Zwei
Stufen, nicht eine: die Knickflaeche und dahinter die Spitze. */
bandKnick: "#D6A11E", bandSpitze: "#B98914",
};
/* ─── Slide 5 · Der Chat für unterwegs ──────────────────────────────────
@@ -3316,32 +3313,38 @@ if (location.search.indexOf("nur=anim") >= 0)
platte(VX, VY, vorn) + '</g>';
/* Das Absperrband der Website: -13°, accent-yellow auf dunklen Kanten,
Schutzhelm und "BALD VERFUEGBAR" im Wechsel. Es liegt ueber beiden
Platten und ragt beidseitig hinaus -- es sperrt die ganze Sache ab,
nicht eine Flaeche darin. */
/* Das Absperrband. Es liegt nicht flach auf der Flaeche, sondern knickt
an beiden Enden nach hinten weg: die Aussenkanten laufen zur Mitte
zusammen, die Knickflaechen sind dunkler, und an der Knickstelle steht
eine Kante. Das ist der ganze Trick -- ein Band, das perspektivisch
wegfuehrt, hat schmalere Enden und weniger Licht darauf.
Schutzhelm und "BALD VERFUEGBAR". Es liegt ueber beiden Platten und
laeuft an beiden Enden hinter sie -- es sperrt die ganze Sache ab,
nicht eine Flaeche darin. Wie das gemacht ist, steht weiter unten bei
der Maske; die Form selbst bleibt das Rechteck der Website.
Vorher war es ein Rechteck mit gleichmaessig durchlaufender Schrift.
Das las sich als Aufkleber und nicht als Band. */
UEBER ist der Rand des Kastens und zugleich der Ueberstand des Bandes
darin. Beides an einer Zahl, weil die Bandlaenge genau so gerechnet
ist, dass der gedrehte Kasten des Bandes exakt die Kastenbreite misst:
bL*cos + bh*sin = W + 2*UEBER. Damit steht nie Geometrie ueber den
viewBox hinaus, auch wenn ein Teil davon verdeckt ist -- und die
Randmessung sieht dasselbe wie das Auge. Genau daran hat es schon
einmal gehakt: getBBox() kennt keine Beschneidung und meldete beim
ersten, am Geraet abgeschnittenen Band 146 px Ueberstand, den es nicht
gab (POST-6.md 6). Wer UEBER anfasst, muss beides mitdenken. */
const UEBER = 84, bh = 92, ty = H / 2 - bh / 2 + 24;
const bogen = 13 * Math.PI / 180;
const bL = (W + 2 * UEBER - bh * Math.sin(bogen)) / Math.cos(bogen);
const bA = (W - bL) / 2, bE = bA + bL;
/* Die Tiefe kommt aus Licht und nicht aus Geometrie. Zwei Anlaeufe
haben die Form verbogen -- erst die Enden zur Spitze verjuengt, dann um
die Knickstelle gekippt. Beides sah nach Schleife oder Welle aus, weil
ein Absperrband nun einmal flach und straff ist. Was ihm gefehlt hat,
war Rundung: quer ueber die Hoehe ein Verlauf von hell nach dunkel, wie
auf einem Band, das leicht gewoelbt ueber der Flaeche liegt, und zu den
Enden hin ein Abdunkeln, weil sie weiter weg sind. Die Form bleibt das
Rechteck, das sie auf der Website ist. */
/* Die Woelbung quer ueber die Hoehe: ein Verlauf von hell nach dunkel,
wie auf einem Band, das leicht gewoelbt ueber der Flaeche liegt. Sie
ist alles, was die Form selbst an Tiefe traegt -- zwei Anlaeufe haben
stattdessen die Geometrie verbogen, erst die Enden zur Spitze
verjuengt, dann um die Knickstelle gekippt, und beides sah nach
Schleife oder Welle aus. Ein Absperrband ist flach und straff.
Das Abdunkeln an den Enden stand vorher hier, in den Koordinaten des
Bandes. Es steht jetzt weiter unten in denen der Zeichnung: es gehoert
an die Stelle, wo das Band hinter eine Platte laeuft, und die liegt
nicht am Bandende. */
const oT = ty, uT = ty + bh;
const gid = "bandLicht", eid = "bandEnden";
const gid = "bandLicht";
let band =
'<defs>' +
'<linearGradient id="' + gid + '" x1="0" y1="0" x2="0" y2="1">' +
@@ -3349,17 +3352,9 @@ if (location.search.indexOf("nur=anim") >= 0)
'<stop offset="0.38" stop-color="' + WEB.band + '"/>' +
'<stop offset="1" stop-color="#D89F1B"/>' +
'</linearGradient>' +
'<linearGradient id="' + eid + '" x1="0" y1="0" x2="1" y2="0">' +
'<stop offset="0" stop-color="#000000" stop-opacity="0.20"/>' +
'<stop offset="0.22" stop-color="#000000" stop-opacity="0"/>' +
'<stop offset="0.78" stop-color="#000000" stop-opacity="0"/>' +
'<stop offset="1" stop-color="#000000" stop-opacity="0.20"/>' +
'</linearGradient>' +
'</defs>' +
'<rect x="' + n1(bA) + '" y="' + n1(oT) + '" width="' + n1(bL) +
'" height="' + bh + '" fill="url(#' + gid + ')"/>' +
'<rect x="' + n1(bA) + '" y="' + n1(oT) + '" width="' + n1(bL) +
'" height="' + bh + '" fill="url(#' + eid + ')"/>';
'" height="' + bh + '" fill="url(#' + gid + ')"/>';
/* Die dunklen Laengskanten. Die untere sitzt eine Spur dicker: dort liegt
die Kante im Schatten der Woelbung. */
@@ -3382,11 +3377,97 @@ if (location.search.indexOf("nur=anim") >= 0)
band += uiText(bx + 44, ty + bh / 2 + 12, wort, gr, 800, WEB.bandDunkel,
{ sperr: "0.16em" });
/* ── Das Band laeuft um den Stapel herum ──────────────────────────────
Auf der Website ist es am Rand des Telefons beschnitten: "Clipped to
the phone's rounded bounds so the ends cut off like real tape"
(ChatDemoSection.tsx). Hier lief es bisher darueber hinaus, damit es
die ganze Sache absperrt und nicht eine Flaeche darin. Das war ein
Gegensatz, den es nicht gibt: beschnitten wird an der Silhouette
*beider* Ausschnitte, und die ist die ganze Sache.
Damit kommt die Tiefe aus dem staerksten Mittel, das es dafuer gibt --
aus der Verdeckung. Ein Ende, das quer zur Laufrichtung abgeschnitten
ist, ist das Ende des Bandes; so sah es vorher aus, wie ein Aufkleber,
der an der Bildkante aufhoert. Ein Ende, das an einer senkrechten
Plattenkante abbricht, ist keines: dort laeuft das Band hinter die
Platte, um den Stapel herum, und kommt hinten nicht mehr zum Vorschein.
Drei Dinge tragen das, und keines davon verbiegt die Form:
die Schnittkante ist die Plattenkante und steht schraeg zum Band
sie ist genauso weich wie die Platten -- eine unscharfe Kante kann
nichts scharf verdecken, und die Platten sind unscharf
die letzten Einheiten davor verlieren Licht, weil die Flaeche sich
wegdreht
Getroffen wird die Silhouette an genau zwei Stellen: links die linke
Kante der hinteren Platte bei x 0, rechts die rechte der vorderen bei
x W. Beide sind dort gerade -- die Rundungen liegen weit weg -- und
beide stehen senkrecht, waehrend das Band mit 13 Grad ankommt. Genau
diese Schraege ist das Zeichen. */
const SILH = rundRechteck(0, 0, PB, PH, RAD) + rundRechteck(VX, VY, PB, PH, RAD);
const dreh = 'rotate(-13,' + n1(W / 2) + ',' + n1(ty + bh / 2) + ')';
/* Der Lichtabfall vor der Kante, als Abstand zur Kante und Deckung.
Nicht linear: eine Falte ist keine Rampe. Die vollen Einheiten stehen
als Plateau dicht an der Kante, danach laeuft es schnell aus -- so
liest sich das letzte Stueck als Kante, um die sich das Band legt, und
nicht als Schatten, der darauf faellt.
Zwei Anlaeufe davor: ein linearer Abfall ueber 44 Einheiten sah nach
Nebel aus, und ein Abfall mit dem Hoehepunkt genau auf der Kante ging
wieder verloren -- dort blendet die Maske das Band schon aus, das
Dunkelste lag also im Durchsichtigen. Der Hoehepunkt gehoert ein
Stueck davor, wo das Band noch voll deckt. */
const UMSCHLAG = [[0, .80], [5, .70], [13, .44], [28, .20], [56, 0]];
const halt = (d, o) => '<stop offset="' + (d / W).toFixed(4) +
'" stop-color="#5A4108" stop-opacity="' + o + '"/>';
/* Die Schnittkante ist weicher als eine gezogene Linie und haerter als
die Platten. Mit deren 2,2 lief das Band ueber vier Einheiten ins
Weisse aus und sah nach Ausblenden aus statt nach Verdecken; ganz
scharf wiederum stand eine gestochene Kante an einer unscharfen
Platte. 1,1 liegt dazwischen: die Kante traegt, ohne zu schneiden.
Der schwarze Strich auf derselben Kontur nimmt die halbe Haarlinie der
Platte zurueck. Ohne ihn endet das Band mitten in der Kante und laesst
nur deren aeussere Haelfte stehen; die Kante wird dann duenner, genau
da, wo sie am meisten zu tragen hat. */
g += '<defs>' +
'<filter id="bandKante" x="-20%" y="-20%" width="140%" height="140%">' +
'<feGaussianBlur stdDeviation="1.1"/></filter>' +
'<mask id="bandSilhouette" maskUnits="userSpaceOnUse" x="-120" y="-120" ' +
'width="' + (W + 240) + '" height="' + (H + 240) + '">' +
'<g filter="url(#bandKante)"><path d="' + SILH + '" fill="#FFFFFF" ' +
'stroke="#000000" stroke-width="1.3"/></g></mask>' +
'<clipPath id="bandFlaeche"><rect x="' + n1(bA) + '" y="' + n1(oT) +
'" width="' + n1(bL) + '" height="' + bh + '" transform="' + dreh + '"/></clipPath>' +
/* Waagerecht in den Koordinaten der Zeichnung, nicht in denen des
Bandes: der Abfall soll parallel zur senkrechten Plattenkante
stehen, an der er endet, und nicht schraeg dazu. Der Ton ist ein
warmes Dunkelbraun und kein Schwarz -- Schwarz macht aus dem Gelb
ein Grau, und ein Band, das sich wegdreht, wird nicht farblos. */
'<linearGradient id="bandUmschlag" gradientUnits="userSpaceOnUse" ' +
'x1="0" y1="0" x2="' + W + '" y2="0">' +
UMSCHLAG.map(([d, o]) => halt(d, o)).join("") +
UMSCHLAG.slice().reverse().map(([d, o]) => halt(W - d, o)).join("") +
'</linearGradient>' +
'</defs>';
/* Um die eigene Mitte drehen, nicht um die der Zeichnung: das Band liegt
24 Einheiten tiefer, und beim Drehen um einen anderen Punkt wandert
sein Kasten seitlich aus -- fuenf Einheiten ueber den Rand. */
g += '<g transform="rotate(-13,' + n1(W / 2) + ',' + n1(ty + bh / 2) + ')" ' +
'filter="url(#hgtief)">' + band + '</g>';
sein Kasten seitlich aus -- fuenf Einheiten ueber den Rand.
Die Maske sitzt auf einer Gruppe darueber und nicht auf dieser hier:
eine Verdeckung wird in den Koordinaten der Platten gerechnet, und die
Drehung an derselben Stelle wuerde sie mitdrehen. Ihr Schatten faellt
damit ebenfalls nur auf die Platten -- neben ihnen ist keine Flaeche,
die einen aufnehmen koennte. */
g += '<g mask="url(#bandSilhouette)">' +
'<g transform="' + dreh + '" filter="url(#hgtief)">' + band + '</g>' +
'<g clip-path="url(#bandFlaeche)"><rect x="0" y="0" width="' + W +
'" height="' + H + '" fill="url(#bandUmschlag)"/></g>' +
'</g>';
return wfSvg(W + 2 * UEBER, H, '<g transform="translate(' + UEBER + ',0)">' + g + '</g>');
}
@@ -3416,11 +3497,11 @@ if (location.search.indexOf("nur=anim") >= 0)
Der Ablauf, in Anteilen der Laufzeit (6 s):
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,00 - 0,03 ruhig, der Verlauf steht
0,03 - 0,19 der Zeiger faehrt auf die Nachricht, der Pfeil erscheint
0,21 - 0,26 Klick
0,25 - 0,33 das Menue klappt auf, die Zeilen gestaffelt
0,40 - 0,54 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