So habe ich meinen animierten Hintergrund gebaut
Der Hintergrund meiner Startseite ist ein 2D-Canvas, kein Video und kein CSS-Farbverlauf. In jedem Frame wird ein weiches Rauschfeld auf einem Raster abgetastet und entschieden, wo kleine Quadrate erscheinen. Hier ist der Effekt Schicht für Schicht erklärt.
01
Ein Rauschfeld abtasten
Ich beginne mit 3D-Simplex-Noise. Die dritte Koordinate bleibt zunächst bei null. Alle 12 CSS-Pixel nehme ich eine Probe und rechne das Ergebnis von ungefähr −1…1 auf 0…1 um. Die Graustufen zeigen die Rohwerte: Benachbarte Werte ändern sich sanft und bilden Wolken statt zufälligem Bildrauschen.
const noise3D = createNoise3D();
for (let y = 0; y <= height; y += 12) {
for (let x = 0; x <= width; x += 12) {
const value = (noise3D(x * 0.002, y * 0.002, 0) + 1) / 2;
}
}02
Durch das Feld wandern
Die Noise-Funktion hat eine dritte Dimension. Wenn dort die vergangene Zeit eingesetzt wird, entsteht in jedem Frame ein neuer, benachbarter Schnitt. Die Formen verändern sich fließend, ohne dass das ganze Canvas verschoben wird. Mit 0,00004 bleibt die Bewegung dezent (requestAnimationFrame liefert die Zeit in Millisekunden).
const t = time * 0.00004;
const value = (noise3D(x * 0.002, y * 0.002, t) + 1) / 2;
requestAnimationFrame(draw);03
Helle Bereiche auswählen und einfärben
Der Großteil des Feldes soll im dunklen Hintergrund verschwinden. Werte bis 0,6 lasse ich weg und rechne den Rest von 0,6…1 auf 0…1 um. In dieser Zwischenansicht bestimmt der neue Wert die Deckkraft blauer Quadrate. So sieht man die Helligkeitsverteilung vor der endgültigen Ja-oder-nein-Entscheidung.
if (value <= 0.6) continue;
const remapped = (value - 0.6) / (1 - 0.6);
// Nur Vorschau: rgba(76, 169, 239, 0.6 * remapped)04
Punkte durch Dithering erzeugen
Auf der Startseite wird jedes Quadrat entweder gezeichnet oder ausgelassen. Eine wiederholte 4×4-Bayer-Matrix gibt jeder Rasterposition einen anderen Schwellenwert. Der Vergleich mit der umgerechneten Helligkeit macht aus weichen Flächen gemusterte Gruppen gleichfarbiger blauer Punkte. Die Matrixwerte werden um 0,5 erhöht und durch 16 geteilt, damit sie zwischen null und eins liegen.
const spacing = 12;
if (value <= 0.6) continue;
const remapped = (value - 0.6) / (1 - 0.6);
const bayer = [
[0, 8, 2, 10], [12, 4, 14, 6],
[3, 11, 1, 9], [15, 7, 13, 5],
];
const threshold = (bayer[row % 4][col % 4] + 0.5) / 16;
if (remapped > threshold) {
ctx.fillRect(x - 2.5, y - 2.5, 5, 5);
}Alles zusammensetzen
Wechsle zwischen den vier Schichten und sieh dir an, wie aus demselben Rauschfeld der fertige Hintergrund wird: Rohwerte, Bewegung, farbige Highlights und schließlich geditherte Punkte.
Performance beachten
Das Noise wird in JavaScript abgetastet und das Canvas in jedem Animationsframe gelöscht und neu gezeichnet. Für den Aufwand zählt vor allem die Zahl der Noise-Abtastungen, nicht nur die Zahl der sichtbaren Punkte.
-
Das Raster nicht zu fein machen
Bei 12 px Abstand braucht ein Canvas mit 1920 × 1080 Pixeln etwa 14.600 Noise-Abtastungen pro Frame. Ein halb so großer Abstand vervierfacht diesen Aufwand ungefähr. Die Rasterweite bestimmt also sowohl das Aussehen als auch die Rechenlast.
-
Unnötiges Zeichnen vermeiden
Werte unter der Helligkeitsschwelle erreichen fillRect nicht. Darüber werden dank Bayer-Dithering nur Quadrate gezeichnet, die den Schwellenwert überschreiten. Das Noise wird weiterhin an jedem Rasterpunkt abgetastet, aber es werden weniger Rechtecke gemalt.
-
Display und Nutzerwünsche berücksichtigen
requestAnimationFrame plant die Frames gemeinsam mit dem Browser. Die Canvas-Auflösung folgt devicePixelRatio, wird aber zur Begrenzung des Pixel-Speichers bei 2 gedeckelt. Größenänderungen werden um 120 ms verzögert; bei reduzierter Bewegung gibt es statt einer Animation nur ein Standbild.
-
Nur Sichtbares animieren
Anders als das einzelne, bildschirmfüllende Canvas der Startseite enthält diese Anleitung mehrere Vorschauen. Jede nutzt einen IntersectionObserver, um außerhalb des sichtbaren Bereichs keine neuen Frames anzufordern und beim Zurückscrollen wieder zu starten.
Auf der Seite einbauen
Das fertige Canvas liegt hinter dem Inhalt der Startseite und füllt seinen Container. In jedem Frame wird es gelöscht und neu gezeichnet. Für hochauflösende Displays skaliere ich die Canvas-Pixel; bei Größenänderungen passe ich sie erneut an. Bei reduzierter Bewegung zeichne ich nur ein Standbild. Die Vorschauen oben pausieren außerdem außerhalb des sichtbaren Bereichs.
Auf der Startseite ansehen →