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:
1 parent
d8b010fbdc
commit
7804587ca0
3 files changed
+198
-57
No files matched your search
+120
-39
@@ -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
|
||||
|
||||
Reference in new issue
Block a user