iso: animierte isometrische Erklärgrafiken
Eine Szene erzählt eine Produktgeschichte in einer 6 bis 14 Sekunden langen Schleife: Dinge treffen ein, Licht wandert zwischen ihnen, ein Teil leuchtet nach dem anderen auf, und die Schleife kehrt zum ersten Bild zurück. Ein Ablauf ist nur eine Form. Wähle die Form, die die Geschichte braucht, aus der Beat-Tabelle: eine Box, die sich öffnet und ihre Layer zeigt, eine Übergabe zwischen zwei Objekten, ein Raster, das sich füllt, ein Stapel, der eine Auswahl dreht, oder Kacheln, die der Betrachter durch Schweben anhebt. Alles ist echtes SVG und HTML-Text, skaliert mit seinem Container, pausiert außerhalb des Bildschirms und wird für reduzierte Bewegung eingefroren.
Das Kit befindet sich neben dieser Datei:
lib/iso.ts: DerScene-Builder (Projektion, Blöcke, Flächen, Kabel, Pulse, Beschriftungen, Bewegungsabläufe),scene.exportSvg(),responsive()undlazyBox().lib/runtime.ts: Spielt eine gerenderte Szene mit WAAPI ab, startet das Intro, sobald 40 % davon (oder die Hälfte der Bildschirmhöhe bei einer hohen Szene) im Sichtfeld sind, pausiert es außerhalb des Bildschirms, verwirft die Animationen, sobald es mehr als eine Bildschirmhöhe entfernt ist, und setzt sie auf demselben Frame fort, bevor es zurückkehrt, friert es für reduzierte Bewegung ein, stelltwindow.isoSeek(t)bereit.scripts/render.ts: Rendert ein Szenenmodul (StandardexportPage) in eine eigenständige HTML-Datei mit eingebetteter Laufzeit.scripts/shots.mjs: Erstellt Screenshots jeder Seite zu gewählten Zeitpunkten und Breiten und schreibtsheet.png.scripts/check.ts: Strenge Typprüfung von Szenendateien auf der Festplatte gegen das Kit (bun scripts/check.ts scene.ts).scripts/page-idle.mjs: Scrollt eine Seite mit vielen Szenen einmal durch, stoppt dann bei 0, 20, 35, 50, 60 und 80 % und gibt die Hauptthread-Zeit an jedem Punkt aus, bei CPU 1x und 4x (node scripts/page-idle.mjs page=<url> width=393 dpr=3 scroll=4). Führe es auf jeder Seite mit mehr als ein paar Szenen aus.scripts/perf.mjs: Spielt eine Seite in Chrome in Telefonbreite mit gedrosselter CPU ab (node scripts/perf.mjs page=<out.html> width=393 throttle=4 seconds=20) und gibt Bildrate, Frame-Zeit-Perzentile, verspätete Frames, lange Tasks und Hauptthread-Zeit aus. Führe es auf jeder Szene mit 30 oder mehr bewegten Objekten aus.scripts/contrast.mjs,scripts/render-all.ts: Misst jeden Text in einer gerenderten Seite gegen die Pixel direkt hinter seinen Glyphen am Stillbild und vier weiteren Zeitpunkten und schlägt fehl unter 4,5:1 (node scripts/contrast.mjs <out.html>;bun scripts/render-all.ts <dir>schreibt zuerst jedes Katalogbeispiel). Führe es auf jeder Szene aus, bevor du sie für fertig erklärst.scripts/study-rive.mjs,scripts/compare-rive.mjs: Optionale Werkzeuge zum Untersuchen einer eigenen.riv-Animation Bild für Bild und zum Vergleichen mit einer Kit-Szene. Beide benötigenruntime=<Ordner mit canvas_advanced.mjs und rive.wasm>.examples/: 64 Szenen für fiktive Produkte, jede eine Datei, dieexample(Titel, Geschichte, Prompt, Level, Kategorie, Layout, Interaktion undart: die kompakten und breiten Szenen ausart(compact, wide, breakpoint)) und eine Standard-Pageexportiert, sodassscripts/render.tsjede davon rendern kann. Einespot-Szene ist eine einzelne kleine Szene,art(compact).hero.tsexportierthero(einArt) undmaterial-gallery.tsexportiertgalleries(einArtpro Finish-Familie), jeweils mit einer Standard-Page.examples/shared.tsenthält die Oberflächen, Farbverläufe,paints, Schriftarten undfitX(), die eine Beschriftung innerhalb ihrer Szene auf der schmalsten Karte hält, auf der sie sitzen wird.
Wähle das Beispiel, das deiner Geschichte am nächsten kommt, und lies es, bevor du zeichnest:
| Beispiel | Level | Zeigt |
|---|---|---|
notifications.ts | einfach | die minimale Datei: ein Kern, der zu drei Kacheln auffächert, Pulse, Ankunftsblitz und Hüpfer. Lies es zuerst |
ci-deploy.ts | einfach | ein Paket, das entlang einer Kette hüpft, eine Stauchung bei der Landung, eine Zustandsfarbe erst am Ende |
file-upload.ts | einfach | Chunks, die einen Fortschrittsbalken füllen, dann Kopien, die sich zu Randpunkten ausbreiten; Laufstriche auf leeren Plätzen |
db-branching.ts | einfach | ein gestrichelter Geist, der fest wird, eine Änderungskachel, die zurückgleitet und zusammenführt |
service-map.ts | einfach | Hover: neun slab({ hover })-Kacheln mit Beschriftungen, die beim Schweben oder Tippen erscheinen, plus eine Schleife, die trotzdem die Geschichte erzählt |
auth-flow.ts | mittel | ein aufrechtes panel()-Telefon, getippte Eingabe, Übergabegeister, die ein Token tragen |
etl-pipeline.ts | mittel | Quellkacheln, die einen Kern entlang von Kabeln speisen, die mit ihnen einzeichnen, dann ein Füll- und Leerraster; Overlays, die mit dem Block gruppiert sind, auf dem sie sitzen, sodass sie sich zusammen bewegen |
queue-workers.ts | mittel | eine Schlangenwarteschlange, die von einer Ereignistabelle gesteuert wird, die der Build validiert (kein Überlauf, kein Entnehmen aus Leerem) |
search-index.ts | mittel | Strichzeichnungskacheln auf einer hellen Seite, eine getippte Abfrage, Trefferbeleuchtung, aufsteigende Ranglisten-Ergebnisse |
feature-flags.ts | mittel | abspielbar: ein echter <button> in einer Beschriftung und ein Inline-Skript, das einen Schleifenschritt mit seek wiederholt |
agent-tools.ts | komplex | ein Kern mit Satelliten, Ruf- und Antwortpulsen, einer Antwortkarte, die eintippt |
checkout-payment.ts | komplex | ein Ring von Schritten mit einem gestrichelten Rückweg und einer Statuszeile, die überblendet |
edge-cache.ts | komplex | dieselbe Anfrage zweimal: ein warmer Fehlschlag zum Ursprung, dann ein kühler Treffer am Rand |
observability.ts | komplex | drei Signaldarstellungen (Striche, Punkte, Spannen), prism-Balken mit heightTo, ein Alarm und eine Wiederherstellung |
keycard-slot.ts, battery-charge.ts, tile-loader.ts, empty-box.ts | Spot | ein kleines Objekt für eine Funktionsliste, einen Ladezustand oder einen leeren Zustand; eine aufrechte panel()-Karte, die an der Lippe eines Schlitzen beschnitten ist, heightTo-Zellen, eine diagonale Fallwelle, Laufstriche |
sync-loop.ts, inbox-fill.ts, alert-stack.ts, table-scan.ts | Spot | Pfeile, die auf die Ebene gequetscht sind, ein Tablett mit Glasfront, Karten, die auf einen Stapel gleiten, mit einem Abzeichen, das zählt und auf der obersten Karte reitet, eine Linse, die Zeile für Zeile gleitet |
audit-ledger.ts, dns-resolve.ts, cron-jobs.ts | einfach | Seiten, die sich mit Siegeln stapeln, ein Hüpfer nach dem anderen mit Antworten, ein Zifferblatt, das Jobs auslöst |
vault-rotate.ts, firewall-filter.ts, zero-trust.ts | mittel | ein Schlüsseltausch mit dem Schlitzmuster, ein abgelehntes Paket, das zurückprallt, jede Anfrage gestempelt |
workload-scheduler.ts, autoscale.ts, health-check.ts | mittel | Platzierung aus einer kleinen Regel-Tabelle, Platz für einen neuen Knoten schaffen, ein Knoten, der entfernt und wieder hinzugefügt wird |
blue-green.ts, snapshot-restore.ts | mittel | ein neu ausgerichtetes Kabel, ein Cursor, der entlang einer Zeitleiste zurückgleitet |
embedding-clusters.ts, training-loss.ts, recs-rerank.ts, ab-test.ts | mittel | Punkte, die sich in Clustern niederlassen, fallende prism-Balken, eine Regal-Neuordnung, eine Aufteilung mit einem Gewinner |
data-erasure.ts, rag-answer.ts | komplex | eine Anfrage, die auf sechs Systeme mit einem Zähler auffächert, abgerufene Karten, die in ein Modell fliegen, und eine Antwort, die eintippt |
hero.ts | komplex | ein Prompt wächst ein System in Stufen von 1, 5, 15 und 40: ein Drehteller-Einschwenker und ein gewichteter Fall, Ausgaben, die darunter hervorgleiten, Pops, ein Pool, der mit einer Rasterfüllung einfällt, endlose Anfragen, eine Neigung zur Maus in Ruhe; blinkt durch fill und wiederholte Kacheln durch <use>, um günstig zu bleiben; nur SVG text(), sodass exportSvg() darauf funktioniert |
funnel-live.ts, billing-cycle.ts, parcel-delivery.ts, test-shards.ts | mittel, komplex | layout: 'wide': 3:1-Streifen von links nach rechts gelesen (sich verengende Stufen, ein Monatsstreifen, der sich ohne Sprung verschiebt, Fahrzeuge, die eine Box tragen, Bruchstücke, die in Spuren rasen und zusammenführen) |
kanban-move.ts, stock-sync.ts, diff-merge.ts, refund-flow.ts | einfach bis komplex | layout: 'diagonal': eine Karte oder ein Token, die/der entlang einer Iso-Achse reist, Tore, die grün werden, eine Rückerstattung, die auf demselben Pfad in einer zweiten Farbe zurückläuft |
live-cursors.ts, two-approvals.ts, design-comments.ts, translate-six.ts | einfach, mittel | layout: 'panels': aufrechte panel()s, die sich gegenüberstehen; Cursor, die tippen, zwei Häkchen, die ein Schloss entriegeln, Pins und ein Thread, eine Nachricht in sechs Sprachen mit einem Thai- und Japanisch-Schriftartenstapel |
cms-publish.ts, sensor-gateway.ts, smart-home.ts, currency-convert.ts | einfach, mittel | layout: 'radial': eine Kopie an fünf Kanäle, Messwerte, die dann eine Bodenwelle hinausschicken, Geräte, die sich der Reihe nach ändern, ein Puls einmal um einen Ringdraht |
ota-rollout.ts, build-cache.ts, calendar-booking.ts, load-slider.ts | einfach bis komplex | layout: 'field': Wellen über ein Gerätefeld mit einem Stopp und Wiederholungsversuch, Cache-Treffer, die aus einer Abhängigkeitstabelle ermittelt werden, ein Meeting, das einen Konflikt überspringt; load-slider ist ein Ziehregler (ein echter Bereichs-Input, Maus, Touch und Tasten), der die Schleife sucht, während der Umgebungsverkehr sich weiterbewegt |
video-transcode.ts, image-resize.ts, fraud-gauge.ts, data-lineage.ts, drill-down.ts | einfach bis komplex | layout: 'exploded': Versionen, die sich heben und codieren, Größen, die sich ablösen, Risikoschichten, die sich über eine Linie hinaus aufaddieren, ein Upstream-Pfad, der durch Schichten nach unten leuchtet; drill-down öffnet einen Teil in seine Schichten von einem echten Button aus, indem es das Schleifensegment dieses Teils sucht |
materials-*.ts, material-gallery.ts | 49 Seitenfinishs in sechs Familien (Metall, Glas, Natürlich, Tech-Muster, Retro, Generativ) als (scene) => Material-Fabriken, eine galerie ohne Beschriftung pro Familie. Generative Finishs nehmen einen Seed. Kopiere ein Finish, anstatt eines zu erfinden |
Einrichtung einmalig: cd <dieser Ordner>/scripts && bun install && bunx playwright install webkit (Screenshots verwenden das installierte Google Chrome für Chromium). Typprüfung: scripts/node_modules/.bin/tsc -p <dieser Ordner>.
1. Storyboard vor dem Zeichnen
Öffne zuerst recipes.md. Es enthält jedes gemessene Bewegungs- und Kompositionsmuster (Ankünfte, Verbindungen, Ströme, Vergleiche, Auswahl, Leerlauf, Interaktion, Easing, Oberflächen), jeweils mit seinen Zahlen und Kit-Aufrufen. Setze die Geschichte aus diesen Rezepten zusammen und behalte ihre Zeitabläufe bei.
Schreibe die Geschichte zuerst als Zeitablaualtabelle: Was der Betrachter verstehen soll, die 3 bis 6 Beats, die es zeigen, und für jeden Beat, welches Element sich wie, wann und wie lange bewegt. Ein Beat pro Idee. Ein Beat, der einen Absatz zur Erklärung braucht, sind zwei Beats oder das falsche Bild.
Bewährte Beat-Formen mit gemessenen Zeitabläufen:
| Beat | Was passiert | Zeitablauf |
|---|---|---|
| Ankunft | Teile fallen nacheinander ein, überschießen ein wenig, setzen sich | dropIn: 0,55 s pro Stück, 83 ms Staffelung, 46 px Fall |
| Übergabe | Geisterumrisse einer Kachel gleiten von einem Objekt zum anderen | 4 Geister, 0,22 s Abstand, 1,2 s pro Stück, ease.io |
| Reise | Ein kurzer Lichtpuls läuft entlang eines Kabels; das Ziel blinkt bei Ankunft auf | 270 px/s, Puls ~0,12 bis 0,16 des Kabels, Anstieg 0,1 s, Ausblenden 0,6 s |
| Layer enthüllen | Eine solide Box wird durchsichtig; innere Layer leuchten nacheinander mit einer Beschriftung auf | Ein 0,23 s, Halten ~1 s, Aus 0,2 s, nächster beginnt, wenn der letzte endet |
| Auswahl drehen | Ein Stapel verschiebt sich um einen Platz nach oben; die aktive Karte wird zur Akzentfarbe | 0,9 s Bewegung alle 3 s, langsamer Start, langes Aus-Easing |
| Füllen und Leeren | Ein Raster füllt sich Kachel für Kachel, hält, fällt zurück auf leer | 7 Frames (0,12 s) Abstand rein, 2 Frames Abstand raus |
| Ziehen | Wenn ein Kabel schrumpft oder wächst, wird die Box, an der es befestigt ist, etwa 6 px entlang des Kabels gezogen, hält, entspannt sich dann, sodass das Kabel wie unter Spannung aussieht | 0,23 s Zug, 0,25 s Halten, 0,65 s Rückkehr mit langem Aus-Easing |
| Hover-Anheben | Eine Kachel steigt 16 px an und nimmt ihre Markenfarbe an, ihr Name erscheint | slab({ hover }): 270 ms ein, 325 ms aus, ease.out |
Verbindungsregel: Ein Kabel ist nur auf dem Bildschirm, solange beide seiner Enden es sind. Ein Kabel zu etwas, das mitten in der Schleife ankommt, zeichnet sich mit seinem Puls ein (wire({ dash: '1 1' }), dann at(id, 'strokeDashoffset', t, d, 1, 0, ease.linear)) und verlässt das Bild mit dem, was es verbindet. Setze ein solches Kabel niemals in das Intro. Ein Kabel kreuzt niemals die Oberseite einer Box: Füge es vor den Objekten hinzu, die es verbindet (damit sie darüber malen) und beginne es am Rand der Box, nicht in ihrer Mitte.
Schleifenregel: Der letzte Frame ist gleich dem ersten. Alles, was sich während der Schleife ändert, ändert sich zurück, bevor sie endet. Nur-Intro-Bewegung geht in intro(); die Schleife beginnt, wenn das Intro endet, und das Intro muss mit demselben Bild enden, mit dem die Schleife beginnt. Ein Element ohne Intro zeigt während des Intros den Startwert der Schleife, der das letzte to seiner Schleifensegmente ist.
Die Malreihenfolge ist fest: Was später hinzugefügt wird, bedeckt immer, was früher hinzugefügt wurde. Bewegung, die ändern würde, wer wen bedeckt (eine Karte, die sich von der Spitze eines Stapels nach unten bewegt), wird stattdessen als Slots gezeichnet. Jedes Element ist ein Slot, der sich einen Schritt bewegt und aus- oder einfärbt wie sein Nachbar, und jedes Segment beginnt wieder vom Ruhewert des Slots, sodass alle Slots gemeinsam zurückspringen, während das Bild gleich aussieht. Gib jedem Slot eine Beschriftung pro Option und überblende, welche neben dem aktiven Slot angezeigt wird.
2. Wähle ein Layout, dann gestalte zuerst für das Telefon
Jedes Beispiel benennt seine Komposition in layout: wide (ein langer Streifen, der von links nach rechts gelesen wird; seine breite Szene ist etwa 3:1, z. B. 1200x400, mit Breakpoint 720, und die Showcase zeigt sie als vollbreite Karte), diagonal (eine lange Reihe entlang einer Iso-Achse), panels (aufrechte panel()s, die sich gegenüberstehen), radial (ein Kern mit Dingen auf einem Ring), field (viele Kacheln von oben gesehen; ein etwas steileres ratio hilft), exploded (Schichten vertikal auseinandergehoben) oder object (ein oder zwei Objekte für eine Funktionsliste oder einen leeren Zustand). Wähle die, die die Geschichte braucht, bevor du zeichnest; eine Seite mit Szenen liest sich besser, wenn sie variieren.
Eine Szene, die der Betrachter abspielen kann (interaction: 'play' | 'drag' | 'explore'), liefert ein kleines Inline-Modul-Skript in art()'s head: echter <button> oder <input type="range"> in einer label({ html }), Zeigerereignisse für Maus und Touch (touch-action: none auf einem Ziehregler), auch Tasten, ein MutationObserver, um Szenen zu binden, die später eingehängt werden, die Schleife pausiert, während der Betrachter handelt, und nach ein paar Leerlaufsekunden fortgesetzt, und eine Schleife, die trotzdem die Geschichte ohne Eingabe erzählt (feature-flags.ts, load-slider.ts, drill-down.ts).
Messestände und Landingpages werden auf Telefonen geöffnet. Baue zwei Szenen und verpacke sie mit responsive(compact, wide):
- compact: etwa 390 breit, Hochformat oder quadratisch (390x420 bis 390x640). Staple die Geschichte von oben nach unten. Entwerfe bei 390 Einheiten, damit eine Beschriftung
size: 13auf einem Telefon 13 px ist. Niemals unter 13. - wide: etwa 900 bis 1200 breit, Querformat, die Geschichte von links nach rechts.
Sa
…
[für die Übersetzung gekürzt]