Blog
Frontend22 min czytania

Magic UI — animowane komponenty dla Reacta i Tailwinda

Rejestr 75 animowanych komponentów Reacta na licencji MIT, instalowanych narzędziem shadcn wprost do repozytorium — 36 z nich nie ciągnie żadnej zależności npm. Pokazujemy pełne wdrożenie w Laravelu z Inertią zamiast w Next.js: components.json, alias do własnej funkcji cn, dyrektywy „use client” w Rollupie i renderowanie po stronie serwera. Plus rachunek za dostępność: tylko cztery komponenty z siedemdziesięciu ośmiu respektują prefers-reduced-motion.

Landing page ma wyglądać drogo. Nagłówek, który składa się litera po literze, logotypy klientów przewijające się w pętli, delikatna smuga światła obiegająca ramkę karty z cenami, licznik wbijający się w okrągłą liczbę, kiedy sekcja wjeżdża w kadr. Klient tego nie nazwie, ale zobaczy różnicę między stroną, która wygląda jak produkt, a stroną, która wygląda jak dokumentacja.

Problem w tym, że zespół backendowy nie ma animatora, a każdy z tych efektów to pół dnia dłubania w requestAnimationFrame, masce CSS albo w API IntersectionObservera — plus drugie pół dnia na to, żeby nie zamulało telefonu i nie wywracało hydracji przy renderowaniu po stronie serwera.

Magic UI (github.com/magicuidesign/magicui, licencja MIT) jest zbiorem takich efektów, gotowych do wklejenia. Nie jest biblioteką w rozumieniu paczki npm i to jest w nim najciekawsze: kod komponentu ląduje w twoim repozytorium jako zwykły plik, który możesz przeczytać, zmienić i skasować. Poniżej to, co realnie dostajesz, gdzie są koszty, i jak to wpiąć w projekt Laravela z Inertią zamiast w Next.js, na który projekt jest domyślnie nastawiony.

Czym to jest, a czym nie jest

Magic UI opisuje się jako „UI Library for Design Engineers”. Praktyczniej: to warstwa marketingowa nad shadcn/ui. shadcn/ui daje komponenty, z których buduje się aplikację — przyciski, formularze, dialogi, tabele. Magic UI daje to, czym się tę aplikację sprzedaje — nagłówki, tła, mockupy urządzeń, efekty przewijania.

Podział jest czysty i to nie przypadek: oba projekty używają tej samej konfiguracji Tailwinda, tych samych zmiennych CSS i tego samego narzędzia wiersza poleceń. Magic UI świadomie nie dubluje niczego z shadcn/ui.

Stan repozytorium na dziś, prosto z API GitHuba i z pliku registry.json:

  • 22 147 gwiazdek, 1 116 forków, 152 kontrybutorów, repozytorium założone 26 czerwca 2023,
  • ostatni commit 11 sierpnia 2026 — poprawka do animated-theme-toggler, chroniąca przed zawieszeniem kompozytora przeglądarki przy szybkim klikaniu,
  • dwa otwarte zgłoszenia, oba to pull requesty z nowymi komponentami (tło z falami wody na WebGL i cząsteczki 3D na canvasie). Zero otwartych błędów,
  • 75 komponentów typu registry:ui w rejestrze plus 133 gotowe przykłady użycia,
  • razem 12 096 linii TSX w katalogu registry/magicui — całość, wszystkie warianty, komplet.
Ta ostatnia liczba jest ważniejsza, niż wygląda. Cała biblioteka mieści się w dwunastu tysiącach linii, a ty i tak kopiujesz do siebie tylko te pliki, których używasz. Marquee to 74 linie. Border beam — 107. To jest kod, który da się przeczytać w przerwie na kawę i poprawić, kiedy przestanie pasować, zamiast zgłaszać błąd i czekać na wydanie.

Skąd rozbieżność w liczbie komponentów

W opisach Magic UI regularnie pojawia się „150+ komponentów”. W rejestrze jest ich 75, w katalogu źródłowym 78 plików .tsx (kilka najnowszych nie trafiło jeszcze do rejestru). Reszta to przykłady — 133 wpisy typu registry:example, czyli warianty w rodzaju „marquee poziomy”, „marquee pionowy”, „marquee 3D”, „marquee z logotypami”. Każdy z nich da się zainstalować osobno i każdy jest osobnym punktem na stronie z dokumentacją, ale komponentów jako takich jest 75.

Nie jest to naciąganie na tyle poważne, żeby projekt przez to skreślać — po prostu przy planowaniu warto liczyć 75, nie 150.

Instalacja: rejestr shadcn zamiast paczki npm

Magic UI nie ma pakietu w npm. Instalacja komponentu to pobranie jego pliku JSON z rejestru i zapisanie kodu w twoim projekcie. Robi to narzędzie shadcn (wersja 4.20.1 z 2 września 2026):

npx shadcn@latest add @magicui/marquee

Prefiks @magicui to przestrzeń nazw rejestru. Narzędzie rozwija ją do adresu https://magicui.design/r/{name}.json, pobiera plik, zapisuje komponent w katalogu skonfigurowanym jako ui, dokłada brakujące zależności npm i dopisuje potrzebne zmienne CSS.

Przestrzeni @magicui nie musisz nigdzie deklarować. Jest w centralnym indeksie rejestrów open source, który shadcn utrzymuje pod adresem ui.shadcn.com/r/registries.json — na dziś 292 pozycje, a Magic UI ma tam ocenę zdrowia 97,3 na 100 (dostępność, poprawność schematów, instalowalność). Jeśli jednak wolisz przypiąć adres na sztywno albo trzymasz własny rejestr firmowy, blok wygląda tak:

{
  "registries": {
    "@magicui": "https://magicui.design/r/{name}.json",
    "@firmowy": {
      "url": "https://design.firma.pl/r/{name}.json",
      "headers": { "Authorization": "Bearer ${REGISTRY_TOKEN}" }
    }
  }
}

Tryb ręczny też jest przewidziany: dokumentacja każdego komponentu ma zakładkę „Manual” z pełnym źródłem do skopiowania i listą animacji CSS do dopisania. Przy audycie bezpieczeństwa, który zabrania narzędziom CLI pisać po repozytorium, to jest realna ścieżka, a nie kurtuazja.

Co jest w katalogu

Siedemdziesiąt pięć komponentów układa się w kilka rodzin. Warto je znać z nazwy, bo szukanie po funkcji na stronie z dokumentacją jest wolniejsze niż wpisanie nazwy w wiersz poleceń.

Tekst

text-animate (najbardziej rozbudowany — cztery tryby podziału: całość, słowa, znaki, linie, i dziesięć wariantów wejścia), typing-animation, hyper-text, morphing-text, word-rotate, flip-text, box-reveal, text-reveal, sparkles-text, aurora-text, line-shadow-text, animated-gradient-text, animated-shiny-text, spinning-text, comic-text, video-text (tekst jako maska na odtwarzanym wideo), highlighter (podkreślenia rysowane odręcznie, na bibliotece rough-notation).

Tła i wzory

particles, meteors, retro-grid, grid-pattern, dot-pattern, flickering-grid, animated-grid-pattern, interactive-grid-pattern, striped-pattern, ripple, warp-background, grid-beams, progressive-blur.

Przyciski i mikrointerakcje

shimmer-button, rainbow-button, pulsating-button, ripple-button, interactive-hover-button, animated-subscribe-button, script-copy-btn, confetti, cool-mode, smooth-cursor, pointer, lens (lupa nad obrazem), scratch-to-reveal.

Układ i struktura

bento-grid, marquee, dock (pasek w stylu macOS), file-tree, terminal (udawana konsola z animowanym wypisywaniem), code-comparison (dwa fragmenty kodu obok siebie, podświetlane przez Shiki), arc-timeline, animated-list, orbiting-circles, animated-beam (linia łącząca dwa elementy DOM, z pulsującym gradientem — kanoniczny „diagram integracji” z każdej strony SaaS-a).

Mockupy urządzeń i efekty specjalne

safari, iphone-15-pro, android, hero-video-dialog, globe (obracająca się kula ziemska na bibliotece cobe, z markerami miast), icon-cloud, glyph-matrix, pixel-image, magic-card, neon-gradient-card, shine-border, border-beam, number-ticker, animated-circular-progress-bar, scroll-progress, scroll-based-velocity, blur-fade, avatar-circles, tweet-card i client-tweet-card, animated-theme-toggler.

Ile to naprawdę kosztuje w zależnościach

Tu Magic UI wypada lepiej, niż sugeruje kategoria „biblioteka animacji”. Rozkład zależności npm w 75 komponentach:

  • 36 komponentów nie potrzebuje niczego — czysty React, Tailwind i, gdzie trzeba, canvas. W tej grupie są marquee, particles, meteors, retro-grid, terminal, safari, iphone-15-pro, shimmer-button, rainbow-button, aurora-text, orbiting-circles, icon-cloud, wszystkie wzory siatek i większość przycisków,
  • 31 wymaga motion — czyli biblioteki dawniej znanej jako Framer Motion,
  • reszta to pojedyncze przypadki: cobe (globe), canvas-confetti (confetti), rough-notation (highlighter), react-tweet (dwie karty tweetów), shiki plus next-themes (code-comparison i script-copy-btn), @radix-ui/react-icons (bento-grid), lucide-react (przełącznik motywu).

Praktycznie znaczy to tyle, że możesz wziąć z Magic UI pięć efektów i nie zwiększyć rozmiaru paczki JS ani o bajt, o ile trafisz w tę pierwszą grupę. To nie jest typowe dla bibliotek animacji.

Warto też wiedzieć, że w rejestrze siedzi jedna niekonsekwencja: smooth-cursor deklaruje framer-motion, kiedy 31 pozostałych deklaruje motion. Jeśli instalujesz tylko ten jeden komponent, dostaniesz do package.json paczkę pod inną nazwą niż reszta.

motion czy framer-motion — i dlaczego to nie jest to samo pytanie, co rok temu

W npm żyją dziś obie nazwy i obie są w wersji 13.2.0, wydanej tego samego dnia (2 września 2026). Zależności rozstrzygają, co jest czym:

  • motion@13.2.0 zależy od framer-motion@^13.2.0,
  • framer-motion@13.2.0 zależy od motion-dom i motion-utils.

Czyli motion to cienka nakładka nad framer-motion, nie osobny silnik. Instalacja obu nie dubluje runtime’u — pod spodem i tak jest jedna kopia motion-dom.

Ale majory muszą się zgadzać. Jeśli projekt ma dziś framer-motion@^12, a ty pozwolisz narzędziu dociągnąć motion@latest, w drzewie wylądują dwie linie 12 i 13 obok siebie: podwójny kod, dwa niezależne zestawy kontekstów Reacta i animacje, które potrafią przestać ze sobą rozmawiać. Dwa wyjścia:

npm install motion@^12          # przypnij major do tego, co masz
# albo, jeśli nie chcesz drugiej nazwy w package.json:
# podmień w pobranych komponentach import "motion/react" na "framer-motion"

Druga opcja jest w pełni bezpieczna, bo API w obu nazwach jest identyczne — motion/react reeksportuje to samo. Przy pięciu komponentach to pięć linii do zmiany, a package.json zostaje czysty.

Tailwind v4 jest wymagany

Aktualne Magic UI zakłada Tailwinda w wersji 4. Widać to w samych komponentach — marquee używa składni gap-(--gap) i [--duration:40s], border-beam sięga po mask-intersect i border-(length:--border-beam-width). To są utility klasy z v4, w v3 nie istnieją.

Projekt utrzymuje osobną stronę v3.magicui.design ze starszymi wersjami komponentów dla Tailwinda 3. Nie jest to jednak ścieżka rozwoju — nowe komponenty idą tylko do wersji bieżącej, a oficjalna rada to migracja według przewodnika shadcn/ui.

Druga konsekwencja v4: konfiguracja przeniosła się z tailwind.config.js do CSS. Komponenty, które potrzebują własnych klatek kluczowych, dokładają je do arkusza globalnego. Dla marquee wygląda to tak:

@theme inline {
  --animate-marquee: marquee var(--duration) infinite linear;
  --animate-marquee-vertical: marquee-vertical var(--duration) linear infinite;

  @keyframes marquee {
    from { transform: translateX(0); }
    to   { transform: translateX(calc(-100% - var(--gap))); }
  }
  @keyframes marquee-vertical {
    from { transform: translateY(0); }
    to   { transform: translateY(calc(-100% - var(--gap))); }
  }
}

Przy instalacji przez CLI narzędzie dopisuje to samo. Przy trybie ręcznym łatwo o tym zapomnieć — objaw jest wtedy jednoznaczny: treść się renderuje, ale stoi w miejscu.

Wpięcie w Laravela z Inertią

Dokumentacja Magic UI pokazuje wyłącznie Next.js, ale narzędzie shadcn oficjalnie wspiera Laravela z Reactem i Inertią, a komponenty Magic UI nie importują niczego z next/ — sprawdziliśmy cały katalog rejestru, zero takich importów. Jedyne dwa komponenty z zależnością next-themes to code-comparison i script-copy-btn, i tam chodzi o odczyt trybu ciemnego, nie o router.

Nasz stack na tym blogu to Laravel z Inertią 3, React 19, Tailwind 4 i Vite — czyli dokładnie ten przypadek. Poniżej pełna ścieżka.

Krok 1: components.json

Narzędzie shadcn potrzebuje pliku konfiguracyjnego w katalogu głównym projektu. Dla Laravela z Vite i Tailwindem 4:

{
  "$schema": "https://ui.shadcn.com/schema.json",
  "style": "new-york",
  "rsc": false,
  "tsx": true,
  "tailwind": {
    "config": "",
    "css": "resources/css/app.css",
    "baseColor": "neutral",
    "cssVariables": true,
    "prefix": ""
  },
  "aliases": {
    "components": "@/components",
    "ui": "@/components/ui",
    "lib": "@/lib",
    "hooks": "@/hooks",
    "utils": "@/lib/helpers/cn"
  },
  "iconLibrary": "lucide"
}

Dwie rzeczy warte uwagi. "rsc": false — nie ma serwerowych komponentów Reacta, więc narzędzie nie będzie ich zakładać. "config": "" — w Tailwindzie 4 nie ma pliku konfiguracyjnego, pusty łańcuch jest tu prawidłową wartością.

Najważniejszy jest alias utils. Każdy komponent Magic UI zaczyna się od import { cn } from "@/lib/utils". Jeśli twój projekt trzyma tę funkcję gdzie indziej — u nas to resources/js/lib/helpers/cn.ts — wskaż to tutaj, a narzędzie przepisze import przy zapisie pliku. Bez tego dostaniesz siedemdziesiąt piąte lib/utils.ts w projekcie, który już ma swoje.

Sama funkcja jest zresztą tą samą trzylinijkową sklejką, którą i tak każdy ma:

import clsx, { type ClassValue } from 'clsx'
import { twMerge } from 'tailwind-merge'

export const cn = (...args: ClassValue[]) => twMerge(clsx(args))

Krok 2: alias @/ w Vite

Alias musi rozwiązywać się w dwóch miejscach niezależnie: w TypeScripcie (podpowiedzi i sprawdzanie typów) i w Vite (faktyczny bundling). W tsconfig.json:

"paths": { "@/*": ["./resources/js/*"] }

W vite.config.js, jeśli jeszcze go tam nie ma:

import path from 'node:path'

export default defineConfig({
  // ...
  resolve: {
    alias: { '@': path.resolve(__dirname, 'resources/js') },
  },
})

Krok 3: dyrektywy „use client” i ostrzeżenia Rollupa

Pięćdziesiąt siedem z siedemdziesięciu ośmiu komponentów zaczyna się od "use client". Poza Next.js ta dyrektywa nic nie robi — jest zwykłym literałem tekstowym na początku modułu i React ją ignoruje. Kod działa.

Rollup ma jednak zwyczaj ostrzegać przy każdym takim pliku: Module level directives cause errors when bundled, „use client” was ignored. Przy pięciu komponentach to pięć linii szumu w każdym buildzie, przy piętnastu — piętnaście, i po tygodniu nikt już nie czyta wyjścia z npm run build. Wyciszenie jest jednolinijkowe:

build: {
  rollupOptions: {
    onwarn(warning, warn) {
      if (warning.code === 'MODULE_LEVEL_DIRECTIVE') return
      warn(warning)
    },
  },
},

Można też po prostu usunąć pierwszą linię z pobranych plików. Wadą jest to, że przy aktualizacji komponentu wróci.

Krok 4: renderowanie po stronie serwera

Tu robi się ciekawie, bo Inertia potrafi renderować po stronie serwera, a osiemnaście komponentów Magic UI sięga po window albo document, a siedem rysuje na canvasie.

Sprawdziliśmy, jak są napisane, i większość zachowuje się poprawnie:

  • globe woła createGlobe wyłącznie wewnątrz useEffect, czyli nigdy na serwerze,
  • particles ma jawny wartownik przy odczycie gęstości pikseli: typeof window !== "undefined" ? window.devicePixelRatio : 1, a nasłuchy i pętlę animacji podpina w efekcie.

To nie znaczy, że można przestać patrzeć. Przy każdym komponencie z tej osiemnastki — flickering-grid, glyph-matrix, smooth-cursor, cool-mode, meteors, magic-card, video-text, highlighter i pozostałe — warto rzucić okiem, czy odczyt DOM nie wypadł poza efekt. Plik masz u siebie w repozytorium, więc to jest jedno wyszukanie, nie zgłoszenie błędu do cudzego projektu.

Gdy trafisz na komponent, który się nie broni, ratunek w projekcie z Inertią jest krótki — odłóż go do momentu, w którym drzewo jest już zamontowane w przeglądarce:

import { useEffect, useState } from 'react'

const TylkoWPrzegladarce = ({ children }) => {
  const [zamontowane, setZamontowane] = useState(false)

  useEffect(() => setZamontowane(true), [])

  return zamontowane ? children : null
}

Cena jest realna i trzeba ją znać: taki komponent nie istnieje w HTML-u serwowanym przez serwer, więc nie zobaczy go ani crawler, ani czytelnik z wyłączonym JavaScriptem. Do dekoracyjnego tła to nie ma znaczenia. Do nagłówka H1 z animowanym tekstem — ma, i to duże. Nagłówki animuj komponentami, które renderują treść od razu i dopiero ją animują (text-animate, blur-fade), a nie takimi, które dorysowują ją z JavaScriptu.

Krok 5: przebudowa i restart procesu SSR

Osobna pułapka, na której traci się godzinę przy pierwszym podejściu, i nie ma z Magic UI nic wspólnego — po prostu tu wychodzi. Proces inertia:start-ssr wczytuje zbudowany plik raz, do pamięci. Sam npm run build go nie przeładowuje.

Efekt: przeglądarka dostaje HTML ze starymi klasami, a hydracja Reacta nie nadpisuje atrybutów przysłanych z serwera. Widzisz wersję sprzed zmiany, mimo że pliki i CSS są już nowe. Przy animacjach prowadzi to prosto do fałszywego wniosku „komponent nie działa”:

vendor/bin/sail npm run build && vendor/bin/sail artisan inertia:stop-ssr

Po zatrzymaniu proces trzeba podnieść ręcznie — supervisor w kontenerze pilnuje tylko PHP-FPM.

Dostępność: cztery komponenty na siedemdziesiąt osiem

To jest najpoważniejszy zarzut wobec Magic UI i nie da się go obejść dobrym słowem. Przeszukaliśmy cały katalog rejestru pod kątem prefers-reduced-motion i useReducedMotion. Trafienia są cztery: dia-text-reveal, icon-cloud, retro-grid i scroll-based-velocity.

Pozostałe siedemdziesiąt cztery animują się zawsze — także u osoby, która w ustawieniach systemu poprosiła o ograniczenie ruchu, bo od animacji parallax dostaje zawrotów głowy albo migotania w polu widzenia. Dla części użytkowników to nie jest kwestia gustu, tylko powód, żeby zamknąć kartę.

Minimum, które trzeba dopisać do arkusza globalnego, zanim pierwszy komponent trafi na produkcję:

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

To załatwia wszystko, co animuje się w CSS — czyli całą grupę 36 komponentów bez zależności npm oraz większość tych opartych o motion, bo ta biblioteka pod spodem też korzysta z transformacji CSS.

Nie załatwia pętli na canvasie. particles, flickering-grid, retro-grid, icon-cloud, glyph-matrix, globe i confetti rysują klatka po klatce w JavaScripcie i medium query ich nie dotyczy. Tam potrzebny jest jawny warunek:

import { useReducedMotion } from 'motion/react'

const Tlo = () => {
  const bezRuchu = useReducedMotion()

  if (bezRuchu) {
    return <div className="absolute inset-0 bg-linear-to-b from-slate-900 to-slate-950" />
  }

  return <Particles className="absolute inset-0" quantity={100} />
}
Zasada, którą stosujemy u siebie: efekt z canvasu wchodzi na stronę razem ze swoim statycznym zamiennikiem. Jeśli nie ma sensownego zamiennika, to znaczy, że efekt niesie treść — a wtedy nie powinien być efektem.

Uczciwie: to nie jest problem wyłącznie Magic UI. Tak wygląda większość bibliotek animacyjnych. Ale skoro kod trafia do twojego repozytorium, odpowiedzialność za niego przechodzi na ciebie w momencie instalacji, nie przy najbliższej aktualizacji zależności.

Próg wyzwalania animacji przy przewijaniu

Komponenty reagujące na przewijanie — blur-fade, text-animate, number-ticker, box-reveal — opierają się o useInView z motion/react. number-ticker robi to wzorcowo: useInView(ref, { once: true, margin: "0px" }), potem sprężyna z tłumieniem 60 i sztywnością 100, a wartość wpisywana jest wprost do textContent, z pominięciem cyklu renderowania Reacta.

Pułapka pojawia się, kiedy zaczniesz przekazywać amount zamiast margin. amount mierzy procent wysokości elementu, nie ekranu. Przy sekcji trzy razy wyższej od okna przeglądarki — a takie są normą na telefonie — amount: 0.2 znaczy, że animacja ruszy dopiero po przewinięciu ponad połowy widoku. Użytkownik przez pół ekranu ogląda pustkę z opacity: 0.

Próg liczy się od krawędzi okna, nie od elementu:

viewport={{ once: true, amount: 'some', margin: '0px 0px -12% 0px' }}

margin trafia wprost do rootMargin obserwatora przecięć, więc ujemne -12% skraca dolną krawędź o mniej więcej dwanaście procent wysokości ekranu. Animacja rusza, gdy element wejdzie w kadr o około sto pikseli — niezależnie od tego, jak wysoka jest sekcja. Ta sama uwaga dotyczy surowych IntersectionObserver z progiem procentowym.

Serwer MCP: komponenty dostępne dla asystenta

Magic UI ma oficjalny serwer Model Context Protocol, który udostępnia katalog komponentów narzędziom wspomagającym pisanie kodu. Zamiast szukać nazwy w dokumentacji, opisujesz efekt.

Instalacja jednym poleceniem, osobno dla każdego środowiska:

npx @magicuidesign/cli@latest install claude
npx @magicuidesign/cli@latest install cursor
npx @magicuidesign/cli@latest install windsurf

Albo ręcznie, wpisem w konfiguracji:

{
  "mcpServers": {
    "magicuidesign-mcp": {
      "command": "npx",
      "args": ["-y", "@magicuidesign/mcp@latest"]
    }
  }
}

Po restarcie środowiska działają polecenia w rodzaju „dodaj pionowy marquee z logotypami klientów” albo „wstaw tło z siatką”. Wartość jest konkretna: asystent zna prawdziwe nazwy właściwości i nie wymyśla API, którego nie ma.

Jedna uwaga o utrzymaniu — pakiet @magicuidesign/mcp stoi na wersji 2.0.0 z 9 marca 2026, czyli pół roku bez wydania, podczas gdy sam rejestr komponentów zmieniał się jeszcze w sierpniu. Najnowsze komponenty mogą nie być serwerowi znane. Rejestr shadcn zawsze będzie świeższy.

Magic UI Pro, czyli gdzie jest model biznesowy

Komponenty są na licencji MIT i zostaną darmowe — to jest przynęta, a nie okrojona wersja. Zarabia warstwa wyżej: Magic UI Pro to 199 USD jednorazowo, bez abonamentu, za dziewięć gotowych szablonów stron (agent AI, narzędzie deweloperskie, aplikacja mobilna, SaaS, startup, portfolio, changelog, blog, Codeforge) i ponad pięćdziesiąt sekcji do składania własnych.

Warunki licencji Pro w jednym zdaniu: użycie komercyjne tak, odsprzedaż kodu nie. Dla agencji budującej strony klientom to jest wersja do przeczytania w całości przed zakupem — granica między „użyciem w projekcie klienckim” a „odsprzedażą” bywa w takich licencjach wąska, a nasze zamówienia to zwykle przekazanie repozytorium na własność zamawiającemu.

Część darmowa nie ma tego problemu. MIT to MIT: komercyjnie, w produkcie zamkniętym, z modyfikacjami, bez pytania nikogo o zdanie. Jedyny obowiązek to zachowanie treści licencji — a skoro kod wtapia się w twoje repozytorium, w praktyce oznacza to notę w pliku NOTICE albo w nagłówku skopiowanego komponentu, jeśli twoja firma prowadzi rejestr zależności.

Czy projekt żyje

Żyje, ale ma tempo dojrzałej biblioteki, nie startupu w fazie wzrostu. Sygnały z sierpnia 2026:

  • ostatni commit 11 sierpnia, wcześniejsze rozłożone przez cały lipiec — poprawki błędów, nie kolejne warianty gradientów,
  • zero otwartych zgłoszeń błędów, dwa otwarte pull requesty ze społeczności,
  • zmiany, które ostatnio wchodziły, mówią sporo o priorytetach: przycisk pauzy dla icon-cloud pod wytyczną WCAG G186, poprawka importów typów, żeby komponenty działały w czystym projekcie Vite z Reactem i TypeScriptem, odświeżenie pliku blokad po alertach Dependabota, bramka CI sprawdzająca build produkcyjny.

To jest profil projektu, który przestał gonić za liczbą komponentów i zaczął pilnować tego, co ma. Dla nas dobra wiadomość — ryzyko, że za pół roku trzeba będzie przepisywać wszystko po zmianie API, jest niskie, tym bardziej że kod i tak leży u nas.

Kiedy to ma sens, a kiedy nie

Ma sens przy stronach sprzedażowych, landing page’ach produktu, portfoliach, dokumentacji z ambicjami wizualnymi, stronach wydarzeń, panelach demonstracyjnych na targi. Wszędzie tam, gdzie użytkownik jest na stronie kilka minut, a wrażenie liczy się tak samo jak treść.

Nie ma sensu w narzędziach, których ktoś używa osiem godzin dziennie. Panel administracyjny, w którym licznik za każdym wejściem odlicza od zera do 1 248, jest po trzecim razie irytujący, a po trzydziestym — powodem zgłoszenia. Do wnętrza aplikacji weź shadcn/ui i zostaw ruch tam, gdzie coś komunikuje: ładowanie, zmiana stanu, potwierdzenie.

Nie ma też sensu tam, gdzie liczy się każdy kilobajt na łączu 3G. Tło z cząsteczkami to pętla animacji na canvasie działająca bez przerwy — na telefonie z niskiej półki widać to na wykresie zużycia baterii, a nie tylko na wykresie klatek.

Podsumowanie

Magic UI jest dobrym narzędziem pod jednym warunkiem: traktujesz go jak zbiór punktów wyjścia, a nie jak zależność. Kod ląduje w repozytorium i od tej chwili jest twój — razem z jego brakami.

  • 75 komponentów w rejestrze, 133 gotowe przykłady, całość w 12 tysiącach linii TSX — da się to przeczytać, a nie tylko użyć,
  • 36 komponentów bez jednej zależności npm, 31 na motion; można zbudować całą sekcję i nie powiększyć paczki JS,
  • instalacja przez narzędzie shadcn, przestrzeń @magicui rozpoznawana bez konfiguracji, ocena zdrowia rejestru 97,3 na 100,
  • Laravel z Inertią jest obsługiwany — żaden komponent nie importuje niczego z next/; potrzebne są components.json, alias @/ w Vite i wskazanie własnej funkcji cn w aliasie utils,
  • serwer MCP daje asystentowi prawdziwe nazwy właściwości zamiast zmyślonych — choć sam pakiet nie miał wydania od marca 2026,
  • projekt utrzymywany — ostatni commit w sierpniu 2026, 152 kontrybutorów, zero otwartych błędów.

Trzy rzeczy do zrobienia zanim pierwszy komponent trafi na produkcję: dopisz regułę prefers-reduced-motion do arkusza globalnego (respektują ją tylko cztery komponenty z siedemdziesięciu ośmiu), dopilnuj zgodności majorów motion i framer-motion, i sprawdź w kodzie każdego komponentu z canvasem, czy nie sięga po window poza efektem — jeśli renderujesz po stronie serwera.

Licencja: komponenty open source są na MIT (Copyright © Magic UI) — użycie komercyjne, modyfikacje i produkty zamknięte bez ograniczeń, przy zachowaniu treści licencji. Płatne Magic UI Pro (199 USD jednorazowo, dziewięć szablonów i ponad pięćdziesiąt sekcji) dopuszcza użycie komercyjne, ale zabrania odsprzedaży kodu — przy pracy agencyjnej, gdzie repozytorium przechodzi na własność klienta, warunki warto przeczytać w całości, zanim wystawi się fakturę.