Pryne Frontend-Architektur-Vertrag
Die tragenden strukturellen Entscheidungen von Prynes Vanilla-JS-Builds, warum sie existieren und die Invarianten, die Sie nicht brechen dürfen. Referenzimplementierung: design-demos/ im Portfolio (Test)-Repository (~/Documents/Coding Folder/Portfolio (test)), aktives Build v4-d-hybrid.html + js/roll-*.js, Stand 2026-07-22.
Fachbegriffe, einmal definiert: IIFE = Immediately Invoked Function Expression, (function () { ... })(); – ein dateibegrenzter Closure, sodass nichts nach außen dringt, außer das, was die Datei explizit auf dem gemeinsamen Namespace platziert. Progressive Enhancement = die Seite ist ohne JS-Erweiterung voll nutzbar; reicheres Verhalten wird nur dann aktiviert, wenn seine Abhängigkeit tatsächlich geladen wird. Develop-plate = die Leinwandgrafik dieses Projekts, die sich „entwickelt“ (sich aus Rauschen auflöst), während der Benutzer interagiert.
Wann dieser Skill NICHT verwendet werden soll
- Animationstiming, Easing, Choreografie-Theorie → pryne-motion-reference
- Ob eine Änderung überhaupt erlaubt ist und wie sie abgesichert ist → pryne-change-control
- Etwas ist kaputt und Sie diagnostizieren → pryne-frontend-debugging
- Nachweis, dass eine Änderung funktioniert (Screenshots, Lighthouse, Rubrik) → pryne-validation-and-qa
- React/Next.js oder ein Projekt mit Bundler – dieser Vertrag gilt nur für No-Build-Vanilla-Seiten.
Der Modul-Vertrag
Ein Anliegen pro Datei. Eine IIFE pro Datei. Kein Bundler, keine Imports.
Der gesamte modulübergreifende Zustand lebt auf einem einzigen globalen Namespace-Objekt – hier window.Roll. roll-core.js erstellt es und wird zuerst geladen; jedes andere Modul beginnt mit const Roll = window.Roll; und liest/schreibt Eigenschaften darauf (roll-core.js:1-7 sagt dies explizit). Module, die nichts voneinander wissen müssen, kommunizieren stattdessen über DOM-Ereignisse (z.B. sendet roll-scroll.js roll:launch; roll-contact-sheet.js hört darauf – siehe roll-scroll.js:35-37).
Die Skript-Reihenfolge im HTML ist der Abhängigkeitsgraph. Aus v4-d-hybrid.html:429-437:
roll-core.js → roll-shader.js → roll-field.js → roll-audio.js → roll-cursor.js
→ vendor/lenis.min.js → roll-scroll.js → roll-contact-sheet.js → roll-eggs.js
Invariante: Ordnen Sie <script> niemals um oder fügen Sie eines ein, ohne zuvor zu prüfen, was das Modul aus Roll liest, und zu bestätigen, dass jeder Produzent früher geladen wird. Es gibt kein Importsystem, das Sie rettet; eine Neuordnung scheitert stillschweigend oder wirft beim Laden einen Fehler.
grep -n "Roll\.\w*" design-demos/js/<module>.js # was es liest/schreibt
GSAP ist bewusst NICHT in dieser Kette – siehe Invariante 2.
Modulzuordnung (Stand 2026-07-22)
| Datei | Ein Anliegen | Zeilen |
|---|---|---|
roll-core.js | Namespace, gemeinsamer Zustand, Develop-plate-Engine, upgradeMotion | 192 |
roll-scroll.js | Die Wirbelsäule: Einstieg, Scroll-Choreografie, HUD, Haupt-rAF (requestAnimationFrame)-Schleife, Lenis | 226 |
roll-field.js | Hintergrund-Canvas-Feld | 136 |
roll-shader.js | WebGL-Korn/Licht-Shader + Canvas-2D-Fallback | 133 |
roll-eggs.js | Versteckte Persönlichkeitsauslöser (nur auf Flüster-Ebene) | 83 |
roll-audio.js | Leiser Umgebungsklang, gekoppelt an Scroll-Geschwindigkeit | 79 |
roll-contact-sheet.js | Kontaktblatt-Enthüllung beim Start | 55 |
roll-cursor.js | Benutzerdefinierter Cursor (nur Desktop, GSAP-abgesichert) | 36 |
Neue interaktive Funktion? Es ist eine neue roll-*.js-Datei (oder ein klar abgegrenzter Abschnitt des Moduls, dem dieses Anliegen gehört), die an der Abhängigkeitsposition zur Skriptkette hinzugefügt wird – nicht als inline <script> im HTML.
Invarianten (im Code verifiziert – halten Sie sie wahr)
- Reduced Motion schaltet jedes Bewegungsmodul ab.
Roll.reduced = matchMedia('(prefers-reduced-motion: reduce)').matches(roll-core.js:9). Jedes Modul konsultiert es: Shader überspringt WebGL (roll-shader.js:90,124), Feld überspringt seine rAF-Schleife (roll-field.js:125,135), Kontaktblatt kehrt früh zurück (roll-contact-sheet.js:12), Scroll überspringt den Hold-to-Develop-Einstieg und Lenis (roll-scroll.js:39-40,152), und CSS entfernt clip-path-Übergänge (v4-d-hybrid.html:293-295). Jede neue Bewegung mussRoll.reduced(JS) prüfen oder unter der Reduced-Motion-Media-Query (CSS) liegen. - GSAP ist eine progressive Erweiterung, niemals eine Abhängigkeit. Es wird
asyncvon CDN mit einem SRI-Hash geladen (v4-d-hybrid.html:440); beim Laden ruft esRoll.upgradeMotion()auf, wasRoll.enhancedumschaltet und Rückrufe ausführt, die überRoll.onMotionReadyregistriert wurden (roll-core.js:10-15,186-191). Wenn GSAP nie ankommt, muss die Seite voll funktionsfähig bleiben – Cursor, Hero-Type und Verzerrung bleiben einfach auf dem Basisniveau (roll-cursor.js:34-35,roll-scroll.js:32-33,89,196). Registrieren Sie GSAP-abhängigen Code mitRoll.onMotionReady(fn); rufen Siegsap.*niemals bedingungslos auf. - Risikoreiche visuelle Übernahmen werden defensiv umschlossen – auf dem wiederkehrenden Pfad, nicht nur beim Setup. Der benutzerdefinierte Cursor ist auf drei Ebenen geschützt, jeweils mit einem wiederherstellenden Catch, der
Roll.cursorUpdateauf null setzt und.custom-cursorentfernt (was den OS-Cursor verbirgt): Setup (roll-cursor.js:9-32, Catch bei 32), der Rumpf des Ereignis-Handlers (roll-cursor.js:17-20) und diepointermove-Aufrufstelle (roll-core.js:26-29). Ein Fehler an irgendeinem Punkt – Setup-Zeit oder jedes spätere Mousemove – stellt den OS-Cursor wieder her (behoben 2026-07-22; Fail-Safe-Vertrag im Dateikopf,roll-cursor.js:1-5). Wenn Sie dieses Muster auf alles anwenden, das eine native Einrichtung verbirgt/ersetzt, schützen Sie auch den wiederkehrenden Pfad, nicht nur das Setup. - clip-path-Enthüllungen leben auf einem inneren Wrapper, niemals auf dem Element, das IntersectionObserver überwacht (die „Concept-C-Fix“ – benannt nach v4 Concept C,
v4-c-ch001.html, wo es entstand, bevor es in v4-d übernommen wurde). Der IO beobachtet.panel; die clip-path-Animation bewegt.panel-inner(v4-d-hybrid.html:121-122,185-186). Begründung: Das Clipping des beobachteten Elements ändert seine Intersection-Geometrie und die Enthüllung bekämpft den Auslöser. - Engagement-gesteuerte visuelle Elemente schalten basierend auf ihrer eigenen Sichtbarkeit, nicht auf dem Seitenladen. Feature-Plates entwickeln sich nur, während ihr Panel
.inhat (roll-scroll.js:204-219); der Code-Kommentar dokumentiert den ursprünglichen Fehler: Platten waren fertig aufgelöst, bevor jemand zu ihnen gescrollt hatte, „stillschweigend die Interaktion des 'Entwickelt sich, während du dich engagierst' besiegend.“ Der Kopfkommentar vonv4-d-hybrid.htmlbezeichnet den Fix als die höchste Priorität aus dem technischen Audit. - WebGL ist explizit und Fallback-sicher. Nicht-premultipliziertes Alpha bei der Kontexterstellung (
roll-shader.js:17), explizitesgl.clearjeden Frame (roll-shader.js:95), 2D-Kontext wird erst erworben, nachdem WebGL seine Chance hatte – ein Canvas kann immer nur einen Kontexttyp haben (roll-shader.js:9-12), undwebglcontextlostscheitert ruhig, anstatt das Rendering-Loop werfen zu lassen (roll-shader.js:129-132). Aufrufer verwenden den einzigen EinstiegspunktRoll.shader.render(t)und wissen nie, ob GL oder 2D verwendet wird. - Scrollen bleibt unter Lenis nativ. Lenis ist eingekauft (
js/vendor/lenis.min.js, nicht CDN), wird nur instanziiert, wenn!Roll.reduced, und hältwindow.scrollYgültig – es ist ein Gefühls-Upgrade, kein Scroll-Hijack (roll-scroll.js:148-152,167). Die Rendering-Schleife liestscrollYwie zuvor.
Single-File-Demo-Philosophie + Design-Tokens
Jede Designvariante ist eine eigenständige HTML-Datei (Inline-CSS, gemeinsame js/-Module), sodass Varianten als vollständige Artefakte verglichen, gescreenshotted und A/B-getestet werden können – siehe pryne-design-direction-decision. Ein langer Kopfkommentar in jeder Datei dokumentiert, was die Variante ist und welche Audit-Ergebnisse sie enthält (lesen Sie ihn vor dem Bearbeiten; er ist das lokale Changelog der Datei).
Alle Farben, Abstände und Easing sind CSS-Custom-Properties in :root (v4-d-hybrid.html:50-63):
:root {
--bg: #0a0a0b; --accent: #d2232e; --ink: #f4f3f1; --dim: #86868c;
--pad-x: clamp(1.25rem, 6vw, 6rem);
--ease-out: cubic-bezier(0.22, 1, 0.36, 1);
--ease-snap: cubic-bezier(0.16, 1, 0.3, 1);
}
Gemäß Prynes globalen Regeln: Niemals eine Farbe/Größe hartcodieren, wo ein Token existiert; Flüssigwerte verwenden clamp(). Neue Bewegungen müssen --ease-out/--ease-snap wiederverwenden, es sei denn, pryne-motion-reference sagt etwas anderes – eine Easing-Sprache pro Build.
Checkliste: Hinzufügen eines Moduls
- Neues
roll-*.js(oder korrektes vorhandenes Besitzermodul), IIFE auf oberster Ebene,const Roll = window.Roll; -
<script>eingefügt nach allem, was es ausRollliest, vor allem, was es liest - Prüft
Roll.reduced; GSAP-Nutzung nur innerhalb vonRoll.onMotionReady - Alles, was eine native Einrichtung verbirgt, ist mit try/catch umschlossen, inklusive eines wiederherstellenden Catches
- Sichtbarkeitsgesteuert, wenn engagement-getrieben; IO-Ziel ≠ clip-path-Ziel
- Tokens, keine hartcodierten Werte
- Dann validieren gemäß pryne-validation-and-qa
Bekannte Schwachstellen (offen und klar dargelegt)
- Kein Build-Schritt: keine Minifizierung, kein Bundling; in Ordnung für Demos, ungelöst für die Produktion.
- Schriftarten werden von Google Fonts CDN geladen (
v4-d-hybrid.html:47-48) trotz der vendor-first-Absicht des Projekts (Self-Hosting wird indesign-demos/DECISIONS.mdnur beiläufig erwähnt, innerhalb des Lenis-Eintrags; der Entscheidungsdatensatz selbst ist älter als die Datei; noch nicht erledigt). GSAP ist ebenfalls noch CDN (gepinnt + SRI). Siehe pryne-change-control, bevor Sie eines davon „beheben“. - Keine automatisierten Tests – Validierung erfolgt nur browserbasiert (pryne-validation-and-qa).
- Platzhalter-Inhalt: Fallstudien/Lebenslauf sind nicht endgültig; polieren Sie den Text nicht, als ob er es wäre.
Herkunft und Wartung
Führen Sie scripts/verify.sh (im Verzeichnis dieses Skills) aus, um alle untenstehenden Punkte auf einmal zu überprüfen.
Grundlage ist das Portfolio (Test)-Repository auf Commit 457868a, 2026-07-22. Überprüfen Sie volatile Fakten erneut, bevor Sie ihnen vertrauen:
- Skript-Reihenfolge:
grep -n "<script" design-demos/v4-d-hybrid.html - Zeilenzahlen / Modulliste:
wc -l design-demos/js/*.js - Reduced-Motion-Abdeckung:
grep -rn "Roll.reduced\|prefers-reduced-motion" design-demos/ - GSAP immer noch CDN+SRI, Schriftarten immer noch CDN:
grep -n "cdn.jsdelivr\|fonts.googleapis" design-demos/v4-d-hybrid.html - Lenis immer noch eingekauft:
ls design-demos/js/vendor/ - Aktives Build ist immer noch v4-d: Überprüfen Sie
design-demos/DECISIONS.mdund das neuestegit log --oneline