Spline Self-Hosted Files in Webflow

Ich habe ein Webflow-Showcase erstellt, um diese Implementierung in Aktion zu zeigen. Du kannst dir sowohl die einfache als auch die erweiterte Version anschauen – und wenn du es selbst ausprobieren möchtest, kannst du das Projekt ganz einfach klonen und duplizieren.
Spline hat kürzlich eine leistungsstarke Funktion eingeführt: den Export deiner 3D-Szenen als selbst gehostete Pakete. Damit hast du volle Kontrolle darüber, wie und wo deine Spline-Szenen gehostet werden – ideal für individuelle Webseitenprojekte mit besserer Performance, CDN-Geschwindigkeit und Unabhängigkeit von Drittanbietern.
In diesem Tutorial zeige ich dir Schritt für Schritt, wie du eine Spline-Szene als selbst gehostetes Paket exportierst, die Dateien bei BunnyCDN hochlädst und die Szene mithilfe eines <canvas>-Elements und der Spline-Runtime in Webflow einbettest.
Auch wenn dieses Tutorial BunnyCDN als Hosting-Plattform verwendet, kannst du jeden beliebigen statischen Filehost nutzen, der CORS-Header und korrekte MIME-Typen unterstützt. Alternativen sind zum Beispiel Cloudflare R2, AWS S3, Netlify, Vercel oder dein eigener Server. BunnyCDN wird hier vorgestellt, da es besonders schnell, günstig und einfach zu bedienen ist.
Schritt 1: Szene aus Spline exportieren
- Öffne deine Spline-Szene.
- Klicke oben rechts auf Exportieren.
- Wähle Vanilla JS als Exporttyp (nicht React oder Next.js).
- Klicke auf Self Hosted ZIP herunterladen.
- Entpacke das Archiv lokal auf deinem Rechner.
Du solltest folgende Dateien sehen:
- scene.splinecode
- process.js
- process.wasm
- runtime.js
- (optional) physics.js und opentype.js
Schritt 2: Dateien bei BunnyCDN hochladen
- Melde dich in deinem Bunny.net-Dashboard an.
- Öffne deine Pull Zone oder erstelle eine neue.
- Lade alle Dateien aus dem ZIP in einen Ordner hoch, z. B.:
https://dein-cdn.b-cdn.net/spline-szene/
- Stelle sicher, dass diese Dateien öffentlich aufrufbar sind:
- runtime.js
- scene.splinecode
- process.wasm
- process.js
- (optional) opentype.js
- (optional) physics.js
- Gehe im Bunny-Dashboard zu Caching & Delivery > Request Settings > Add CORS Headers:
- Datei-Endungen: js, wasm, splinecode
- Header: Access-Control-Allow-Origin, Wert: *
- Leere optional den Cache für den Ordner, um sicherzustellen, dass die neuen Dateien sofort ausgeliefert werden.
Schritt 3: Szene in Webflow einbetten
- Ziehe in Webflow ein Embed-Element an die gewünschte Stelle auf deiner Seite.
- Füge folgenden Code ein und ersetze die URLs durch die Pfade zu deinem BunnyCDN-Ordner:
<canvas id="spline-container" style="width:100%; height:600px;"></canvas>
<script type="module">
import { Application } from 'https://dein-cdn.b-cdn.net/spline-szene/runtime.js';
const canvas = document.getElementById('spline-container');
const app = new Application(canvas, {
wasmPath: 'https://dein-cdn.b-cdn.net/spline-szene/'
});
app.load('https://dein-cdn.b-cdn.net/spline-szene/scene.splinecode')
.then(() => console.log('Szene geladen'))
.catch((err) => console.error('Ladefehler', err));
</script>
⚠️ Häufige Fehlerquellen
- Achte darauf, dass du beim Export Vanilla JS ausgewählt hast.
- Alle Runtime-Dateien müssen aus demselben Export-Paket stammen.
- Vergewissere dich, dass die CORS-Header und MIME-Typen bei Bunny korrekt gesetzt sind.
- Der Webflow-Vorschaumodus lädt keine externen Skripte – veröffentliche deine Seite zum Testen.
✅ Geschafft!
Wenn alles korrekt eingerichtet ist, sollte deine Spline-Szene jetzt direkt und performant in deiner Webflow-Seite angezeigt werden. Du profitierst von mehr Flexibilität, schnellen Ladezeiten und voller Kontrolle über deine Assets.
Falls etwas nicht funktioniert, prüfe die Konsole deines Browsers auf Fehlermeldungen und stelle sicher, dass alle URLs korrekt und öffentlich erreichbar sind.
Halte Ausschau nach zukünftigen Updates von Spline – neue Exportformate und Runtime-Verbesserungen machen das Self-Hosting noch einfacher.
Erweiterte Lösung für mehrere Spline-Szenen auf einer Seite
Wenn deine Webflow-Seite mehrere Spline-Szenen enthält, brauchst du ein Setup, das Performance-Probleme vermeidet und wiederholten Code reduziert. Die folgende optimierte Lösung sorgt dafür, dass alle Szenen effizient geladen werden – ohne dass das Runtime-Modul mehrfach geladen wird – und bleibt dabei sauber und skalierbar.
✅ Vorteile dieses Setups
- Die Runtime wird nur einmal geladen, unabhängig von der Anzahl der Szenen
- Jede Szene wird lazy-loaded, sobald sie in den Viewport scrollt
- Keine doppelten Downloads von Runtime oder Assets
- Modular & lesbar: Alle Szenen sind klar über Variablen definiert
- Trennung von Struktur und Logik: Der Code lebt im globalen Footer, die Canvas-Elemente auf den jeweiligen Seiten
🔧 So funktioniert es
- Füge das untenstehende Skript in deinen site-wide Footer Embed in Webflow ein.
- Platziere auf der Seite für jede Szene ein <canvas>-Element mit einer eindeutigen id.
- Das Skript erkennt, wann ein Canvas in den Viewport kommt, und lädt die entsprechende Spline-Datei.
- Alle .splinecode-Dateien werden zusätzlich bei Leerlaufzeit im Hintergrund vorgeladen (prefetch), um das spätere Laden zu beschleunigen.
<script>
document.addEventListener("DOMContentLoaded", async function () {
// Pfad zu deinen selbst gehosteten Runtime- und .splinecode-Dateien
const WASM_PATH = 'https://YOUR_CDN_URL_HERE/spline-files/';
// Lade das Runtime-Modul einmal und verwende es wieder
let runtimeModulePromise = import(WASM_PATH + 'runtime.js');
const getRuntime = () => runtimeModulePromise;
// Einfache Warteschlange, damit Szenen nacheinander initialisiert werden
let queue = Promise.resolve();
const enqueue = (task) => (queue = queue.then(task).catch(() => {}));
// Verfolgung, welche Szenen bereits geladen wurden
const initialized = new Set();
// Prüft, ob ein Canvas versteckt ist
const isHidden = (el) => {
if (!el) return true;
const cs = window.getComputedStyle(el);
return cs.display === 'none' || cs.visibility === 'hidden';
};
// Lädt eine Szene in ein Canvas
async function loadScene({ canvasId, splineUrl }) {
if (initialized.has(canvasId)) return;
const canvas = document.getElementById(canvasId);
if (!canvas || isHidden(canvas)) return;
await enqueue(async () => {
const { Application } = await getRuntime();
const app = new Application(canvas, { wasmPath: WASM_PATH });
await app.load(splineUrl);
initialized.add(canvasId);
console.log(`✅ Spline-Szene geladen: ${canvasId}`);
});
}
// Lazy Loading per IntersectionObserver
function lazyLoadScene(cfg) {
const canvas = document.getElementById(cfg.canvasId);
if (!canvas || isHidden(canvas) || initialized.has(cfg.canvasId)) return;
const io = new IntersectionObserver(async (entries, obs) => {
if (!entries[0].isIntersecting) return;
obs.disconnect();
await loadScene(cfg);
}, {
rootMargin: '1000px 0px', // Frühzeitig laden für bessere UX
threshold: 0.05
});
io.observe(canvas);
}
// ---------- KONFIGURATION START ----------
// Hier definierst du alle Szenen
const scenes = [
{
canvasId: 'spline-scene-1',
splineUrl: 'https://YOUR_CDN_URL_HERE/spline-files/scene-1/scene.splinecode'
},
{
canvasId: 'spline-scene-2',
splineUrl: 'https://YOUR_CDN_URL_HERE/spline-files/scene-2/scene.splinecode'
},
{
canvasId: 'spline-scene-3',
splineUrl: 'https://YOUR_CDN_URL_HERE/spline-files/scene-3/scene.splinecode'
}
// Weitere Szenen können hier hinzugefügt werden...
];
// ---------- KONFIGURATION ENDE ----------
// Prefetch: Lade alle .splinecode-Dateien im Hintergrund vor
const idle = window.requestIdleCallback || ((fn) => setTimeout(fn, 250));
idle(() => {
scenes.forEach(s => {
try {
fetch(s.splineUrl, { mode: 'no-cors' });
} catch (_) {}
});
});
// Beobachter für alle Szenen aktivieren
scenes.forEach(lazyLoadScene);
});
</script>
Canvas-Elemente in Webflow einfügen
Füge an jeder Stelle auf deiner Seite, an der eine Spline-Szene erscheinen soll, folgendes ein (z. B. als Embed-Element):
<canvas id="spline-scene-1" style="width: 100%; height: 100%;"></canvas>
<canvas id="spline-scene-2" style="width: 100%; height: 100%;"></canvas>
<canvas id="spline-scene-3" style="width: 100%; height: 100%;"></canvas>
Fazit
Diese Lösung ist ideal, wenn du mehrere Spline-Szenen auf einer Seite nutzt und dabei Wert auf:
- flüssiges Scrollen,
- sauberen und modularen Code,
- geringere Ressourcenbelastung und
- vollständige Kontrolle über Ladeverhalten
legst.
Für einzelne Szenen reicht auch das ursprüngliche Setup – aber sobald es mehrere werden, ist dieses Setup deutlich überlegen.