Spline - 3D Design w Przeglądarce
Czym jest Spline?
Spline to rewolucyjne narzędzie do tworzenia interaktywnych scen 3D bezpośrednio w przeglądarce, bez potrzeby instalowania skomplikowanego oprogramowania jak Blender czy Cinema 4D. Spline demokratyzuje 3D design, pozwalając nawet osobom bez doświadczenia w 3D tworzyć imponujące, interaktywne elementy dla stron internetowych, aplikacji i prezentacji.
To co wyróżnia Spline na tle tradycyjnych narzędzi 3D to nacisk na interaktywność i web. Sceny stworzone w Spline nie są statyczne - można dodawać animacje reagujące na hover, click, scroll, a nawet ruchy kursora. Gotowy projekt eksportuje się jako embed, kod React lub link, który można natychmiast osadzić na stronie.
Spline szybko zyskał popularność wśród web developerów i designerów, którzy chcą dodać elementy 3D do swoich projektów bez nauki skomplikowanych narzędzi. Firmy takie jak Figma, Linear czy Framer używają Spline do tworzenia interaktywnych elementów na swoich stronach.
Dlaczego Spline?
Kluczowe zalety
- Browser-based - Działa w przeglądarce, bez instalacji
- No-code 3D - Twórz 3D bez znajomości programowania
- Interaktywność - Hover, click, scroll, keyboard events
- Web-native export - React, iframe, vanilla JS
- Real-time collaboration - Praca zespołowa w czasie rzeczywistym
- Physics engine - Symulacja grawitacji i kolizji
- PBR Materials - Realistyczne materiały
- Animation timeline - Keyframe animations
- State machines - Zaawansowane interakcje
- Cloud storage - Projekty w chmurze
Spline vs tradycyjne narzędzia 3D
| Cecha | Spline | Blender | Three.js | Figma |
|---|---|---|---|---|
| Krzywa nauki | Łatwa | Trudna | Średnia | Brak 3D |
| Browser-based | ✅ | ❌ | ✅ (runtime) | ✅ |
| Interaktywność | ✅ Built-in | ❌ | ✅ Manual | ❌ |
| Web export | ✅ One-click | ⚠️ Dodatkowe | ✅ Natywny | ❌ |
| Real-time collab | ✅ | ❌ | ❌ | ✅ |
| Cena | Free/$9/mo | Free | Free | Free/$15/mo |
| Cel | Web 3D | Full 3D | Code 3D | 2D UI |
Interfejs Spline
Pasek narzędzi
┌─────────────────────────────────────────────────────────────┐
│ TOOLBAR │
├─────────────────────────────────────────────────────────────┤
│ 🔲 Select - Zaznaczanie obiektów │
│ ↔️ Transform - Przesuwanie, skalowanie, obracanie │
│ ⬜ Cube - Tworzenie sześcianu │
│ ⚪ Sphere - Tworzenie kuli │
│ 🔵 Cylinder - Tworzenie cylindra │
│ 🍩 Torus - Tworzenie torusa │
│ 📐 Plane - Tworzenie płaszczyzny │
│ ✏️ Path - Rysowanie ścieżek │
│ 🅰️ Text 3D - Tekst przestrzenny │
│ 💡 Light - Dodawanie świateł │
│ 📷 Camera - Dodawanie kamer │
│ 🎮 Events - Dodawanie interakcji │
└─────────────────────────────────────────────────────────────┘Panel właściwości
┌─────────────────────────────────────────────────────────────┐
│ PROPERTIES │
├─────────────────────────────────────────────────────────────┤
│ Transform: │
│ Position: X [0] Y [0] Z [0] │
│ Rotation: X [0] Y [0] Z [0] │
│ Scale: X [1] Y [1] Z [1] │
│ │
│ Material: │
│ Type: [Glass ▼] │
│ Color: [#3B82F6] │
│ Metalness: [0.5] ───────────── │
│ Roughness: [0.2] ───── │
│ Opacity: [0.8] ─────────── │
│ │
│ Events: │
│ [+ Add Event] │
│ └─ On Hover → Rotate Y 45° │
│ └─ On Click → Scale 1.2 │
└─────────────────────────────────────────────────────────────┘Modelowanie 3D
Podstawowe prymitywy
// Dostępne prymitywy w Spline:
// Geometric Primitives
- Cube // Sześcian, modyfikowalne wymiary
- Sphere // Kula z kontrolą segmentów
- Cylinder // Cylinder z radius top/bottom
- Torus // Torus z inner/outer radius
- Cone // Stożek
- Plane // Płaszczyzna
- Capsule // Kapsuła
// Advanced Shapes
- Parametric // Kształty parametryczne
- Extrude // Wyciągnięcie z profilu
- Lathe // Obrót profilu
- Text 3D // Tekst przestrzenny
- SVG // Import i wyciągnięcie SVGBoolean Operations
// Operacje boolean pozwalają łączyć kształty:
Union (Suma):
┌───┐
│ ■ │ + ● = ┌───●
│ │ │
└───┘ └───┘
Subtract (Różnica):
┌───┐
│ ■ │ - ● = ┌───╮
│ │ │ ╰──
└───┘ └───┘
Intersect (Część wspólna):
┌───┐
│ ■ │ ∩ ● = ╭──╮
│ │ │ │
└───┘ ╰──╯Sculpting & Deformation
// Narzędzia deformacji:
Bend - Wyginanie obiektu
Twist - Skręcanie wzdłuż osi
Taper - Zwężanie/rozszerzanie
Noise - Dodawanie szumu do powierzchni
Subdivide - Zwiększenie geometrii
Smooth - Wygładzanie krawędziMateriały i tekstury
PBR Materials
Spline używa fizycznie poprawnego renderowania (PBR):
// Właściwości materiałów PBR:
Material Properties:
├── Base Color // Kolor bazowy
├── Metalness // 0 (dielektryk) - 1 (metal)
├── Roughness // 0 (lustro) - 1 (matowy)
├── Normal Map // Szczegóły powierzchni
├── Emissive // Emisja światła
├── Opacity // Przezroczystość
└── Refraction // Załamanie światła
// Presety materiałów:
- Glass // Szkło przezroczyste
- Metal // Metaliczny połysk
- Plastic // Plastik
- Ceramic // Ceramika
- Rubber // Guma
- Wood // Drewno
- Fabric // TkaninaCustom Shaders
// Spline pozwala na custom shaders:
Gradient Material:
- Start Color: #3B82F6
- End Color: #8B5CF6
- Direction: Y (vertical)
Fresnel Effect:
- Base Color: #1E40AF
- Fresnel Color: #60A5FA
- Fresnel Power: 3.0
Matcap:
- Wybierz z biblioteki matcaps
- Idealne dla stylizowanych renderówOświetlenie
// Typy świateł:
Directional Light:
- Równoległe promienie (słońce)
- Shadows: Soft/Hard/None
Point Light:
- Źródło punktowe
- Range, Intensity
Spot Light:
- Stożek światła
- Angle, Penumbra
Area Light:
- Światło powierzchniowe
- Size, Softness
Ambient Light:
- Globalne oświetlenie
- Intensity, Color
HDRI Environment:
- Import obrazów HDRI
- Realistyczne odbiciaAnimacje
State-based Animations
// Stany (States) to kluczowa funkcja Spline:
Base State (default):
├── Position: (0, 0, 0)
├── Rotation: (0, 0, 0)
└── Scale: (1, 1, 1)
Hover State:
├── Position: (0, 0.5, 0) // Unosi się
├── Rotation: (0, 15, 0) // Obraca
└── Scale: (1.1, 1.1, 1.1) // Powiększa
Click State:
├── Position: (0, 0, 0)
├── Rotation: (0, 180, 0) // Pełny obrót
└── Scale: (0.9, 0.9, 0.9) // Zmniejsza
// Transition settings:
- Duration: 0.3s
- Easing: ease-out
- Delay: 0sTimeline Animations
// Keyframe animations na timeline:
Timeline:
0s ────────── 1s ────────── 2s ────────── 3s
│ │ │ │
├── Keyframe ├── Keyframe ├── Keyframe ├── Loop
│ Pos(0,0,0)│ Pos(0,2,0)│ Pos(0,0,0)│
│ Rot(0°) │ Rot(180°) │ Rot(360°) │
// Opcje:
- Loop: Play once / Loop / Ping-pong
- Easing: Linear / Ease / Bounce / etc.
- Autoplay: On scene loadPhysics Animations
// Wbudowany silnik fizyki:
Rigid Body:
├── Mass: 1.0
├── Friction: 0.5
├── Restitution: 0.3 // Odbicie
└── Gravity: -9.8
Constraints:
├── Fixed // Zamocowany
├── Hinge // Zawias
├── Slider // Suwak
└── Spring // Sprężyna
// Przykład: Ball drop
1. Create sphere
2. Add Rigid Body
3. Create plane (floor)
4. Enable collision
5. Play physics simulationInteraktywność
Event System
// Dostępne wydarzenia:
Mouse Events:
├── On Hover (Mouse Enter)
├── On Hover Out (Mouse Leave)
├── On Click (Mouse Down)
├── On Mouse Up
└── On Mouse Move
Scroll Events:
├── On Scroll
└── On Scroll In View
Keyboard Events:
├── On Key Down
└── On Key Up
Scene Events:
├── On Start (Scene Load)
└── On Look At (Camera focus)
// Akcje po wydarzeniu:
- Change State
- Play Animation
- Toggle Visibility
- Change Variable
- Navigate to URL
- Play SoundPrzykłady interakcji
// Interaktywny przycisk 3D:
Object: Button3D
Events:
├── On Hover:
│ └── Change State → "Hover"
│ - Scale: 1.05
│ - Color: #60A5FA
│ - Transition: 0.2s
├── On Click:
│ └── Change State → "Pressed"
│ - Scale: 0.95
│ - Play Sound: "click.mp3"
│ - After 0.1s → Navigate to "/signup"
└── On Hover Out:
└── Change State → "Default"
// Rotujący produkt:
Object: ProductModel
Events:
├── On Mouse Move:
│ └── Rotate Y: mouse.x * 0.5
└── On Scroll:
└── Camera zoom: scroll.y * 0.1
// Parallax effect:
Layer1: On Mouse Move → offset(x*0.1, y*0.1)
Layer2: On Mouse Move → offset(x*0.2, y*0.2)
Layer3: On Mouse Move → offset(x*0.3, y*0.3)Export do Web
React Component
# Instalacja
npm install @splinetool/react-spline
# lub
pnpm add @splinetool/react-spline// components/SplineScene.tsx
import Spline from '@splinetool/react-spline'
import type { Application } from '@splinetool/runtime'
import { useRef } from 'react'
export function SplineScene() {
const splineRef = useRef<Application | null>(null)
function onLoad(spline: Application) {
splineRef.current = spline
// Dostęp do obiektów w scenie
const cube = spline.findObjectByName('Cube')
console.log('Cube loaded:', cube)
}
function handleClick() {
if (!splineRef.current) return
// Programowa interakcja
const button = splineRef.current.findObjectByName('Button')
if (button) {
button.emitEvent('mouseDown')
}
}
return (
<div className="h-screen w-full">
<Spline
scene="https://prod.spline.design/xxxxx/scene.splinecode"
onLoad={onLoad}
/>
<button onClick={handleClick}>
Trigger 3D Button
</button>
</div>
)
}Next.js Integration
// app/page.tsx
'use client'
import dynamic from 'next/dynamic'
// Dynamic import dla SSR compatibility
const Spline = dynamic(
() => import('@splinetool/react-spline'),
{
ssr: false,
loading: () => (
<div className="h-screen w-full flex items-center justify-center">
<div className="animate-spin rounded-full h-12 w-12 border-t-2 border-primary" />
</div>
)
}
)
export default function Home() {
return (
<main className="relative">
{/* Hero z 3D */}
<section className="h-screen relative">
<div className="absolute inset-0 z-0">
<Spline scene="https://prod.spline.design/hero/scene.splinecode" />
</div>
<div className="relative z-10 flex items-center justify-center h-full">
<div className="text-center text-white">
<h1 className="text-6xl font-bold mb-4">
Welcome to the Future
</h1>
<p className="text-xl">
Interactive 3D experiences for the web
</p>
</div>
</div>
</section>
</main>
)
}Vanilla JavaScript
<!DOCTYPE html>
<html>
<head>
<title>Spline Scene</title>
<style>
#canvas3d {
width: 100%;
height: 100vh;
}
</style>
</head>
<body>
<canvas id="canvas3d"></canvas>
<script type="module">
import { Application } from '@splinetool/runtime'
const canvas = document.getElementById('canvas3d')
const app = new Application(canvas)
app.load('https://prod.spline.design/xxxxx/scene.splinecode')
.then(() => {
console.log('Scene loaded!')
// Znajdź obiekt po nazwie
const cube = app.findObjectByName('Cube')
// Nasłuchuj na eventy
cube.addEventListener('mouseDown', () => {
console.log('Cube clicked!')
})
// Animuj programowo
function animate() {
cube.rotation.y += 0.01
requestAnimationFrame(animate)
}
animate()
})
</script>
</body>
</html>Iframe Embed
<!-- Najprostszy sposób osadzenia -->
<iframe
src="https://my.spline.design/untitled-xxxxx/"
frameborder="0"
width="100%"
height="500px"
allowfullscreen
></iframe>
<!-- Responsive iframe -->
<div style="position: relative; padding-bottom: 56.25%; height: 0;">
<iframe
src="https://my.spline.design/untitled-xxxxx/"
style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"
frameborder="0"
allowfullscreen
></iframe>
</div>API Programistyczne
// Spline Runtime API
interface SplineApplication {
// Scena
load(url: string): Promise<void>
// Znajdowanie obiektów
findObjectByName(name: string): SplineObject | undefined
findObjectById(id: string): SplineObject | undefined
getAllObjects(): SplineObject[]
// Eventy
addEventListener(event: string, callback: Function): void
removeEventListener(event: string, callback: Function): void
// Kontrola
play(): void
pause(): void
setZoom(level: number): void
// Zmienne
setVariable(name: string, value: any): void
getVariable(name: string): any
}
interface SplineObject {
// Transformacje
position: { x: number; y: number; z: number }
rotation: { x: number; y: number; z: number }
scale: { x: number; y: number; z: number }
// Widoczność
visible: boolean
// Eventy
emitEvent(eventType: string): void
addEventListener(event: string, callback: Function): void
// Dzieci
children: SplineObject[]
parent: SplineObject | null
}Use Cases
Hero Sections z 3D
// components/Hero3D.tsx
export function Hero3D() {
return (
<section className="relative h-screen overflow-hidden">
{/* 3D Background */}
<div className="absolute inset-0">
<Spline
scene="https://prod.spline.design/abstract-shapes/scene.splinecode"
style={{ width: '100%', height: '100%' }}
/>
</div>
{/* Gradient overlay */}
<div className="absolute inset-0 bg-gradient-to-t from-black/80 to-transparent" />
{/* Content */}
<div className="relative z-10 flex items-center justify-center h-full">
<div className="text-center text-white max-w-3xl px-4">
<h1 className="text-5xl md:text-7xl font-bold mb-6">
3D Made Easy
</h1>
<p className="text-xl mb-8 text-white/80">
Create stunning interactive 3D experiences without code
</p>
<button className="bg-white text-black px-8 py-4 rounded-full font-semibold hover:scale-105 transition">
Get Started Free
</button>
</div>
</div>
</section>
)
}Product Showcase
// components/ProductShowcase.tsx
import Spline from '@splinetool/react-spline'
import { useState } from 'react'
const colors = [
{ name: 'Black', value: '#000000' },
{ name: 'Silver', value: '#C0C0C0' },
{ name: 'Gold', value: '#FFD700' },
]
export function ProductShowcase() {
const [selectedColor, setSelectedColor] = useState(colors[0])
const [spline, setSpline] = useState<Application | null>(null)
function onLoad(app: Application) {
setSpline(app)
}
function changeColor(color: typeof colors[0]) {
setSelectedColor(color)
if (spline) {
spline.setVariable('productColor', color.value)
}
}
return (
<section className="py-20 bg-gray-50">
<div className="container mx-auto px-4">
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
{/* 3D Model */}
<div className="h-[500px] bg-white rounded-2xl shadow-lg overflow-hidden">
<Spline
scene="https://prod.spline.design/product/scene.splinecode"
onLoad={onLoad}
/>
</div>
{/* Product Info */}
<div>
<span className="text-primary font-semibold">New Arrival</span>
<h2 className="text-4xl font-bold mt-2 mb-4">
Premium Headphones
</h2>
<p className="text-gray-600 mb-8">
Experience crystal-clear audio with our flagship headphones.
Drag to rotate the 3D model.
</p>
{/* Color Selector */}
<div className="mb-8">
<span className="text-sm font-medium text-gray-500">
Color: {selectedColor.name}
</span>
<div className="flex gap-3 mt-2">
{colors.map((color) => (
<button
key={color.name}
onClick={() => changeColor(color)}
className={`w-10 h-10 rounded-full border-2 transition ${
selectedColor.name === color.name
? 'border-primary scale-110'
: 'border-transparent'
}`}
style={{ backgroundColor: color.value }}
/>
))}
</div>
</div>
<div className="flex items-center gap-4">
<span className="text-3xl font-bold">$349</span>
<button className="bg-primary text-white px-8 py-3 rounded-lg hover:bg-primary/90 transition">
Add to Cart
</button>
</div>
</div>
</div>
</div>
</section>
)
}Interactive Logo
// components/InteractiveLogo.tsx
export function InteractiveLogo() {
return (
<div className="w-48 h-48 cursor-pointer">
<Spline
scene="https://prod.spline.design/logo/scene.splinecode"
// Logo reaguje na hover i click automatycznie
// dzięki events zdefiniowanym w Spline
/>
</div>
)
}Data Visualization
// components/DataViz3D.tsx
import { useEffect, useRef } from 'react'
interface DataPoint {
label: string
value: number
}
export function DataViz3D({ data }: { data: DataPoint[] }) {
const splineRef = useRef<Application | null>(null)
useEffect(() => {
if (!splineRef.current) return
// Aktualizuj wysokości słupków w 3D
data.forEach((point, index) => {
const bar = splineRef.current?.findObjectByName(`bar_${index}`)
if (bar) {
bar.scale.y = point.value / 100
}
})
}, [data])
return (
<div className="h-[400px] bg-gray-900 rounded-xl">
<Spline
scene="https://prod.spline.design/chart/scene.splinecode"
onLoad={(app) => { splineRef.current = app }}
/>
</div>
)
}Optymalizacja wydajności
Best Practices
// Optymalizacja scen Spline:
// 1. Geometria
- Używaj low-poly gdzie możliwe
- Limit vertices: < 100k dla mobile
- Merge static objects
- Use instances for repeated objects
// 2. Materiały
- Ogranicz unique materials
- Unikaj heavy shaders na mobile
- Compress textures (max 2048px)
- Use matcaps zamiast PBR gdzie możliwe
// 3. Lighting
- Max 3-4 światła na scenę
- Baked lighting dla static scenes
- Disable shadows na mobile
// 4. Animacje
- Ogranicz physics objects
- Use CSS transforms gdzie możliwe
- Pausuj animacje poza viewport
// 5. Loading
- Lazy load Spline components
- Show loading placeholder
- Preload critical scenesLazy Loading w React
// components/LazySpline.tsx
import { useInView } from 'react-intersection-observer'
import dynamic from 'next/dynamic'
const Spline = dynamic(() => import('@splinetool/react-spline'), {
ssr: false,
})
export function LazySpline({ scene }: { scene: string }) {
const { ref, inView } = useInView({
triggerOnce: true,
rootMargin: '200px',
})
return (
<div ref={ref} className="h-[500px]">
{inView ? (
<Spline scene={scene} />
) : (
<div className="h-full bg-gray-100 animate-pulse rounded-xl" />
)}
</div>
)
}Cennik
| Plan | Cena | Zawiera |
|---|---|---|
| Free | $0 | Unlimited projekty, Spline watermark, Public scenes |
| Pro | $9/mo | No watermark, Private scenes, Priority export |
| Team | $29/user/mo | Collaboration, Shared libraries, Admin controls |
| Enterprise | Custom | SSO, Dedicated support, Custom features |
FAQ - Najczęściej zadawane pytania
Czy Spline jest darmowy?
Tak, darmowy plan pozwala na unlimited projekty i eksport. Jedynym ograniczeniem jest watermark i publiczność scen.
Czy potrzebuję umiejętności 3D?
Nie, Spline jest zaprojektowany dla osób bez doświadczenia w 3D. Interface jest intuicyjny, podobny do narzędzi 2D jak Figma.
Jak dobrze działa na mobile?
Sceny Spline działają na mobile, ale wymagają optymalizacji. Zalecana jest niska liczba polygonów i uproszczone materiały.
Czy mogę eksportować do plików 3D?
Tak, Spline pozwala na eksport do GLTF/GLB, który można użyć w innych aplikacjach 3D lub Three.js.
Jak współpracować z zespołem?
Plan Team pozwala na real-time collaboration, podobnie jak w Figma. Wielu użytkowników może edytować tę samą scenę.
Czy Spline używa WebGL?
Tak, Spline używa WebGL do renderowania. Działa we wszystkich nowoczesnych przeglądarkach.
Podsumowanie
Spline rewolucjonizuje 3D design dla web:
- Browser-based - Twórz 3D bez instalacji
- No-code friendly - Intuicyjny interface
- Interaktywność - Hover, click, scroll events
- Web-native - React, iframe, vanilla JS export
- Real-time collaboration - Praca zespołowa
- Physics engine - Symulacje grawitacji i kolizji
Spline to idealne narzędzie dla web developerów i designerów, którzy chcą dodać interaktywne elementy 3D do swoich projektów bez nauki skomplikowanego oprogramowania.
Spline - 3D design in the browser
What is Spline?
Spline is a revolutionary tool for creating interactive 3D scenes directly in the browser, without needing to install complex software like Blender or Cinema 4D. Spline democratizes 3D design, allowing even people with no 3D experience to create impressive, interactive elements for websites, applications, and presentations.
What sets Spline apart from traditional 3D tools is its focus on interactivity and the web. Scenes created in Spline are not static - you can add animations that respond to hover, click, scroll, and even cursor movement. The finished project can be exported as an embed, React code, or a link that can be immediately embedded on a page.
Spline quickly gained popularity among web developers and designers who want to add 3D elements to their projects without learning complex tools. Companies like Figma, Linear, and Framer use Spline to create interactive elements on their websites.
Why Spline?
Key advantages
- Browser-based - Works in the browser, no installation needed
- No-code 3D - Create 3D without programming knowledge
- Interactivity - Hover, click, scroll, keyboard events
- Web-native export - React, iframe, vanilla JS
- Real-time collaboration - Teamwork in real time
- Physics engine - Gravity and collision simulation
- PBR Materials - Realistic materials
- Animation timeline - Keyframe animations
- State machines - Advanced interactions
- Cloud storage - Projects in the cloud
Spline vs traditional 3D tools
| Feature | Spline | Blender | Three.js | Figma |
|---|---|---|---|---|
| Learning curve | Easy | Hard | Medium | No 3D |
| Browser-based | ✅ | ❌ | ✅ (runtime) | ✅ |
| Interactivity | ✅ Built-in | ❌ | ✅ Manual | ❌ |
| Web export | ✅ One-click | ⚠️ Additional | ✅ Native | ❌ |
| Real-time collab | ✅ | ❌ | ❌ | ✅ |
| Price | Free/$9/mo | Free | Free | Free/$15/mo |
| Purpose | Web 3D | Full 3D | Code 3D | 2D UI |
Spline interface
Toolbar
┌─────────────────────────────────────────────────────────────┐
│ TOOLBAR │
├─────────────────────────────────────────────────────────────┤
│ 🔲 Select - Select objects │
│ ↔️ Transform - Move, scale, rotate │
│ ⬜ Cube - Create a cube │
│ ⚪ Sphere - Create a sphere │
│ 🔵 Cylinder - Create a cylinder │
│ 🍩 Torus - Create a torus │
│ 📐 Plane - Create a plane │
│ ✏️ Path - Draw paths │
│ 🅰️ Text 3D - 3D text │
│ 💡 Light - Add lights │
│ 📷 Camera - Add cameras │
│ 🎮 Events - Add interactions │
└─────────────────────────────────────────────────────────────┘Properties panel
┌─────────────────────────────────────────────────────────────┐
│ PROPERTIES │
├─────────────────────────────────────────────────────────────┤
│ Transform: │
│ Position: X [0] Y [0] Z [0] │
│ Rotation: X [0] Y [0] Z [0] │
│ Scale: X [1] Y [1] Z [1] │
│ │
│ Material: │
│ Type: [Glass ▼] │
│ Color: [#3B82F6] │
│ Metalness: [0.5] ───────────── │
│ Roughness: [0.2] ───── │
│ Opacity: [0.8] ─────────── │
│ │
│ Events: │
│ [+ Add Event] │
│ └─ On Hover → Rotate Y 45° │
│ └─ On Click → Scale 1.2 │
└─────────────────────────────────────────────────────────────┘3D modeling
Basic primitives
// Available primitives in Spline:
// Geometric Primitives
- Cube // Cube with modifiable dimensions
- Sphere // Sphere with segment control
- Cylinder // Cylinder with radius top/bottom
- Torus // Torus with inner/outer radius
- Cone // Cone
- Plane // Plane
- Capsule // Capsule
// Advanced Shapes
- Parametric // Parametric shapes
- Extrude // Extrusion from a profile
- Lathe // Profile revolution
- Text 3D // 3D text
- SVG // Import and extrude SVGBoolean operations
// Boolean operations allow you to combine shapes:
Union (Sum):
┌───┐
│ ■ │ + ● = ┌───●
│ │ │
└───┘ └───┘
Subtract (Difference):
┌───┐
│ ■ │ - ● = ┌───╮
│ │ │ ╰──
└───┘ └───┘
Intersect (Intersection):
┌───┐
│ ■ │ ∩ ● = ╭──╮
│ │ │ │
└───┘ ╰──╯Sculpting & deformation
// Deformation tools:
Bend - Bending an object
Twist - Twisting along an axis
Taper - Narrowing/widening
Noise - Adding noise to a surface
Subdivide - Increasing geometry
Smooth - Smoothing edgesMaterials and textures
PBR materials
Spline uses physically based rendering (PBR):
// PBR material properties:
Material Properties:
├── Base Color // Base color
├── Metalness // 0 (dielectric) - 1 (metal)
├── Roughness // 0 (mirror) - 1 (matte)
├── Normal Map // Surface details
├── Emissive // Light emission
├── Opacity // Transparency
└── Refraction // Light refraction
// Material presets:
- Glass // Transparent glass
- Metal // Metallic shine
- Plastic // Plastic
- Ceramic // Ceramic
- Rubber // Rubber
- Wood // Wood
- Fabric // FabricCustom shaders
// Spline allows custom shaders:
Gradient Material:
- Start Color: #3B82F6
- End Color: #8B5CF6
- Direction: Y (vertical)
Fresnel Effect:
- Base Color: #1E40AF
- Fresnel Color: #60A5FA
- Fresnel Power: 3.0
Matcap:
- Choose from the matcap library
- Ideal for stylized rendersLighting
// Light types:
Directional Light:
- Parallel rays (sun)
- Shadows: Soft/Hard/None
Point Light:
- Point source
- Range, Intensity
Spot Light:
- Light cone
- Angle, Penumbra
Area Light:
- Surface light
- Size, Softness
Ambient Light:
- Global illumination
- Intensity, Color
HDRI Environment:
- Import HDRI images
- Realistic reflectionsAnimations
State-based animations
// States are a key feature of Spline:
Base State (default):
├── Position: (0, 0, 0)
├── Rotation: (0, 0, 0)
└── Scale: (1, 1, 1)
Hover State:
├── Position: (0, 0.5, 0) // Floats up
├── Rotation: (0, 15, 0) // Rotates
└── Scale: (1.1, 1.1, 1.1) // Scales up
Click State:
├── Position: (0, 0, 0)
├── Rotation: (0, 180, 0) // Full rotation
└── Scale: (0.9, 0.9, 0.9) // Scales down
// Transition settings:
- Duration: 0.3s
- Easing: ease-out
- Delay: 0sTimeline animations
// Keyframe animations on the timeline:
Timeline:
0s ────────── 1s ────────── 2s ────────── 3s
│ │ │ │
├── Keyframe ├── Keyframe ├── Keyframe ├── Loop
│ Pos(0,0,0)│ Pos(0,2,0)│ Pos(0,0,0)│
│ Rot(0°) │ Rot(180°) │ Rot(360°) │
// Options:
- Loop: Play once / Loop / Ping-pong
- Easing: Linear / Ease / Bounce / etc.
- Autoplay: On scene loadPhysics animations
// Built-in physics engine:
Rigid Body:
├── Mass: 1.0
├── Friction: 0.5
├── Restitution: 0.3 // Bounce
└── Gravity: -9.8
Constraints:
├── Fixed // Fixed in place
├── Hinge // Hinge joint
├── Slider // Slider joint
└── Spring // Spring joint
// Example: Ball drop
1. Create sphere
2. Add Rigid Body
3. Create plane (floor)
4. Enable collision
5. Play physics simulationInteractivity
Event system
// Available events:
Mouse Events:
├── On Hover (Mouse Enter)
├── On Hover Out (Mouse Leave)
├── On Click (Mouse Down)
├── On Mouse Up
└── On Mouse Move
Scroll Events:
├── On Scroll
└── On Scroll In View
Keyboard Events:
├── On Key Down
└── On Key Up
Scene Events:
├── On Start (Scene Load)
└── On Look At (Camera focus)
// Actions after an event:
- Change State
- Play Animation
- Toggle Visibility
- Change Variable
- Navigate to URL
- Play SoundInteraction examples
// Interactive 3D button:
Object: Button3D
Events:
├── On Hover:
│ └── Change State → "Hover"
│ - Scale: 1.05
│ - Color: #60A5FA
│ - Transition: 0.2s
├── On Click:
│ └── Change State → "Pressed"
│ - Scale: 0.95
│ - Play Sound: "click.mp3"
│ - After 0.1s → Navigate to "/signup"
└── On Hover Out:
└── Change State → "Default"
// Rotating product:
Object: ProductModel
Events:
├── On Mouse Move:
│ └── Rotate Y: mouse.x * 0.5
└── On Scroll:
└── Camera zoom: scroll.y * 0.1
// Parallax effect:
Layer1: On Mouse Move → offset(x*0.1, y*0.1)
Layer2: On Mouse Move → offset(x*0.2, y*0.2)
Layer3: On Mouse Move → offset(x*0.3, y*0.3)Export to web
React component
# Installation
npm install @splinetool/react-spline
# or
pnpm add @splinetool/react-spline// components/SplineScene.tsx
import Spline from '@splinetool/react-spline'
import type { Application } from '@splinetool/runtime'
import { useRef } from 'react'
export function SplineScene() {
const splineRef = useRef<Application | null>(null)
function onLoad(spline: Application) {
splineRef.current = spline
const cube = spline.findObjectByName('Cube')
console.log('Cube loaded:', cube)
}
function handleClick() {
if (!splineRef.current) return
const button = splineRef.current.findObjectByName('Button')
if (button) {
button.emitEvent('mouseDown')
}
}
return (
<div className="h-screen w-full">
<Spline
scene="https://prod.spline.design/xxxxx/scene.splinecode"
onLoad={onLoad}
/>
<button onClick={handleClick}>
Trigger 3D Button
</button>
</div>
)
}Next.js integration
// app/page.tsx
'use client'
import dynamic from 'next/dynamic'
const Spline = dynamic(
() => import('@splinetool/react-spline'),
{
ssr: false,
loading: () => (
<div className="h-screen w-full flex items-center justify-center">
<div className="animate-spin rounded-full h-12 w-12 border-t-2 border-primary" />
</div>
)
}
)
export default function Home() {
return (
<main className="relative">
{/* Hero with 3D */}
<section className="h-screen relative">
<div className="absolute inset-0 z-0">
<Spline scene="https://prod.spline.design/hero/scene.splinecode" />
</div>
<div className="relative z-10 flex items-center justify-center h-full">
<div className="text-center text-white">
<h1 className="text-6xl font-bold mb-4">
Welcome to the Future
</h1>
<p className="text-xl">
Interactive 3D experiences for the web
</p>
</div>
</div>
</section>
</main>
)
}Vanilla JavaScript
<!DOCTYPE html>
<html>
<head>
<title>Spline Scene</title>
<style>
#canvas3d {
width: 100%;
height: 100vh;
}
</style>
</head>
<body>
<canvas id="canvas3d"></canvas>
<script type="module">
import { Application } from '@splinetool/runtime'
const canvas = document.getElementById('canvas3d')
const app = new Application(canvas)
app.load('https://prod.spline.design/xxxxx/scene.splinecode')
.then(() => {
console.log('Scene loaded!')
const cube = app.findObjectByName('Cube')
cube.addEventListener('mouseDown', () => {
console.log('Cube clicked!')
})
function animate() {
cube.rotation.y += 0.01
requestAnimationFrame(animate)
}
animate()
})
</script>
</body>
</html>Iframe embed
<!-- Simplest way to embed -->
<iframe
src="https://my.spline.design/untitled-xxxxx/"
frameborder="0"
width="100%"
height="500px"
allowfullscreen
></iframe>
<!-- Responsive iframe -->
<div style="position: relative; padding-bottom: 56.25%; height: 0;">
<iframe
src="https://my.spline.design/untitled-xxxxx/"
style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"
frameborder="0"
allowfullscreen
></iframe>
</div>Programming API
// Spline Runtime API
interface SplineApplication {
// Scene
load(url: string): Promise<void>
// Finding objects
findObjectByName(name: string): SplineObject | undefined
findObjectById(id: string): SplineObject | undefined
getAllObjects(): SplineObject[]
// Events
addEventListener(event: string, callback: Function): void
removeEventListener(event: string, callback: Function): void
// Control
play(): void
pause(): void
setZoom(level: number): void
// Variables
setVariable(name: string, value: any): void
getVariable(name: string): any
}
interface SplineObject {
// Transforms
position: { x: number; y: number; z: number }
rotation: { x: number; y: number; z: number }
scale: { x: number; y: number; z: number }
// Visibility
visible: boolean
// Events
emitEvent(eventType: string): void
addEventListener(event: string, callback: Function): void
// Children
children: SplineObject[]
parent: SplineObject | null
}Use cases
Hero sections with 3D
// components/Hero3D.tsx
export function Hero3D() {
return (
<section className="relative h-screen overflow-hidden">
{/* 3D Background */}
<div className="absolute inset-0">
<Spline
scene="https://prod.spline.design/abstract-shapes/scene.splinecode"
style={{ width: '100%', height: '100%' }}
/>
</div>
{/* Gradient overlay */}
<div className="absolute inset-0 bg-gradient-to-t from-black/80 to-transparent" />
{/* Content */}
<div className="relative z-10 flex items-center justify-center h-full">
<div className="text-center text-white max-w-3xl px-4">
<h1 className="text-5xl md:text-7xl font-bold mb-6">
3D Made Easy
</h1>
<p className="text-xl mb-8 text-white/80">
Create stunning interactive 3D experiences without code
</p>
<button className="bg-white text-black px-8 py-4 rounded-full font-semibold hover:scale-105 transition">
Get Started Free
</button>
</div>
</div>
</section>
)
}Product showcase
// components/ProductShowcase.tsx
import Spline from '@splinetool/react-spline'
import { useState } from 'react'
const colors = [
{ name: 'Black', value: '#000000' },
{ name: 'Silver', value: '#C0C0C0' },
{ name: 'Gold', value: '#FFD700' },
]
export function ProductShowcase() {
const [selectedColor, setSelectedColor] = useState(colors[0])
const [spline, setSpline] = useState<Application | null>(null)
function onLoad(app: Application) {
setSpline(app)
}
function changeColor(color: typeof colors[0]) {
setSelectedColor(color)
if (spline) {
spline.setVariable('productColor', color.value)
}
}
return (
<section className="py-20 bg-gray-50">
<div className="container mx-auto px-4">
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
{/* 3D Model */}
<div className="h-[500px] bg-white rounded-2xl shadow-lg overflow-hidden">
<Spline
scene="https://prod.spline.design/product/scene.splinecode"
onLoad={onLoad}
/>
</div>
{/* Product Info */}
<div>
<span className="text-primary font-semibold">New Arrival</span>
<h2 className="text-4xl font-bold mt-2 mb-4">
Premium Headphones
</h2>
<p className="text-gray-600 mb-8">
Experience crystal-clear audio with our flagship headphones.
Drag to rotate the 3D model.
</p>
{/* Color Selector */}
<div className="mb-8">
<span className="text-sm font-medium text-gray-500">
Color: {selectedColor.name}
</span>
<div className="flex gap-3 mt-2">
{colors.map((color) => (
<button
key={color.name}
onClick={() => changeColor(color)}
className={`w-10 h-10 rounded-full border-2 transition ${
selectedColor.name === color.name
? 'border-primary scale-110'
: 'border-transparent'
}`}
style={{ backgroundColor: color.value }}
/>
))}
</div>
</div>
<div className="flex items-center gap-4">
<span className="text-3xl font-bold">$349</span>
<button className="bg-primary text-white px-8 py-3 rounded-lg hover:bg-primary/90 transition">
Add to Cart
</button>
</div>
</div>
</div>
</div>
</section>
)
}Interactive logo
// components/InteractiveLogo.tsx
export function InteractiveLogo() {
return (
<div className="w-48 h-48 cursor-pointer">
<Spline
scene="https://prod.spline.design/logo/scene.splinecode"
/>
</div>
)
}Data visualization
// components/DataViz3D.tsx
import { useEffect, useRef } from 'react'
interface DataPoint {
label: string
value: number
}
export function DataViz3D({ data }: { data: DataPoint[] }) {
const splineRef = useRef<Application | null>(null)
useEffect(() => {
if (!splineRef.current) return
data.forEach((point, index) => {
const bar = splineRef.current?.findObjectByName(`bar_${index}`)
if (bar) {
bar.scale.y = point.value / 100
}
})
}, [data])
return (
<div className="h-[400px] bg-gray-900 rounded-xl">
<Spline
scene="https://prod.spline.design/chart/scene.splinecode"
onLoad={(app) => { splineRef.current = app }}
/>
</div>
)
}Performance optimization
Best practices
// Optimizing Spline scenes:
// 1. Geometry
- Use low-poly where possible
- Limit vertices: < 100k for mobile
- Merge static objects
- Use instances for repeated objects
// 2. Materials
- Limit unique materials
- Avoid heavy shaders on mobile
- Compress textures (max 2048px)
- Use matcaps instead of PBR where possible
// 3. Lighting
- Max 3-4 lights per scene
- Baked lighting for static scenes
- Disable shadows on mobile
// 4. Animations
- Limit physics objects
- Use CSS transforms where possible
- Pause animations outside the viewport
// 5. Loading
- Lazy load Spline components
- Show loading placeholder
- Preload critical scenesLazy loading in React
// components/LazySpline.tsx
import { useInView } from 'react-intersection-observer'
import dynamic from 'next/dynamic'
const Spline = dynamic(() => import('@splinetool/react-spline'), {
ssr: false,
})
export function LazySpline({ scene }: { scene: string }) {
const { ref, inView } = useInView({
triggerOnce: true,
rootMargin: '200px',
})
return (
<div ref={ref} className="h-[500px]">
{inView ? (
<Spline scene={scene} />
) : (
<div className="h-full bg-gray-100 animate-pulse rounded-xl" />
)}
</div>
)
}Pricing
| Plan | Price | Includes |
|---|---|---|
| Free | $0 | Unlimited projects, Spline watermark, Public scenes |
| Pro | $9/mo | No watermark, Private scenes, Priority export |
| Team | $29/user/mo | Collaboration, Shared libraries, Admin controls |
| Enterprise | Custom | SSO, Dedicated support, Custom features |
FAQ - frequently asked questions
Is Spline free?
Yes, the free plan allows unlimited projects and export. The only limitations are the watermark and scenes being public.
Do I need 3D skills?
No, Spline is designed for people with no 3D experience. The interface is intuitive, similar to 2D tools like Figma.
How well does it work on mobile?
Spline scenes work on mobile, but they require optimization. A low polygon count and simplified materials are recommended.
Can I export to 3D files?
Yes, Spline allows export to GLTF/GLB, which can be used in other 3D applications or Three.js.
How do I collaborate with a team?
The Team plan enables real-time collaboration, similar to Figma. Multiple users can edit the same scene simultaneously.
Does Spline use WebGL?
Yes, Spline uses WebGL for rendering. It works in all modern browsers.
Summary
Spline revolutionizes 3D design for the web:
- Browser-based - Create 3D without installation
- No-code friendly - Intuitive interface
- Interactivity - Hover, click, scroll events
- Web-native - React, iframe, vanilla JS export
- Real-time collaboration - Teamwork
- Physics engine - Gravity and collision simulations
Spline is the ideal tool for web developers and designers who want to add interactive 3D elements to their projects without learning complex software.