Spline, czyli scena 3D bez pisania kodu graficznego
Umieszczenie trójwymiarowej sceny na stronie wymagało dotąd znajomości bibliotek graficznych, pojęć z grafiki komputerowej i sporo cierpliwości. Spline zamienia to w pracę w edytorze działającym w przeglądarce, przypominającą narzędzia do projektowania interfejsów.
Budujesz scenę wizualnie, dodajesz materiały, światła i interakcje, a potem eksportujesz ją do osadzenia na stronie. Wynik działa w przeglądarce, reaguje na kursor i przewijanie, i nie wymaga od Ciebie napisania ani jednej linii kodu graficznego.
To narzędzie ma jednak koszt, którego materiały o nim mówią mniej wyraźnie, niż powinny, i jest to koszt wydajnościowy. Poświęcam mu osobną sekcję, bo od niego zależy, czy warto po nie sięgać.
Jak wygląda praca
Edytor przypomina narzędzia do projektowania interfejsów, z osią czasu i panelem właściwości, więc osoba znająca Figmę odnajduje się w nim szybciej, niż w klasycznym programie do grafiki trójwymiarowej.
Scenę składasz z brył podstawowych, kształtów rysowanych na płaszczyźnie i wyciąganych w przestrzeń oraz modeli wczytanych z zewnątrz. Materiały ustawia się suwakami, a oświetlenie przez dodanie źródeł i ustawienie ich siły.
Interakcje są tu najciekawszą częścią i zarazem powodem, dla którego ludzie po to sięgają. Zdarzenie takie jak najechanie kursorem, kliknięcie albo przewinięcie strony uruchamia przejście do innego stanu sceny, opisanego wizualnie. Bez tego mechanizmu trójwymiarowa scena jest ozdobą, a z nim staje się elementem interfejsu.
Warto od początku pilnować liczby obiektów i rozmiaru tekstur. Scena, która w edytorze działa płynnie na mocnym komputerze, potrafi zatrzymać przewijanie na telefonie sprzed trzech lat, a różnicy nie widać, dopóki sam tego nie sprawdzisz na takim urządzeniu.
Osadzenie na stronie
Najprostsza droga to gotowy komponent wczytujący scenę z adresu. Instalujesz dwie paczki, bo silnik uruchomieniowy jest zależnością równorzędną i nie wciąga się sam w każdym menedżerze pakietów.
npm install @splinetool/react-spline @splinetool/runtimeimport Spline from '@splinetool/react-spline'
export function Sekcja() {
return <Spline scene="https://prod.spline.design/xxx/scene.splinecode" />
}To działa i ma dwie konsekwencje, które warto znać. Pierwsza: scena pobierana jest z serwerów producenta, więc czas ładowania zależy od jego infrastruktury, a znikniecie usługi oznacza puste miejsce na Twojej stronie. Drugą jest brak kontroli nad momentem wczytania, o ile sam go nie dołożysz.
Bardziej świadomy układ polega na wczytywaniu sceny dopiero wtedy, gdy jest potrzebna, i pokazaniu czegoś w międzyczasie.
import dynamic from 'next/dynamic'
const Spline = dynamic(() => import('@splinetool/react-spline'), {
ssr: false,
loading: () => <div className="h-[500px] bg-slate-100" />,
})Wbrew rozpowszechnionemu przekonaniu wyłączenie renderowania po stronie serwera nie jest tu warunkiem uniknięcia awarii. Komponent jest oznaczony jako kliencki, a po obiekty przeglądarki sięga dopiero w efekcie uruchamianym po zamontowaniu, więc w Next.js nie psuje budowania. Dynamiczny import z wyłączonym renderowaniem serwerowym służy tu czemu innemu: odsunięciu pobrania paczki i pokazaniu własnego wypełniacza w tym czasie. Biblioteka ma zresztą osobne wejście @splinetool/react-spline/next, które renderuje po stronie serwera rozmyty podgląd wyliczony z samej sceny, więc miejsce nie jest puste w trakcie ładowania.
Dla osób pracujących bezpośrednio z bibliotekami graficznymi dostępny jest wariant wczytujący scenę do własnego drzewa obiektów, co pozwala mieszać elementy zaprojektowane w edytorze z kodem pisanym ręcznie.
Koszt wydajnościowy
To jest sekcja najważniejsza w tym tekście i rzecz, którą warto rozstrzygnąć przed podjęciem decyzji.
Pierwsza pozycja to rozmiar. Scena z kilkoma obiektami, teksturami i modelem wczytanym z zewnątrz waży zwykle kilka megabajtów, czyli tyle, co cała reszta typowej strony razem wzięta. Przy połączeniu mobilnym to są sekundy oczekiwania, zanim cokolwiek się pojawi.
Druga to obciążenie karty graficznej. Scena renderuje się w pętli przez cały czas, gdy jest widoczna, więc zużywa procesor graficzny nieprzerwanie. Na telefonie przekłada się to wprost na zużycie baterii i na płynność przewijania reszty strony.
Rozwiązaniem jest zatrzymanie renderowania, gdy scena wyjedzie poza ekran.
const kontener = useRef<HTMLDivElement>(null)
const [widoczna, ustawWidoczna] = useState(false)
useEffect(() => {
const obserwator = new IntersectionObserver(
([wpis]) => ustawWidoczna(wpis.isIntersecting),
{ rootMargin: '200px' }
)
if (kontener.current) obserwator.observe(kontener.current)
return () => obserwator.disconnect()
}, [])
<div ref={kontener} className="h-[500px]">
{widoczna && <Spline scene={ADRES} />}
</div>Zapas dwustu pikseli w ustawieniach obserwatora sprawia, że scena zaczyna się wczytywać tuż przed wjechaniem w kadr, więc użytkownik nie widzi pustego miejsca, a poza kadrem nic się nie renderuje.
Trzecia to miary jakości strony. Duży zasób ładowany na początku pogarsza czas do wyświetlenia głównej treści, a element pojawiający się po wczytaniu przesuwa układ, jeśli nie zarezerwowałeś na niego miejsca.
Cztery rzeczy ograniczają ten koszt i warto zastosować wszystkie. Zarezerwuj wymiary elementu z góry, żeby układ się nie przesuwał. Wczytuj scenę dopiero, gdy zbliża się do widoku, zamiast przy wejściu na stronę. Zatrzymuj renderowanie, gdy scena wyjdzie poza widok albo gdy karta przestanie być aktywna. I przygotuj wariant zastępczy: statyczny obraz dla urządzeń słabszych albo dla osób, które w ustawieniach systemu ograniczyły animacje.
To ostatnie warto potraktować poważnie. Scena reagująca na ruch kursora u części osób wywołuje realny dyskomfort, a sprawdzenie odpowiedniego ustawienia to trzy linie kodu.
Warto też zmierzyć skutek, zamiast go szacować. Otwórz stronę w narzędziach deweloperskich z ograniczoną przepustowością sieci i spowolnionym procesorem, ustawionymi tak, żeby odpowiadały średniemu telefonowi. Liczba, którą zobaczysz, mówi więcej niż jakiekolwiek zalecenie ogólne, bo dotyczy Twojej sceny na Twojej stronie, a nie przykładu z dokumentacji. Ten test zajmuje pięć minut i regularnie kończy dyskusję o tym, czy scena zostaje na ekranie powitalnym.
Kiedy to ma sens
Warto rozdzielić zastosowania, w których narzędzie wygrywa, od tych, w których jest kosztowną ozdobą.
Wygrywa na stronie głównej produktu, gdzie użytkownik przychodzi raz, na krótko, a pierwsze wrażenie faktycznie decyduje. Trójwymiarowy model produktu obracany kursorem mówi więcej niż trzy zdjęcia i jest tym, co ludzie zapamiętują.
Wygrywa przy prezentacji rzeczy fizycznych. Mebel, urządzenie, opakowanie, element ubioru: obejrzenie ze wszystkich stron zastępuje galerię i zmniejsza liczbę pytań przed zakupem.
Wygrywa też przy stronach wydarzeń, portfolio i kampaniach, gdzie efekt jest częścią przekazu, a czas życia strony liczy się w tygodniach.
Przegrywa wszędzie tam, gdzie liczy się szybkie dostarczenie informacji. Dokumentacja, panel administracyjny, sklep z setką produktów, aplikacja używana codziennie przez tych samych ludzi. W tych miejscach kilkusekundowe ładowanie i stałe obciążenie karty graficznej są kosztem bez żadnego zwrotu.
Przegrywa również przy treści, która ma się indeksować. Scena trójwymiarowa nie niesie tekstu, więc dla wyszukiwarki jest pustym prostokątem, i to warto uwzględnić, planując, co znajdzie się na ekranie powitalnym.
Jest jeszcze jeden przypadek, w którym warto się wstrzymać: strona, na której użytkownik ma coś wypełnić albo kupić. Efekt przyciągający uwagę konkuruje wtedy z formularzem o tę samą uwagę, a przy zakupie każde rozproszenie działa przeciw Tobie. Trójwymiarowy model produktu obok formularza zamówienia bywa sensowny, ale trójwymiarowa animacja tła nad nim raczej nie.
Jak zmniejszyć scenę
Skoro rozmiar jest głównym kosztem, warto wiedzieć, co go napędza, bo intuicja myli się tu regularnie.
Największą pozycją są zwykle tekstury, a nie liczba obiektów. Obraz o rozdzielczości dwóch tysięcy pikselów użyty jako materiał na małym elemencie waży tyle samo co ten sam obraz na całym ekranie, a widać go w ułamku tej wielkości. Zmniejszenie tekstur do rozmiaru, w jakim faktycznie się pojawiają, zbija paczkę najszybciej.
Druga to modele wczytane z zewnątrz. Model pobrany z biblioteki bywa przygotowany pod renderowanie filmowe i ma dziesiątki tysięcy wielokątów, z których na ekranie widać kilka procent. Uproszczenie siatki przed wczytaniem to praca na kwadrans i zwykle kilkukrotna redukcja rozmiaru.
Trzecia to obiekty niewidoczne w kadrze. Scena budowana wizualnie gromadzi elementy, które w finalnym ujęciu są zasłonięte albo poza kadrem, a mimo to trafiają do eksportu.
Czwarta, najmniej oczywista, to liczba materiałów. Każdy odrębny materiał to osobne przetwarzanie przy renderowaniu, więc dziesięć obiektów dzielących jeden materiał kosztuje mniej niż dziesięć obiektów z dziesięcioma różnymi.
Sprawdź rozmiar wyeksportowanej sceny przed osadzeniem jej na stronie.
curl -sI https://prod.spline.design/xxx/scene.splinecode |
awk '/[Cc]ontent-[Ll]ength/ { printf "%.1f MB\n", $2/1048576 }'To jedna liczba, którą warto znać przed decyzją, bo powyżej kilku megabajtów rozmowa przestaje dotyczyć estetyki, a zaczyna dotyczyć tego, czy ktokolwiek zobaczy stronę przed zamknięciem karty.
Praca z zespołem i przekazanie do wdrożenia
Narzędzie stoi na styku projektowania i programowania, więc warto ustalić, kto za co odpowiada, zanim scena trafi na stronę.
Osoba projektująca pracuje w edytorze i publikuje scenę pod adresem, który się nie zmienia. Osoba wdrażająca osadza ten adres raz i nie wraca do tego przy każdej poprawce, bo zmiany w edytorze pojawiają się na stronie po ponownym opublikowaniu.
To wygodne i niesie jedno ryzyko warte nazwania. Zmiana opublikowana bez uzgodnienia trafia od razu na produkcję, bez przeglądu i bez możliwości cofnięcia przez osobę odpowiedzialną za stronę. Przy poważnym wdrożeniu warto rozważyć serwowanie sceny z własnej infrastruktury, co odbiera wygodę natychmiastowej publikacji i daje w zamian kontrolę nad tym, co widzą użytkownicy. Warto tylko wiedzieć, gdzie producent to umieścił: eksport kodu i eksport do samodzielnego hostowania są wymienione dopiero na planie firmowym z wyceną indywidualną, więc na planach z cennika nie masz do tego drogi wprost.
Drugą rzeczą do ustalenia jest, kto sprawdza wydajność. Osoba projektująca widzi scenę w edytorze na mocnym sprzęcie i nie ma powodu podejrzewać problemu, a osoba wdrażająca dostaje gotowy adres i przyjmuje, że wszystko jest w porządku. Test na słabszym telefonie należy do kogoś i warto, żeby ten ktoś był wskazany, a nie domyślny.
Plany i co je dzieli
Cennik producenta rozkłada możliwości na cztery poziomy plus wycenę indywidualną, a stawka zależy od tego, czy płacisz z góry za rok, czy co miesiąc.
| Plan | Rocznie, za miejsce | Miesięcznie, za miejsce | Co dochodzi |
|---|---|---|---|
| Free | 0 USD | 0 USD | ograniczona liczba plików, eksport na stronę ze znakiem wodnym |
| Hobby | 12 USD | 15 USD | znak wodny znika z eksportów na stronę, pliki bez limitu, biblioteka materiałów |
| Pro | 20 USD | 25 USD | eksport na Apple i Androida, znak wodny znika także z osadzeń, projekty i foldery bez limitu |
| Max | 120 USD | 150 USD | 10 000 kredytów miesięcznie, najwyższe limity funkcji AI, wsparcie priorytetowe |
| Enterprise | wycena indywidualna | wycena indywidualna | eksport kodu i samodzielne hostowanie, logowanie SSO, historia wersji pliku |
Dwie rzeczy w tej tabeli łatwo przeoczyć. Pierwsza to znak wodny rozbity na dwie osobne pozycje: eksport sceny na stronę czyści już Hobby, natomiast osadzenie sceny bez znaku wymaga Pro. Druga to eksport na platformy mobilne, przypisywany zwykle „planom płatnym" w ogóle, a dostępny dopiero od Pro.
Osobną pozycją są kredyty na funkcje sztucznej inteligencji: 2 000 miesięcznie na Hobby, 3 000 na Pro, 10 000 na Max. Pulę podnosi się dokupując kolejne tysiące po 5 USD miesięcznie za tysiąc, i jest to stała pozycja doliczana do abonamentu, a nie jednorazowe doładowanie. Kredyty zużywa wyłącznie generowanie modeli, tekstur i stylów, więc przy scenie składanej ręcznie ta kolumna Cię nie dotyczy.
Spline kontra alternatywy
| Rozwiązanie | Mocna strona | Słabość | Kiedy wybrać |
|---|---|---|---|
| Spline | Praca wizualna, interakcje bez kodu, eksport do Reacta | Duży rozmiar, obciążenie karty graficznej | Strona produktu, portfolio, prezentacja |
| Biblioteki graficzne wprost | Pełna kontrola, optymalizacja rozmiaru | Wymaga wiedzy z grafiki trójwymiarowej | Rozbudowana scena albo gra |
| Wideo z animacją | Przewidywalny rozmiar, działa wszędzie | Brak interaktywności | Efekt bez reakcji na użytkownika |
| Motion | Lekkie, animuje istniejące elementy | Dwa wymiary, nie trójwymiarowa scena | Animacja interfejsu, nie model |
Drugi wiersz warto rozważyć przy scenie, która ma żyć długo. Kod pisany wprost daje kontrolę nad tym, co trafia do paczki, i pozwala zejść z rozmiarem znacznie niżej, kosztem czasu i wiedzy.
Trzeci wiersz bywa pomijany, a rozwiązuje zaskakująco wiele przypadków. Jeśli scena nie reaguje na użytkownika, tylko odtwarza animację, nagranie tej animacji waży mniej, działa na każdym urządzeniu i nie obciąża karty graficznej przez cały czas widoczności.
Typowe błędy
Pierwszy to osadzenie sceny bez zarezerwowania miejsca. Element pojawiający się po wczytaniu przesuwa układ, co pogarsza miary jakości strony i irytuje użytkownika.
Drugi to wczytywanie sceny przy wejściu na stronę zamiast wtedy, gdy zbliża się do widoku. Kilka megabajtów pobieranych od razu opóźnia wszystko inne.
Trzeci to przekonanie, że bez wyłączenia renderowania serwerowego aplikacja się wywali, i budowanie na tym całej konfiguracji. Komponent jest kliencki i po obiekty przeglądarki sięga dopiero po zamontowaniu. Prawdziwym niedopatrzeniem jest co innego: pominięcie wejścia @splinetool/react-spline/next, które daje rozmyty podgląd renderowany po stronie serwera, i niewstawienie w to miejsce własnego wypełniacza.
Czwarty to testowanie wyłącznie na komputerze deweloperskim. Scena płynna na mocnej maszynie potrafi zatrzymać przewijanie na starszym telefonie.
Piąty to pominięcie ustawienia ograniczającego ruch. U części osób animacje wywołują realny dyskomfort, a sprawdzenie tego to trzy linie kodu.
Szósty to umieszczenie sceny tam, gdzie użytkownik przychodzi po informację. Dokumentacja i panel administracyjny tracą na tym jednoznacznie, a koszt ładowania nie zwraca się w żaden sposób.
Siódmy to pozostawienie w scenie obiektów niewidocznych w finalnym kadrze. Trafiają do eksportu razem z resztą i podnoszą rozmiar, mimo że nikt ich nigdy nie zobaczy.
FAQ
Czy Spline jest darmowy?
Plan bezpłatny pozwala tworzyć sceny i eksportować je na stronę, przy czym eksport zawiera znak wodny producenta, a liczba plików jest ograniczona. Znak wodny z eksportów na stronę zdejmuje dopiero Hobby, czyli 12 USD miesięcznie za miejsce przy płatności rocznej albo 15 USD przy miesięcznej. Osadzenie sceny bez znaku oraz eksport na Apple i Androida wchodzą jeszcze wyżej, na Pro za 20 USD rocznie albo 25 USD miesięcznie.
Ile waży taka scena?
Zwykle kilka megabajtów, czyli tyle, co cała reszta typowej strony. To najważniejsza liczba przy tej decyzji, bo przy połączeniu mobilnym przekłada się wprost na sekundy oczekiwania, zanim cokolwiek się pojawi.
Czy działa na telefonach?
Działa, natomiast obciąża kartę graficzną przez cały czas widoczności, co przekłada się na zużycie baterii i płynność przewijania. Przy urządzeniach starszych warto przygotować wariant zastępczy w postaci statycznego obrazu.
Czy scena jest widoczna dla wyszukiwarek?
Nie w sensie treści. Scena nie niesie tekstu, więc dla wyszukiwarki jest pustym obszarem. Jeśli ekran powitalny ma się indeksować, tekst musi znaleźć się obok sceny, a nie w niej.
Kiedy lepiej użyć czegoś innego?
Gdy scena nie reaguje na użytkownika, bo wtedy nagranie tej samej animacji waży mniej i działa wszędzie. Oraz gdy strona służy szybkiemu dostarczeniu informacji, bo tam koszt ładowania i obciążenia nie zwraca się w żaden sposób.
Narzędzie i dokumentacja stoją na stronie projektu, a pakiet do Reacta znajdziesz w rejestrze npm.