← Blog
Frontend14 min czytania

dgm.js — nieskończone płótno i inteligentne kształty w Reakcie

Biblioteka nieskończonego płótna z bezgłowymi komponentami dla Reacta, wielostronicowością, współpracą w czasie rzeczywistym i eksportem do PDF — a przy tym z kształtami skryptowanymi we wbudowanym Lispie. Rzecz, która decyduje o wdrożeniu, jest jednak licencyjna: GPL-3.0 przy pakiecie wysyłanym do przeglądarki oznacza coś innego niż GPL na serwerze. Wyjaśniamy co i pokazujemy zweryfikowane alternatywy.

Prośba „chcielibyśmy mieć w panelu tablicę do rysowania" pojawia się w projektach częściej, niż mogłoby się wydawać — przy planowaniu przestrzeni, schematach procesów, mapach zależności między obiektami albo prostym narzędziu do adnotacji. Nieskończone płótno z kształtami, które łączą się liniami i pamiętają połączenia, jest sporym kawałkiem inżynierii i nikt nie pisze go od zera.

dgm.js (github.com/dgmjs/dgmjs) jest jedną z odpowiedzi na tę potrzebę i technicznie odpowiedzią ciekawą — z bezgłowymi komponentami dla Reacta, wielostronicowością, współpracą w czasie rzeczywistym, eksportem do PDF i kształtami, które da się skryptować we wbudowanym dialekcie Lispa.

Ten wpis odwraca jednak zwykłą kolejność i licencję omawia nie na końcu, a jako rzecz najważniejszą. Powód jest prosty: przy bibliotece frontendowej na GPL-3.0 licencja rozstrzyga o wdrożeniu, zanim dojdzie się do oceny funkcji — i rozstrzyga inaczej, niż podpowiada intuicja wyrobiona na oprogramowaniu serwerowym.

Stan projektu

Dane z API GitHuba i npm na 7 października 2026:

  • 1671 gwiazdek i 85 forków, repozytorium założone 4 lutego 2024, kod w TypeScripcie,
  • licencja GPL-3.0 z osobną opcją komercyjną,
  • ostatnia wersja 1.5.5 opublikowana 26 grudnia 2025 — i tego samego dnia był ostatni push do repozytorium, czyli ponad dziewięć miesięcy ciszy,
  • 20 otwartych zgłoszeń oraz — liczba, która mówi najwięcej o skali użycia — 521 pobrań pakietu z npm w ostatnim miesiącu,
  • pięć pakietów: core, react, export, pdf i wtyczka do Yjs na współpracę w czasie rzeczywistym.

Dwie rzeczy w organizacji tego projektu trzeba powiedzieć wprost, bo obie wpływają na decyzję o użyciu. Pierwsza jest zapisana w README bez ogródek: projekt nie przyjmuje wkładu z zewnątrz i nie akceptuje żadnych pull requestów. Nie jest to więc projekt społecznościowy, a otwarty kod produktu rozwijanego przez jedną osobę.

Druga wynika z listy wdrożeń w README: wymienione tam Frame0 (narzędzie do szkicowania makiet) i DGM App to produkty tego samego autora. Biblioteka jest więc silnikiem komercyjnych aplikacji, udostępnionym na copyleftowej licencji ze ścieżką odpłatną — model zupełnie legalny i uczciwie opisany, ale zmieniający sposób, w jaki należy patrzeć na jej rozwój. Dziewięć miesięcy bez commita nie znaczy tu porzucenia, bo autor ma biznesowy powód, żeby silnik utrzymywać; znaczy natomiast, że tempo rozwoju odpowiada potrzebom jego produktów, a nie naszym.

Co ta biblioteka potrafi

Zestaw funkcji jest poważny i wart wyliczenia, bo tłumaczy, dlaczego warto się nią w ogóle zainteresować:

  • Nieskończone płótno z obsługą wielu stron — to drugie jest rzadkie i przydatne, bo dokument z kilkoma tablicami jest naturalnym modelem dla projektu, nie dla pojedynczego rysunku,
  • Bezgłowe komponenty dla Reacta — logika bez narzuconego wyglądu, więc interfejs dopasowuje się do systemu projektowego klienta, nie odwrotnie,
  • Styl odręczny — rysunek wyglądający jak szkic, co przy makietach i schematach roboczych ma realne znaczenie komunikacyjne: odbiorca widzi, że to propozycja, nie projekt końcowy,
  • Współpraca w czasie rzeczywistym przez osobną wtyczkę integrującą Yjs, czyli bibliotekę bezkonfliktowych typów replikowanych,
  • Tryb ciemny z kolorami adaptacyjnymi — nie przełącznik na motyw, a przeliczanie kolorów rysunku,
  • Eksport do PNG, JPEG, WebP i SVG oraz do PDF w osobnych pakietach,
  • Tekst formatowany oraz eksport i import JSON — czyli dokument da się przechowywać w bazie klienta i wersjonować bez binarnego formatu.

Inteligentne kształty, czyli Lisp we frontendzie

Najbardziej nieoczywista decyzja projektowa i rzecz, która wyróżnia tę bibliotekę spośród wszystkich podobnych. Kształty nie są klasami TypeScriptu, które się rozszerza — są opisywane skryptem w osadzonym dialekcie Lispa o nazwie Mal, z wyrażeniami nawiasowymi definiującymi sposób rysowania.

W praktyce jeden skrypt określa trzy rzeczy: jak kształt jest rysowany na płótnie, jaki ma obrys i gdzie ma punkty połączeń dla linii. Wygląda to tak:

(do
  (def! m 5)
  (def! l (. shape :left))
  (def! t (. shape :top))
  (def! r (. shape :right))
  (def! b (. shape :bottom))
  (call canvas :polygon [
    [l t]
    [r t]
    [r (- b m)]
    [(- r m) b]
    [l b]
    [l t]
  ]))

To jest rysowanie kartki z zagiętym rogiem — pięć punktów, z których jeden jest przesunięty o marginesy. Ten sam zestaw punktów zwrócony jako wartość służy potem jako obrys i jako lista punktów połączeń, więc linia doczepiona do kształtu wie, gdzie się przyklejać. Do tego dochodzi odczyt właściwości rozszerzonych kształtu, czyli parametryzacja bez pisania kodu.

Ocena tego rozwiązania jest dwustronna i warto ją mieć przed decyzją. Na plus: definicje kształtów stają się danymi, a nie kodem — da się je trzymać w bazie, edytować bez przebudowy aplikacji i dostarczać jako bibliotekę elementów dla konkretnego klienta. Przy narzędziu, w którym klient ma własny zestaw symboli branżowych, jest to bardzo mocna właściwość. Na minus: własny kształt wymaga nauczenia się języka, którym poza tym projektem nie posługuje się nikt. Nie ma tu ekosystemu, przykładów z internetu ani osoby w zespole, która to już robiła.

Architektura i trasowanie połączeń

Wewnętrzna dokumentacja projektu opisuje przepływ sterowania jednym łańcuchem: edytor przyjmuje akcje, kontroler zamienia je w zdarzenia, przekształcenia tworzą transakcje, a te mutują magazyn obiektów. Reguła jest przy tym twarda i zapisana wprost: wszystkie zmiany idą przez akcje, głównie z powodu rozwiązywania ograniczeń między kształtami. Stan nie jest utrzymywany przez rozbudowany metamodel, a serializowany prostym eksportem i importem JSON — i to była świadoma decyzja, żeby uprościć poprzednią wersję biblioteki.

Osobno opisane jest trasowanie połączeń, czyli najtrudniejsza część każdego edytora diagramów. Są dwa tryby — skośny i prostokątny — a procedura dla każdego z nich jest wypisana krok po kroku: przesunięcie punktów końcowych do środków albo do punktów połączeń, przesunięcie ich na styczne obrysu, usunięcie segmentów leżących wewnątrz kształtu i na końcu redukcja ścieżki przez usuwanie punktów według kąta. Kto próbował samodzielnie zrobić linię, która ładnie omija dwa prostokąty, doceni, że ktoś to przemyślał i zapisał.

Model kształtów

Hierarchia typów jest krótka i warto ją znać, bo to ona decyduje, czy model danych biblioteki pasuje do dziedziny klienta. U podstawy stoi Shape z pozycją i rozmiarem, mogący zawierać dzieci — więc grupowanie jest wbudowane w model, nie dorobione. Z niego wychodzą trzy gałęzie:

  • Box — dokłada wypełnienie, narożniki i tekst; z niego dziedziczą Text, Rectangle i Ellipse. Wynika z tego rzecz przydatna: każdy prostokąt i każda elipsa ma tekst z definicji, więc etykiety w schemacie nie są osobnymi obiektami do pozycjonowania,
  • Line — ma ścieżkę i typ linii, a jej pochodną jest Connector z polami początku i końca. To rozróżnienie jest istotne: linia swobodna i połączenie między kształtami to dwa różne typy, a nie jedna rzecz z flagą,
  • Diagram — korzeń dokumentu.

Warstwa magazynu jest równie oszczędna: fabryka tworzy kształty, przekształcenie tworzy transakcje, magazyn je stosuje, a stan edytora trzyma wszystkie trzy. Transakcja jest zbiorem mutacji — i to jest miejsce, w którym cofanie zmian oraz integracja z bezkonfliktowymi typami replikowanymi stają się naturalne, bo obie potrzebują właśnie strumienia jawnych mutacji.

Uwaga o samej dokumentacji, którą trzeba dodać dla uczciwości: ten opis architektury jest wewnętrznym brudnopisem. Plik nosi nazwę roboczą poprzedniej wersji, zawiera listę zadań do zrobienia, a część notatek jest po koreańsku. To spójne z zasadą braku wkładu z zewnątrz — dokumentacja techniczna nie jest pisana dla nas. Publiczna dokumentacja i przykład na StackBlitz istnieją osobno.

Co na tym faktycznie stoi

Przy bibliotece z pięciuset pobraniami miesięcznie pytanie „czy to w ogóle działa w produkcji" jest zasadne, a odpowiedź daje lista wdrożeń w README. Są tam cztery pozycje i warto je rozdzielić:

  • Frame0 — narzędzie do szkicowych makiet o niskiej wierności, oraz DGM App — pełna aplikacja do notatek graficznych. Oba są produktami autora biblioteki, co znaczy, że silnik jest utrzymywany pod realne obciążenie komercyjne, ale też że kierunek rozwoju wyznaczają ich potrzeby,
  • Nakso — tablica działająca lokalnie, i draw2app — narzędzie generujące aplikację internetową ze szkicu o niskiej wierności przy pomocy modelu językowego. Te dwa są wdrożeniami zewnętrznymi, więc pokazują, że biblioteka daje się użyć komuś spoza projektu.

To jest sytuacja typowa dla narzędzi rozwijanych w modelu „silnik pod własny produkt": jakość kodu bywa wyższa, niż sugerują statystyki pobrań, bo autor sam jest jego najbardziej wymagającym użytkownikiem. Jednocześnie brak społeczności znaczy dokładnie to, co znaczy — przy problemie zostajesz z kodem i z jedną osobą, która go zna.

Licencja: rzecz, która rozstrzyga

dgm.js jest dostępny na dwóch licencjach i strona projektu opisuje to jednoznacznie: GPL-3.0 dla oprogramowania otwartego, którego autorzy potrafią spełnić jej warunki, oraz licencja komercyjna dla oprogramowania własnościowego, gdzie kodu udostępniać się nie chce albo nie można. Cennika nie ma — po licencję komercyjną trzeba napisać na wskazany adres.

I teraz sedno, bo tu wyrobiona na serwerach intuicja prowadzi na minę. Przy oprogramowaniu serwerowym na GPL rozumowanie jest zwykle takie: uruchamiamy je u siebie, nikomu nie przekazujemy kopii, więc nie ma rozpowszechniania i nie ma obowiązków. W przypadku biblioteki frontendowej to rozumowanie nie działa, bo mechanika jest inna: pakiet JavaScriptu jest wysyłany do przeglądarki każdego użytkownika. Każdy odwiedzający otrzymuje kopię programu — a to jest, w powszechnie przyjmowanym odczytaniu tej licencji, właśnie przekazanie utworu.

Konsekwencja praktyczna dla pracy agencyjnej: zamknięta aplikacja klienta, do której pakietu wchodzi dgm.js, jest utworem opartym na programie na GPL-3.0 i wysyłanym użytkownikom. Wyjścia są dwa i oba trzeba klientowi nazwać: albo cała ta aplikacja frontendowa jest udostępniona na GPL-3.0 wraz z kodem źródłowym, albo kupuje się licencję komercyjną.

Zaznaczam wyraźnie, że to jest odczytanie licencji, nie porada prawna — a przy projekcie, w którym stawką jest kod klienta, właśnie taką sprawę oddaje się do sprawdzenia prawnikowi, zanim biblioteka wejdzie do pliku zależności. Zwracam natomiast uwagę na drugą stronę tego samego faktu: ta licencja jest oczywistym wyborem, jeśli sami budujemy coś otwartego. Wtedy GPL-3.0 nic nie kosztuje i nic nie utrudnia.

Alternatywy, zweryfikowane pod kątem licencji

Skoro licencja jest tu głównym kryterium, wypada podać, jak wygląda w narzędziach z tej samej półki. Wszystkie dane sprawdzone bezpośrednio w plikach licencji i w API GitHuba w dniu pisania:

  • Excalidraw — MIT, 131 508 gwiazdek, push w dniu pisania tego tekstu. Licencyjnie bez zastrzeżeń, styl odręczny w standardzie, ekosystem nieporównywalnie większy,
  • Konva — MIT (nota obejmuje też oryginalną pracę nad KineticJS), 14 776 gwiazdek, push dzień przed. Niżej poziomem: to biblioteka do rysowania na płótnie, nie gotowy edytor diagramów, więc dużo trzeba dołożyć samemu,
  • tldraw — 50 226 gwiazdek, push w dniu pisania, ale licencja własnościowa firmy tldraw, nie otwarta. Sam tekst licencji definiuje osobno środowisko produkcyjne i deweloperskie i odsyła po licencje alternatywne do sprzedaży. Trzeba ją przeczytać w całości przed użyciem — jest to najbliższy odpowiednik funkcjonalny dgm.js, ale nie jest to oprogramowanie otwarte.

Wniosek dla typowego zlecenia agencyjnego jest więc dość jednoznaczny: przy zamkniętej aplikacji klienta pierwszym kandydatem jest Excalidraw, a dgm.js i tldraw wymagają albo rozmowy o licencji komercyjnej, albo otwarcia kodu.

Pułapki

  • GPL-3.0 w pakiecie wysyłanym do przeglądarki to sytuacja inna niż GPL na serwerze. Najważniejsza rzecz w tym wpisie,
  • Licencja komercyjna bez cennika — koszt poznasz dopiero po kontakcie, więc przy wycenie projektu jest to niewiadoma,
  • Projekt nie przyjmuje pull requestów. Poprawka, której potrzebujesz, albo pojawi się, bo potrzebuje jej autor, albo nie pojawi się wcale,
  • Ponad dziewięć miesięcy bez commita i 521 pobrań miesięcznie. Nie ma tu społeczności, na której można się oprzeć w razie problemu,
  • Własne kształty wymagają nauki osadzonego Lispa, którego nie zna nikt poza tym projektem,
  • Wewnętrzna dokumentacja techniczna nie jest pisana dla osób z zewnątrz — brudnopis z zadaniami i notatkami po koreańsku,
  • Współpraca w czasie rzeczywistym to osobna wtyczka, a z nią osobny serwer synchronizacji i osobny zakres pracy,
  • Eksport do PDF i do obrazów są osobnymi pakietami — warto o nich wiedzieć przy szacowaniu rozmiaru pakietu wynikowego.

Gdzie to ma sens

Zakres zastosowań jest węższy niż przy poprzednich narzędziach z tej serii, ale realny:

  • Nasze własne projekty otwarte. Jeśli budujemy coś na licencji zgodnej z GPL-3.0, ta biblioteka jest do wzięcia bez żadnych kosztów i zastrzeżeń,
  • Prototypy i badanie możliwości. Przykład na StackBlitz pozwala sprawdzić, czy w ogóle warto rozmawiać o takim narzędziu z klientem, bez instalowania czegokolwiek,
  • Produkt z własną biblioteką kształtów branżowych. To jest przypadek, w którym skryptowane kształty naprawdę wygrywają: zestaw symboli specyficznych dla dziedziny klienta, dostarczany jako dane i zmienialny bez wdrożenia. Warto wtedy przeliczyć koszt licencji komercyjnej wobec czasu, jaki zajęłoby to samo na Excalidrawie albo Konvie,
  • Wielostronicowe dokumenty ze schematami — funkcja, której w prostszych narzędziach zwykle nie ma i którą trzeba by dopisywać samemu.

Podsumowanie

  • Solidny zestaw funkcji: nieskończone płótno, wiele stron, bezgłowe komponenty dla Reacta, styl odręczny, tryb ciemny z adaptacją kolorów, eksport do obrazów i PDF, JSON w obie strony,
  • Kształty skryptowane w osadzonym Lispie — definicje kształtów jako dane, ale z językiem do nauczenia od zera,
  • Wszystkie zmiany przez akcje, stan serializowany prostym JSON-em, trasowanie połączeń w dwóch trybach opisane krok po kroku,
  • GPL-3.0 albo licencja komercyjna — a pakiet w przeglądarce znaczy, że pierwsza opcja obejmuje aplikację klienta,
  • Sprawdź licencję przed funkcjami; przy zamkniętym kodzie klienta to jest pierwsza, nie ostatnia rozmowa,
  • Brak przyjmowania wkładu z zewnątrz i dziewięć miesięcy ciszy przy 521 pobraniach miesięcznie,
  • Do zamkniętych projektów zacznij od Excalidrawa (MIT, aktywny, ogromna społeczność); Konva daje niższy poziom na MIT, a tldraw ma licencję własnościową,
  • Do projektów otwartych dgm.js jest realną i ciekawą opcją — i wtedy warto go rozważyć poważnie.

Licencja: dgm.js jest udostępniony na GPL-3.0, z osobną licencją komercyjną dostępną po kontakcie z autorem — klasyczne podwójne licencjonowanie, w którym copyleft jest wariantem darmowym, a licencja odpłatna ścieżką dla oprogramowania własnościowego. GPL-3.0 to silny copyleft: utwór oparty na programie i przekazywany dalej musi być udostępniony na tej samej licencji, wraz z kodem odpowiadającym. Kluczowa różnica wobec typowego oprogramowania serwerowego — i powód, dla którego omówiłem licencję na początku, a nie na końcu — polega na tym, że biblioteka frontendowa jest przekazywana każdemu użytkownikowi w postaci pakietu wysyłanego do jego przeglądarki. Nie ma tu sytuacji „używamy wewnętrznie, więc nie rozpowszechniamy": w powszechnie przyjmowanym odczytaniu tej licencji wysłanie skryptu do przeglądarki jest przekazaniem kopii programu. Dla zamkniętej aplikacji klienta zostają więc dwa wyjścia — udostępnienie tej aplikacji na GPL-3.0 albo zakup licencji komercyjnej — i obie ścieżki należy wycenić, zanim biblioteka trafi do pliku zależności. Nie jest to porada prawna, a wskazanie, którą sprawę trzeba oddać prawnikowi. Zaznaczę na koniec rzecz, o której przy krytyce copyleftu łatwo zapomnieć: ten model jest w pełni uczciwy — autor jasno opisuje oba warianty, nie ukrywa ograniczeń wersji darmowej i nie stosuje licencji udającej otwartość. Wybór jest po naszej stronie, a informacja potrzebna do jego dokonania jest podana wprost.