01 · Element
Ember
Feuer · Mut
Flammen steigen über die Karte und züngeln an ihren Seiten hinab, Glut und kleine hohle Dreiecke schweben nach oben. Beweg den Mauszeiger, und das Feuer neigt sich mit.

Showcase · Three.js · WebGPU · TSL
Elemental Cards ist ein interaktives 3D-Karten-Karussell. Jede Karte ist eine Pille aus Rauchglas mit Icon, Namen und zwei Stichworten. Erreicht eine Karte die Mitte, wird ihre Oberfläche zu einem schillernden Farbverlauf, und ihr Element erwacht um sie herum: Feuer, Sonnenlicht, Wind oder ein blühender Lotus.
Die Szene ist kein Video. Deine Grafikkarte zeichnet sie 60- bis 120-mal pro Sekunde mit Three.js und dem neuen WebGPU-Renderer, und sie reagiert auf Scrollen, Mauszeiger und Klicks. In Browsern ohne WebGPU wechselt sie automatisch zu WebGL 2.
Die vier Karten
Jeder Effekt wird im Koordinatensystem seiner Karte gezeichnet. So neigt er sich mit der Karte und folgt ihr durch das Karussell. Das macht jeder Effekt, und so funktioniert er.
Die Flammen steigen über der Karte am höchsten und bleiben an den Seiten niedrig. Glut schwebt nach oben und verglimmt, einige hohle Dreiecke treiben durch das Feuer. Bewegst du den Mauszeiger schnell zur Seite, neigen sich die Flammen gegen die Bewegung.
Technik: Die Flamme beginnt beim Abstand zum Kartenumriss. Drei Noise-Ebenen ziehen unterschiedlich schnell nach oben und brechen den weichen Verlauf in Flammenzungen auf. Eine Farbrampe bildet die Hitze von Dunkelrot über Orange bis zu einem hellen Kern ab.
Der Rand glüht auf, bevor sich die Oberfläche mit Farbe füllt. Dann fächern Strahlen aus, Funken und kleine Ringe lösen sich vom Rand. Strahlen und Glow sammeln sich auf der Seite, die deinem Mauszeiger am nächsten ist.
Technik: Zwei exponentielle Abfälle vom Distanzfeld ergeben den heißen Rand und den weiten Schein. Die Strahlen sind zwei Noise-Bänder, die rund um die Karte nach Winkel gelesen werden. Weil sich die Textur kachelt, schließt sich der Kreis ohne Naht.
Feine Linien schmiegen sich an die Karte, helle mischen sich mit weichen türkisen, und Striche wandern von links nach rechts. Der Mauszeiger drängt die Luft beiseite, und in seiner Nähe und nach einem Klick wird der Wind schneller.
Technik: Die Linien sind Höhenlinien eines seitlich gestreckten Distanzfelds, verformt durch langsames Noise. Jede Linie bekommt eine eigene Geschwindigkeit und Strichlänge. Eine eigene Uhr treibt die Striche an, damit sie ohne Sprung beschleunigen können.
Dreizehn Blätter in vier Lagen entfalten sich hinter der Karte, die inneren zuerst. Ihre Ränder leuchten, sie atmen langsam und weichen dem Mauszeiger aus, während rosa Funken um die Blüte aufsteigen.
Technik: Jedes Blatt ist ein gewölbtes Mesh, das einmal auf der CPU geformt wird. Die Aktivierung treibt ein gestaffeltes Easing pro Lage. Das Material blendet den äußersten Rand aus und glättet so die Kontur ohne Multisampling.
So ist es gebaut
Die Karten nutzen den Three.js-WebGPURenderer und TSL, die Three.js Shading Language. Mit TSL schreibst du Shader als TypeScript-Funktionen, die zu WGSL für WebGPU und zu GLSL für WebGL 2 kompiliert werden.
Eine kleine Funktion weiß, wie weit jeder Punkt vom Pillen-Umriss entfernt ist. Kartenkante, Kantenglättung, Glasrand und jeder Glow drumherum werden aus dieser einen Zahl abgeleitet.
// Signed distance to the pill-shaped card, in card space.
// Negative inside, zero on the outline, positive outside.
function sdPill(p: Node<"vec2">) {
const h = HH - HW
return length(vec2(p.x, p.y.sub(clamp(p.y, -h, h)))).sub(HW)
}Eine ruhende Karte ist Rauchglas: oben schwarz, unten sammelt sich die Farbe des Elements, dazu ein haarfeiner Rand. Leuchtet sie, ziehen vier weiche Farbflecken über die Oberfläche, leicht verformt durch Noise. Die Beschriftung ist eine Canvas-Textur, die einmal beim Start gezeichnet wird.
Jedes Element legt eine Ebene hinter seine Karte. Der Shader berechnet nur Licht, und die Ebenen werden additiv gemischt, ohne den Alphakanal zu berühren. So bleibt der dunkle Raum sichtbar und die Karte liegt obenauf.
// Flames: a gradient from the card outline outwards,
// broken into tongues by three layers of rising noise.
const reach = mix(0.05, 0.62, up.pow(1.25)).add(above.mul(0.95))
const heat = clamp(
float(1).sub(d.div(reach)).add(noise.mul(mix(0.35, 1.05, up))).sub(0.18),
0.0, 1.0,
)Glut, Funken, Ringe und Lichtpunkte sind instanzierte Sprites. Jede Instanz berechnet Position, Größe und Ausblendung im Shader aus ihrer Nummer und der Zeit. Die CPU aktualisiert nie einen einzelnen Partikel.
// Embers live entirely on the GPU: no per-frame JavaScript.
const life = fract(time.mul(rnd(1).mul(0.35).add(0.28)).add(rnd(2)))
material.positionNode = vec3(x0, float(HH - 0.25).add(life.mul(1.1)), 0.02)
const embers = new THREE.Sprite(material)
embers.count = 70 // one draw call, 70 instancesEin einziger Post-Processing-Schritt färbt den Raum hinter den Karten in der Farbe des Elements, spiegelt die Karten mit zunehmender Unschärfe im Boden und fügt Bloom und etwas Filmkorn hinzu. Über den Karten wird der Bloom gedämpft, damit die Beschriftung lesbar bleibt.
// WebGPU where available, WebGL 2 everywhere else.
const renderer = new THREE.WebGPURenderer({ canvas, antialias: false })
await renderer.init()
renderer.backend.isWebGPUBackend // true on WebGPUInteraktion
Statische Karten sind ein Bild. Diese reagieren auf das, was du tust, und genau das hält Besucher auf einer Landingpage.
Die Karte unter dem Mauszeiger neigt sich ihm in 3D entgegen. Ein weicher Glanz gleitet über das Glas, und der Rand leuchtet dort auf, wo der Zeiger ist.
Flammen neigen sich, Sonnenstrahlen sammeln sich, Wind umströmt den Zeiger und der Lotus weicht aus. Ein schwaches Licht in der Elementfarbe folgt dem Mauszeiger durch den Raum.
Ein Klick auf die leuchtende Karte schickt einen Ring in ihrer Farbe los, dazu Funken und ein kurzes Aufflackern. Ein Klick auf eine Seitenkarte scrollt zu ihrem Kapitel.
Der Bereich bleibt beim Scrollen fixiert. Die Scroll-Position bewegt das Karussell stufenlos: Effekte verblassen, wenn eine Karte die Mitte verlässt, und bauen sich auf, wenn die nächste ankommt.
Performance
Ein schöner Effekt, der ruckelt, wirkt kaputt. Diese Entscheidungen halten die Szene auf dem Laptop flüssig und auf dem Handy gut bedienbar.
Formen, Effekte, Partikel, Spiegelung und Bloom sind Shader. Pro Frame aktualisiert JavaScript nur eine Handvoll Zahlen: Karussell-Position, Mauszeiger und die Winkel der Lotusblätter.
Prozedurales 3D-Noise pro Pixel ist auf großen Glow-Flächen teuer. Eine kachelbare 256 × 256 Noise-Textur, einmal beim Start erzeugt, ersetzt es durch günstige Texturzugriffe.
Jede Kante wird im Shader geglättet. Das Post-Processing-Ziel braucht daher kein teures MSAA.
Die Engine misst die Frame-Zeiten gegen die Bildwiederholrate des Displays. Kommen Frames dauerhaft zu spät, senkt sie die Auflösung schrittweise und hebt sie wieder an, sobald Luft ist.
Die Engine lädt erst, wenn der Bereich in die Nähe kommt, rendert nur, solange er sichtbar ist, und pausiert im Hintergrund-Tab. Der Seitentext ist serverseitig gerendertes HTML und wartet nie auf WebGL.
Der WebGPURenderer nutzt WebGPU, wo der Browser es kann, und wechselt sonst automatisch zu WebGL 2. Derselbe TSL-Code läuft auf beiden.
Für deine Website
Dieselben Bausteine funktionieren weit über Elemente und Lotusblüten hinaus. Ein paar Ideen, wo sich ein interaktiver 3D-Karten-Bereich lohnt:
Der empfohlene Tarif leuchtet, reagiert auf den Mauszeiger und zündet bei der Auswahl.
Jedes Feature bekommt einen eigenen Effekt, der es auf einen Blick erklärt.
Ein Persönlichkeitstyp, eine Empfehlung oder eine Belohnung wird zu einem Moment, an den man sich erinnert.
Seltenheits-Glow, Folien-Effekte und Freischalt-Animationen für Spiele und Communities.
Ein Einstieg, mit dem Besucher spielen wollen, ohne Ladezeit oder SEO zu verschlechtern.
Eine scrollgesteuerte Geschichte für einen Launch, einen Produkt-Drop oder eine Konferenz.
Ich setze genau dein Briefing um: deine Farben, deine Inhalte, die Anzahl der Karten und die Effekte, die du willst, in reinem Three.js oder in React und Next.js. Du bekommst sauberen, dokumentierten Code und einen Bereich, der auch auf dem Handy funktioniert.
TypeScript-, React- & Next.js-EntwicklungIn Browsern mit WebGPU-Unterstützung, etwa aktuellem Chrome und Edge sowie neueren Safari- und Firefox-Versionen auf unterstützten Systemen, läuft WebGPU. Überall sonst läuft derselbe Code mit WebGL 2. Ist beides nicht verfügbar, zeigt der Bereich ein Standbild, und alle Texte bleiben lesbar.
Nicht, wenn er so gebaut ist. Alle Texte sind serverseitig gerendertes HTML, das Suchmaschinen direkt lesen. Die 3D-Engine lädt erst, wenn der Bereich in die Nähe kommt, pausiert außerhalb des Bildschirms, und bis zum ersten Frame zeigt ein leichtes Vorschaubild die Szene.
Ja. Die Engine ist eine framework-unabhängige TypeScript-Klasse, die eine kleine Client-Komponente startet und wieder aufräumt. Diese Seite selbst ist eine Next.js-Seite.
Ja. Farben, Anzahl der Karten, Texte, Icons, Effekte und die Scroll-Geschichte sind anpassbar. Ich setze genau das um, was dein Briefing beschreibt, und kläre offene Gestaltungsfragen vorher mit dir.
Mein Stundensatz liegt bei 75 USD. Der Gesamtaufwand hängt von Anzahl der Karten und Effekte, den Interaktionen und der Einbindung in deine Website ab. Umfang und Schätzung vereinbaren wir, bevor ich anfange.
TSL, die Three.js Shading Language, ermöglicht Shader als JavaScript- oder TypeScript-Funktionen. Three.js kompiliert sie zu WGSL für WebGPU oder zu GLSL für WebGL 2, sodass ein Shader auf beiden läuft.
Erzähl mir, was der Bereich können soll, wo er eingebunden wird und welchen Zeitrahmen du hast. Ich antworte mit Rückfragen oder einer ersten Schätzung.
Design-Inspiration: das Elemental-Cards-Konzept von Zsolt Kacso. Diese Version wurde von Grund auf mit Three.js, WebGPU und TSL neu gebaut. Original-Post auf X