Ten dokument opisuje cel, strukturę i decyzje architektoniczne platformy Lolly. Odzwierciedla zarówno wizję produktu, jak i obecny stan kodu.
Status: Lolly to wewnętrzny prototyp w zamkniętym pilotażu, który jeszcze się nie zakończył. Silnik jest deterministyczny i wewnętrznie spójny, ale produkt jest wczesny - SUSE jest klientem numer jeden - a jego mechanizmy kryptografii i parsowania plików przechodzą obecnie rygorystyczne utwardzanie infrastruktury SUSE, przygotowujące je do skali korporacyjnej (naprawdę dobrze nam to wychodzi). Traktuj poniższą architekturę jako zamysł projektowy w trakcie testów, a nie gotowy, certyfikowany produkt. Zobacz Adoption & Governance, by dowiedzieć się, jak pilotaż jest prowadzony i mierzony.
Jak czytać tę stronę. Zawiera dwa rodzaje materiału, w tej kolejności. Pierwsza połowa to dlaczego to istnieje: problem, pozycjonowanie i cykl życia, przez który przechodzi pojedynczy zasób. Od Ogólny obraz w dół to już jak dopasowane są warstwy: dokument architektury dla współtwórców, obejmujący podział na silnik/powłokę/pakiet, układ repozytorium, cele dostarczania i zobowiązania, które ograniczają każdą zmianę w platformie. Jeśli jesteś tu, by zmieniać kod, a nie zrozumieć produkt, zacznij od ogólnego obrazu.
Dwa uzupełniające dokumenty sięgają głębiej niż ta strona.
engine/README.mdw repozytorium to mapa silnika moduł po module, z wygenerowaną tabelą każdego modułu i tego, co parsuje lub zapisuje. Threat Model & Trust Boundaries to ta sama architektura odczytana jako granice zaufania i to właściwa strona na każde pytanie o to, co silnik traktuje jako niezaufane.
Dlaczego to istnieje
Zespoły mierzą się z powtarzającym się problemem: praca kreatywna i związana z treścią, która jest zbyt przewidywalna, by za każdym razem angażować wykwalifikowane ręce, ale zbyt wrażliwa na jakość, by oddać ją bez zabezpieczeń. Efektem jest albo wolna przepustowość (wąskie gardło specjalisty), albo niespójność (ludzie używający dowolnego dostępnego narzędzia), albo uzależnienie od dostawcy (SaaS-owy DAM kontrolujący twoje szablony).
Ta platforma jest bezpośrednią odpowiedzią:
Programistyczna kreacja i treści na skalę - generowanie zasobów bez pracy ręcznej, z regułami pod centralną kontrolą, dla pracowników, dostawców i partnerów.
Lolly to nie miejsce, w którym powstaje system projektowy - to miejsce, w którym jest on produkowany. Pomyśl o tym jak o automacie do projektowania: dokonujesz wyboru, dostajesz wynik. Za każdym razem. Silnik dąży do najwyższej jakości, jaką dany format może uzyskać na sprzęcie, który masz przed sobą, a ten sam silnik tworzy ten sam plik na każdej platformie, na jaką trafia.
Efektem jest obfitość: każde wydarzenie ma poprawne oznakowanie, każdy alert CVE pasuje do stylu firmowego, każda etykieta drukuje się czysto, każda stopka e-mail jest aktualna - wszystko bez zgłoszenia do działu projektowego. Platforma obsługuje powtarzalną, zoperacjonalizowaną kreację. Celowo nie jest to narzędzie do twórczości na zamówienie - projektanci nadal odpowiadają za flagowe prace.
Innowacja probabilistyczna, skalowanie deterministyczne
Każda dyskusja o AI w procesie kreatywnym utyka na tym samym pytaniu: która część jest zadaniem maszyny? To stare pytanie z ustaloną odpowiedzią. Skrybowie i iluminatorzy pracowali już między dwoma narzędziami - luźnym szkicem, gdzie nic nie było ustalone i wszystko można było wypróbować, oraz prasą drukarską, onieśmielającą właśnie dlatego, że się zobowiązywała. Szkice były miejscem, gdzie działa się sztuka. Prasa była sposobem, by dotarła do kogokolwiek. Nikt nie mylił tych dwóch rzeczy, a obie wciąż się rozwijały - nowe atramenty, nowe kroje, nowe prasy - każda ulepszana w harmonii z rzemiosłem i intencją, której służyła.
Lolly wyznacza tę samą granicę. Eksploruj probabilistycznie: model, projektant, luźny pomysł, prompt, który prowadzi tam, gdzie nikt nie planował. Potem skaluj deterministycznie - rzeczą, która dociera do dziesięciu tysięcy wyników, jest narzędzie, a narzędzie renderuje się za każdym razem tak samo, na podstawie danych wejściowych, które można odczytać. Eksploracja pozostaje swobodna, bo nic dalej w łańcuchu nie zależy od tego, czy wypadnie tak samo dwa razy. Wynik zdobywa zaufanie, bo nie jest zgadywanką. Przełożenie eksperymentów z AI na przewidywalne, powtarzalne rezultaty nie jest nową dyscypliną; to ten sam podział pracy, który sprawił, że druk w ogóle zasługiwał na zaufanie.
Ufaj procesowi twórczemu, skaluj z rygorem.
Na tle alternatyw
| Capability | Lollyconstraint-first | Penpotopen design | CanvaAffinity Cavalry |
Adobedesktop pro | Brand DAMFrontify Bynder |
Cloudinarymedia pipeline | Figmaonline pro | Render APIsBannerbear Placid Creatomate |
|---|---|---|---|---|---|---|---|---|
| Overall completenessunweighted mean - weight rows for your own context · columns are sorted by this row | 84 | 70 | 57 | 48 | 41 | 41 | 41 | 34 |
Production maturity & track recordCanva, Adobe, Figma, Bynder/Frontify: a decade-plus at massive scale. Render APIs: years in production pipelines. Penpot: shipping, large community, younger at enterprise scale. Lolly: closed pilot, security hardening underway, no public case studies. Cloudinary: 2012, enterprise media infrastructure at global scale. |
25 | 75 | 100 | 100 | 100 | 100 | 100 | 75 |
Mass generation from data (CSV / API)Lolly: batch grid + CLI, one file per row. Canva: Bulk Create + Autofill API - real, but Enterprise-gated, async, text/image fields only; Affinity Publisher adds desktop data merge. Adobe: InDesign data merge and scripting. Figma: Buzz fills templates from CSV or XLSX, free in beta (Aug 2026) - cloud- and account-gated, 50. Penpot: open API/MCP, not purpose-built. Render APIs: this is their entire product - account- and cloud-gated, so 75 under the method rule. DAM: Studio-style batch create and resize. Cloudinary: URL-driven overlays and named transforms derive variants at scale - account-gated, 75. |
100 | 50 | 50 | 50 | 75 | 75 | 50 | 75 |
Offline & air-gap operationLolly: static deploy, no server in the render path, MDM/air-gap. The Canva column is scored on its best family member: Affinity (free since Oct 2025) runs offline as a desktop suite once a verified account activates it - 75, the same deduction Adobe takes. Canva's own Offline (2026) still edits pre-synced designs only, per device, in a 14-day window. Adobe: desktop apps run offline; licensing phones home. Figma: cached-file viewing and limited editing. Penpot: self-host on your infra behind a firewall (server required). Cloud APIs and DAM: none. |
100 | 75 | 75 | 75 | 0 | 0 | 25 | 0 |
On-device rendering - data never leavesLolly: renders and converts in-browser or CLI, locally; zero upload. Adobe: local desktop rendering, but cloud services and telemetry in the suite. Figma: canvas renders locally, files live in Figma's cloud. Penpot: 90 - rendering happens in the browser and the save target is a server that can be your own sovereign private cloud, even your own laptop, with private export throughout; only the server hop separates it from Lolly. Canva itself is server-side by design; the column's 75 is Affinity - local desktop rendering, account activation and telemetry, the same shape as Adobe. Render APIs, DAM: server-side by design. |
100 | 90 | 75 | 75 | 0 | 0 | 25 | 0 |
Hard brand constraints (structural)Lolly: rules compiled into template code - off-brand output is impossible, not just discouraged. Canva: element locks - permission-based, admin-set and static: no template logic such as conditional logo switching or responsive recomposition at fill time, and Canva AI does not yet respect Brand Controls - 50. Render APIs: templates are fixed (only declared fields vary) but no governance layer. DAM: locked templates with restrictions. Figma: Buzz templates hold locked guidelines at fill time; the design surface stays review-enforced - 50. Penpot: tokens and systems enforced by review, not runtime. Adobe: libraries, little enforcement. Cloudinary: presets and Enterprise-gated transformation templates fix operations, not brand layout - 50. |
100 | 50 | 50 | 25 | 75 | 50 | 50 | 75 |
C2PA provenance, signed at creationAdobe: the broadest shipped implementation (Photoshop, Lightroom, Premiere, Firefly) - signing happens locally in the desktop apps and in the cloud for the Content Authenticity web app, and nothing signs without an Adobe account and an Adobe-provisioned identity, so it is account-gated end to end: 75 under the method rule. Lolly: on-device key generation, offline signing, plus pixel imprint - no account anywhere; the on-device key reads as unverified in stock validators (the interim trust list froze Jan 2026) until an identity or an organization's own CA vouches for it, and the stack is pilot-stage and unaudited, so 75. Penpot: 50 via the official Lolly Export plugin - the same on-device engine signing Lolly uses, opt-in rather than default (and disclosed plainly: it is Lolly's own plugin). No evidence of C2PA writing in Canva, Figma, render APIs or DAM as of Aug 2026. Cloudinary: 50 - signs images on delivery (fl_c2pa, CAI member since 2020), attesting delivery by Cloudinary rather than creation by you. |
75 | 50 | 0 | 75 | 0 | 50 | 0 | 0 |
CLI, pipeline & AI-agent automationLolly: CLI, TUI, MCP server, URL mode - one engine everywhere. Render APIs: API-first, webhooks, integrations - account- and cloud-gated, so 75 under the method rule. Penpot: open API, plugins, official MCP server. Canva: Connect API - Enterprise-gated, async, rate-limited. Adobe: UXP/ExtendScript plus Firefly APIs. Figma: strong REST/plugin API, no render pipeline. DAM: asset-management APIs. Cloudinary: API-first media pipeline - account-gated, 75. |
100 | 75 | 50 | 50 | 50 | 75 | 50 | 75 |
Live collaboration (real-time co-editing)The capability that trades most directly against offline. Figma: the scale benchmark - 200 simultaneous editors, up to 500 people in a file - account and cloud required. Canva: mature real-time editing across the product, same precondition. Penpot: real-time multiplayer with live cursors; self-hosting lifts the vendor-account precondition, but a server is still required. Lolly: pairwise P2P shipped - an invite/accept ceremony (QR, link or code), LAN-first, zero server, no account, works fully air-gapped - no large rooms, so Partial; the only column that collaborates with no internet at all. Adobe: Live Co-Editing in beta, cloud documents only. Render APIs: no editing surface. DAM: comments and approvals, not canvas co-editing. Cloudinary: DAM comments and workflows, no canvas co-editing. |
50 | 75 | 75 | 25 | 25 | 25 | 75 | 0 |
No design skill requiredCanva: the category benchmark for ease. DAM: fill a locked template. Lolly: fill in fields - but someone technical must author tools first (the cold-start cost sits with builders, not producers). Render APIs: swaps design skill for developer skill. Adobe, Figma, Penpot: professional tools. Cloudinary: the media library is easy; transformations are developer territory. |
100 | 25 | 100 | 25 | 100 | 50 | 25 | 50 |
Open source, self-hosted, no lock-inPenpot: MPL-licensed, 51k+ stars, self-host via Docker/K8s - fully verifiable today. Lolly: MPL-2.0, the repository is public (github.com/lolly-tools/lolly), OBS builds, no contributor agreement - and it is young: months in public, no external audit, a community still forming, with SUSE maintaining it as a user of its own systems. 75 while youth is the honest deduction. Everything else is proprietary SaaS or proprietary desktop. |
75 | 100 | 0 | 0 | 0 | 0 | 0 | 0 |
Cost at production scaleLolly and Penpot: zero marginal cost on your own hardware. Render APIs: metered - roughly $0.005–0.049 per image, credits often expiring monthly. Canva/Figma: per-seat; Canva's automation needs Enterprise, though Affinity itself is free since Oct 2025. Adobe: premium per-seat suite. DAM: sales-led enterprise quotes, MAU or seat models. Cloudinary: credit-metered across transforms, storage and bandwidth - 25. |
100 | 100 | 50 | 25 | 25 | 25 | 50 | 25 |
Annual medium enterprise spendIndicative list-price arithmetic for a medium enterprise - think 500-5000 people - August 2026: a guess range, not a quote; deals vary and the seat mix dominates. Ring = how much of the board's largest annual spend (US$500k) you keep; the number in the ring is each range's upper bound. Canva (US$75k-400k; Affinity free since Oct 2025 pulls the design-seat share down), Adobe (US$100k-500k) and Figma (US$30k-250k) assume the realistic creative-seat share of an organisation this size - tens to hundreds of seats, not a licence for every employee. Render APIs price by usage (US$5k-60k). DAM is quote-only, commonly US$50k-250k and up. Penpot is hand-set at 99: "your server" can be your own laptop - a small technical hurdle at well under 1% of an Adobe-scale spend. Lolly: US$0 by licence - the apps ship free, run offline and keep working in perpetuity; works on devices immediately, config optional; hosting an instance is an organisation's choice, not a cost of entry. Cloudinary: US$30k-150k, credit-based; enterprise contracts commonly sit near US$82k. |
$0 | $0 | $400k | $500k | $250k+ | $150k | $250k | $60k |
Kompletność możliwości w dzisiejszych narzędziach kreatywnych, na podstawie badania z sierpnia 2026. Punktacja: 0 brak, 25 na poziomie obejścia, 50 realne, ale ograniczone lub częściowe, 75 mocne z zastrzeżeniami, 100 kluczowa kompetencja.
signed by Lollypositioning-comparison.htmlHTMLAI generatedgenerated by ClaudeSprawdź samodzielnieGet the signed filepixels, not shapes38 KBLuka jest jasna: nic, co dziś jest dostępne, nie daje nam wyniku opartego najpierw na ograniczeniach, działającego offline, o niskim progu umiejętności i dostępnego wewnętrznie. Lolly zawiera nawet otwarte płótno - Design - gdzie kolory, typografia i zasoby podlegają globalnym ustawieniom marki, więc swobodny układ pozostaje oparty najpierw na ograniczeniach. Czym nie jest, to nieograniczony pakiet projektowy: projektanci nadal używają Illustratora i Figmy do flagowych prac na zamówienie. Permutacje można składać za pomocą tego narzędzia.
signed by Lollyvector SVGSprawdź samodzielnieGet the signed file281 paths~38k nodes443 groups6 images2269 KB
signed by Lollyvector SVGSprawdź samodzielnieGet the signed file281 paths~38k nodes443 groups6 images2270 KB
Użyj do: Szybkiego generowania zoperacjonalizowanych zasobów kreatywnych - kafelków wydarzeń, identyfikatorów imiennych, stopek, alertów CVE, kodów QR, kart społecznościowych, etykiet przesyłek, ustrukturyzowanych raportów.
Nie używaj do: Unikalnej twórczości typu hero.
Cykl życia kampanii
Najjaśniejszym sposobem zobaczenia, czym jest Lolly, nie jest lista funkcji - to śledzenie pojedynczego zasobu, gdy przechodzi z rąk do rąk. Prześledź, jak jedna zlokalizowana karta kampanii przemieszcza się przez organizację:
- Twórca ustala reguły. Projektant tworzy bazowy szablon w narzędziu Design, na stałe wpisując zmienne typografii i kolorów marki. Nie robi jednej karty - wykonuje pracę podstawową raz, by nigdy więcej nie musieć ręcznie lokalizować.
- Deweloper to skaluje. Ten sam szablon jest podłączony do nocnego pipeline'u przez CLI, więc świeży wykres lub nowy wariant językowy generuje się automatycznie - żaden projektant nie otwiera pliku ponownie.
- Producent po prostu z tego korzysta. Handlowiec, offline w samolocie, otwiera to samo narzędzie i generuje w pełni zgodną z marką prezentację na spotkanie z klientem. Bez umiejętności projektowych, bez sieci, bez czekania.
"Świeży wykres" z kroku drugiego to render taki jak ten, wygenerowany z ciągu danych i garści parametrów, bez otwierania przez nikogo pliku projektowego:
signed by Lollyvector SVGSprawdź samodzielnieGet the signed file15 paths~1.3k nodes4 groups21 KB
signed by Lollyvector SVGSprawdź samodzielnieGet the signed file15 paths~1.3k nodes4 groups21 KB
Chodzi nie o to, że Lolly jest dobre dla projektantów i dobre dla deweloperów i dobre dla sprzedaży, każde z osobna. To sztafeta: początkową pracę twórcy skaluje deweloper, co z kolei daje siłę producentowi. Bezwysiłkowe doświadczenie nietechnicznego handlowca w samolocie jest możliwe wyłącznie dzięki rygorowi, który ustalił projektant, a wdrożył deweloper.
To jest mnożnik siły. Lolly nie jest szufladą osobnych narzędzi dla osobnych ról - to jeden deterministyczny cykl życia zasobu, którego dotyka każda rola, a każda para rąk, przez którą przechodzi, mnoży wartość poprzedniej.
Jedna akceptacja, dziesięć tysięcy zasobów
Ponieważ akceptacja znajduje się w narzędziu, a nie w pliku (zobacz Jak Lolly wypada na tle innych), skala przestaje być problemem przeglądu. Zaakceptuj raz zlokalizowane narzędzie do kart społecznościowych, a potem wygeneruj 10 000 zasobów w 12 językach z arkusza kalkulacyjnego - i żaden z nich nie potrzebuje nowej kontroli zgodności od działu prawnego czy marki, bo szablon, z którego wszystkie powstają, był już zaakceptowany.
To samo deterministyczne narzędzie osiąga tę skalę na trzy sposoby, z których każdy daje identyczny, wcześniej zaakceptowany wynik:
- Osoba, w aplikacji. Siatka wsadowa
/pro: wklej lub zaimportuj wiersze, otrzymaj jeden gotowy zasób na wiersz, pobierz archiwum zip. Bez umiejętności projektowych, bez zgłoszenia, bez czekania. - Deweloper, z linii poleceń. CLI uruchamia ten sam silnik i tę samą ścieżkę renderowania bez interfejsu, więc narzędzie można wywołać sekwencyjnie dla wszystkich 10 000 wierszy w skrypcie lub nocnym pipeline'ie. Wywołanie
lolly <tool> --field=…w pętli to cała integracja. - System lub agent AI, przez MCP. To samo narzędzie obsługiwane programistycznie, z tą samą wiernością i jeszcze większą skalą - bo maszyna się nie znudzi, gdy napływają tysiące plików.
signed by Lollyvector SVGSprawdź samodzielnieGet the signed file348 paths~77k nodes537 groups7 images3100 KB
signed by Lollyvector SVGSprawdź samodzielnieGet the signed file348 paths~77k nodes544 groups7 images3103 KB
Jeden zestaw ograniczeń marki, ustalony raz przez projektanta; trzy drogi do identycznego, wcześniej zaakceptowanego wyniku - a droga maszynowa skaluje się najdalej ze wszystkich, bo nigdy się nie męczy, gdy napływają pliki.
Ogólny obraz: jak dopasowane są warstwy
Wszystko od tego miejsca w dół to architektura. Diagram pokazuje cały system w jednym widoku: narzędzia to dane na górze, silnik pośrodku nie wie nic o żadnej platformie, powłoki poniżej niego implementują jeden kontrakt, a katalogi dostarczają treść.
┌─────────────────────────────────────────────┐
│ Tools (data, not code) │
│ tool.json + template.html + hooks.js? │
└─────────────────────────────────────────────┘
▲
│ talks to via Capability Bridge v1
▼
┌─────────────────────────────────────────────┐
│ Engine │
│ loader · validator · runtime · template │
│ inputs · url-mode │
│ PLATFORM AGNOSTIC. Knows nothing of DOM, │
│ filesystem, or You. │
└─────────────────────────────────────────────┘
▲
│ implements HostV1
▼
┌──────────────┬──────────────┬──────────────┬──────────────┐
│ Web Shell │ Tauri Desktop│ Tauri Mobile │ CLI Shell │
│ (PWA) │ │ │ │
└──────────────┴──────────────┴──────────────┴──────────────┘
▲
│ fetches from
▼
┌─────────────────────────────────────────────┐
│ Catalogs │
│ catalog/tools/index.json + tool dirs │
│ catalog/assets/index.json + asset files │
└─────────────────────────────────────────────┘
Układ repozytorium
Treść jest zamontowana jako pakiety: community/, docs/, każdy shells/, oba services/ oraz brands/suse są osobnymi repozytoriami, wypożyczonymi jako submoduły git tego repozytorium. Repozytorium nadrzędne jest właścicielem engine/, schemas/, scripts/, tests/, api/, brands/lolly-start/ i profiles.json. Zobacz Build Guide » Getting the source, by poznać polecenie checkout i przepływ pracy między repozytoriami.
lolly/
├── engine/ # Platform-agnostic core. Open source (MPL-2.0).
│ └── src/
│ ├── index.ts # public surface - loader, runtime, template, inputs, url-mode
│ ├── loader.ts # fetches and validates tool files
│ ├── runtime.ts # orchestrates the 5-step lifecycle
│ ├── template.ts # Handlebars hydration + annotateTemplate
│ ├── inputs.ts # manifest → runtime input model
│ ├── url-mode.ts # URL ↔ input state round-trip
│ ├── validate.ts # JSON Schema validation of manifests
│ ├── compose.ts # resolve nested tool renders (composes)
│ ├── embed.ts # parse portable lolly.tools embed URLs
│ └── bridge/
│ └── host-v1.ts # type re-export of the @lolly-tools/core contract
│
├── shells/
│ ├── web/ # PWA - hosted online; primary distribution
│ │ └── src/
│ │ ├── main.ts # boot, routing
│ │ ├── theme.ts # theme apply/persist (FOUC prevention)
│ │ ├── bridge/ # web implementations of HostV1 APIs
│ │ │ ├── index.ts # compose all bridge pieces
│ │ │ ├── db.ts # IndexedDB setup
│ │ │ ├── state.ts # host.state - saved edits
│ │ │ ├── profile.ts # host.profile - user details
│ │ │ ├── assets.ts # host.assets - catalog + user uploads
│ │ │ ├── clipboard.ts # host.clipboard
│ │ │ ├── export.ts # host.export - rasterise/serialize
│ │ │ ├── net.ts # host.net - allowlisted fetch
│ │ │ └── media.ts # host.media - live camera frames (onFrame)
│ │ ├── catalog/
│ │ │ └── sync.ts # boot-time catalog sync + offline cache
│ │ ├── styles/ # app-wide CSS (app.css, picker.css, tokens.css)
│ │ └── views/
│ │ ├── gallery.ts # tool library listing + saved-state cards
│ │ ├── tool.ts # mounts one tool (inputs + canvas + actions)
│ │ ├── picker.ts # asset picker UI (invoked by host.assets)
│ │ ├── profile.ts # user details editor
│ │ ├── projects.ts # /p - folders of saved sessions (nested; folder/selection export)
│ │ └── free-canvas.ts # free-canvas editor overlay for render.layout:"editor" tools
│ │
│ ├── cli/ # Node.js CLI - same engine, headless jsdom
│ │ ├── bin/lolly.ts
│ │ └── src/
│ │ ├── run.ts # loadTool → createRuntime → export → write file
│ │ └── bridge.ts # CLI implementation of HostV1
│ │
│ ├── tui/ # Interactive terminal shell (Ink) - reuses the CLI bridge
│ │ └── src/
│ │ ├── main.tsx # full-screen app: Gallery / Projects / Profile / ToolView
│ │ └── bridge.ts # CLI bridge + on-disk state under ~/.lolly
│ │
│ ├── tauri-desktop/ # downloadable desktop app
│ └── tauri-mobile/ # iOS/Android app
│
├── tools/ # profile VIEW (gitignored) - data, not code. Merged from packs:
│ # community/ (public, brand-agnostic, MPL) + brands/<active>/tools (brand-owned).
│ # A SELECTION follows - the mounted set depends on the profile.
│ ├── qr-code/
│ ├── quotes/
│ ├── email-signature/
│ ├── snippet/
│ ├── countdown-timer/
│ ├── color-palette/
│ ├── color-block/ # typed/heterogeneous blocks (addMenu discriminator)
│ ├── dynamic-layout/
│ ├── tool-logo/ # "Logo" - auto-switching brand logo
│ ├── street-map/ # offline vector city-block maps
│ ├── url-shot/ # "URL Screenshot" (capture capability)
│ ├── strip-data/ # on-device metadata strip - JPEG/PNG/SVG/PDF (file in → clean file out)
│ ├── compress-pdf/ # on-device PDF compressor - recompresses images (file in → smaller file out)
│ ├── brand-lockup/ # "Brand Lockup" - SUSE logo lockups; HarfBuzz text-to-path (wasm)
│ ├── chart-creator/ # SVG charts from structured data
│ ├── filter/ # photo effects in one tool - halftone/scanline/posterize/voronoi (vector), duotone/pixel-stretch/imperfections (raster)
│ ├── meeting-planner/ # global timezone meeting scheduler
│ ├── calendar-ics/ # event → .ics calendar file plus a card
│ ├── digi-ad/ # "Animated Ad" - looping banner from scenes
│ ├── event-name-badge/ # conference badges - composes qr-code as an SVG
│ ├── wayfinding-signage/ # event signage; directions blocks auto-fit label text
│ ├── text-helper/ # on-device text workbench (format/decode/hash/de-identify)
│ ├── design/ # "Design" - freeform WYSIWYG editor canvas (render.layout: editor)
│ ├── multi-page-pdf/ # multi-page PDF document - cover, flowing content blocks, back page
│ ├── diagram-builder/ # org / layercake / process / cycle / pyramid diagrams
│ ├── logo-wall/ # many logos → auto-packed grid
│ ├── logo-lockup-partner/ # SUSE + partner co-brand lockup
│ ├── icon/ # favicon .ico / png / svg from text + colours
│ ├── lottie-digi-ad/ # animated Lottie ad banners
│ └── pose-geeko/ # pose the SUSE Geeko mascot - print-ready stills
│
├── catalog/
│ ├── tools/index.json # tool registry
│ └── assets/
│ ├── index.json # asset registry
│ └── suse/... # logo, palette, etc.
│
├── schemas/ # JSON Schema for tool.json, asset entries, AssetRef
├── scripts/ # build-catalog-index.ts, checksum-assets.ts, validate-catalog.ts
├── tests/ # engine tests
└── docs/ # this file + authoring guides + positioning
Model dostarczania platformy
Platforma działa na kilku powierzchniach - web PWA, Tauri desktop/mobile, skryptowalne CLI oraz interaktywne TUI. Wszystkie z nich używają tego samego silnika i tych samych plików narzędzi.
Web (PWA) - główna dystrybucja
Hostowane pod adresem URL kontrolowanym przez SUSE. Działa offline, gdy tylko service worker zapisze w pamięci podręcznej narzędzia i zasoby. To tu większość pracowników, dostawców i partnerów będzie korzystać z platformy. Konto nie jest wymagane - stan jest przechowywany w IndexedDB na każdym urządzeniu.
Powłoka web jest responsywna z jednego układu. Na desktopie narzędzie to zmieniany rozmiarowo pasek boczny z elementami sterującymi obok sceny podglądu z nawigacją po płótnie natywną dla gładzika (Cmd/Ctrl-kółko lub uszczypnięcie, by powiększyć wokół kursora, Space- lub przeciąganie środkowym przyciskiem, by przesuwać, klawisze 0/1/+/− oraz HUD Fit/%). Na urządzeniach mobilnych (≤640px) elementy sterujące zmieniają się w zakotwiczony u góry arkusz z uchwytem do przeciągania, który zatrzaskuje się w pozycji peek/half/full (dotknięcie przełącza) nad statycznym podglądem pełnoekranowym, a pływający przycisk Render otwiera elementy sterujące Export w wyskakującym arkuszu od dołu. Dotyk umożliwia uszczypnięcie do powiększenia i przeciąganie na podglądzie. Ścieżka renderowania i elementy sterujące eksportu są identyczne w obu przypadkach - zmienia się tylko układ interfejsu.
signed by Lollyvector SVGSprawdź samodzielnieGet the signed file5 paths989 nodes11 groups14 KB
signed by Lollyvector SVGSprawdź samodzielnieGet the signed file5 paths989 nodes11 groups14 KB
To samo narzędzie na szerokości telefonu, bez drugiego układu do utrzymywania: kontrolki stają się arkuszem u góry, podgląd zajmuje cały ekran, a pigułka renderowania unosi się nad nim.
signed by Lollyvector SVGSprawdź samodzielnieGet the signed file47 paths~1.9k nodes84 groups1 image212 KB
signed by Lollyvector SVGSprawdź samodzielnieGet the signed file47 paths~1.9k nodes84 groups1 image211 KB
Tryb wsadowy (/pro). Powłoka webowa udostępnia też siatkę wsadową w stylu arkusza kalkulacyjnego (shells/web/src/pro/), która renderuje wiele wierszy naraz w jednym lub wielu narzędziach. Obsługuje odczyt i zapis CSV/TSV oraz wklejanie z arkusza, per-wierszowy szablon/format/rozmiar/jednostkę/dpi, panel boczny edytora bloków z podglądem na żywo, zwijalne kolumny eksportu, pasek tagów "relevance" na wiersz, zmianę kolejności wierszy przez uchwyt przeciągania po lewej, dwuetapowe potwierdzenie usunięcia, zapisane sesje wsadowe i pobieranie w formacie .zip. To jest powierzchnia jeden-do-wielu stojąca za pozycjonowaniem "masowego generowania treści".
Tauri desktop / mobile
Spakowana aplikacja natywna (mały rozmiar dzięki Tauri). Zapewnia pełną dostępność offline, dostęp do systemu plików dla narzędzi zależnych od CLI (PDF Smasher, Font Outliner) i dostęp do kamery. Rozszerzenie narzędzi zaplanowane na połowę 2026.
CLI
lolly <tool-id> [--input=value ...] --output=file.png
Użytkownicy desktopu mogą wywoływać wiele narzędzi z terminala. Powłoka CLI ładuje ten sam silnik, tworzy DOM jsdom, uruchamia tę samą ścieżkę renderowania i zapisuje plik. Tryb URL jest transportem - CLI nie jest osobną implementacją. To gwarantuje, że wyniki CLI i GUI są identyczne.
lolly qr-code --url=https://suse.com --output=qr.svg
lolly quotes --quote="Ship it." --output=quote.png
lolly # lists available tools
lolly qr-code # lists inputs for that tool
TUI
npm run tui
Interaktywny odpowiednik CLI: pełnoekranowa aplikacja terminalowa sterowana klawiaturą (zbudowana na Ink) do przeglądania narzędzi, wypełniania danych wejściowych, zapisywania projektów i eksportowania - wszystko bez GUI. Jej most hosta ponownie wykorzystuje implementację CLI dla formatów bez DOM (SVG/EMF/EPS/HTML + tekst/dane) i dodaje stan na dysku pod ~/.lolly oraz opcjonalny podgląd inline. Poza tym ma warstwę renderowania w przeglądarce: ograniczoną bezgłowe Chromium (to samo, które instaluje serwer MCP), które generuje raster/PDF/wideo i przechwytywanie URL na żądanie - napędzając zbudowaną kopię powłoki webowej, więc wynik jest identyczny, i uruchamiając się dopiero przy pierwszym eksporcie takiego formatu. Dzięki temu url-shot (z przycinaniem + zmianą kolorów + wektorowym PDF/SVG) i każde narzędzie raster/pdf działają też w terminalu. Zobacz przewodnik TUI.
Niezależnie od tego, na jakiej powierzchni jesteś, zakładka Capabilities w panelu jest pełną mapą tego, co platforma deklaruje, że potrafi zrobić, pogrupowaną i czytelną bez otwierania choćby jednego narzędzia.
Kategorie narzędzi
Narzędzia są oznaczane category w manifeście do grupowania w galerii.
Wiersze są wymienione w kolejności sekcji galerii. Sekcja utility zawsze renderuje się jako ostatnia w galerii (po każdej innej kategorii, w tym przyszłych) - to szuflada "Offline Utilities" działająca on-device.
| Kategoria | Przykłady | Planowane |
|---|---|---|
everyone | QR Code Generator, Quote Card, Email Signature, Logo, Wordmark, Audiogram, Battlecards, Sequence Studio, Record | Employee Image Stationery |
designer | Brand Lockup, Design, Chart, Darkroom, Filter, Pose Geeko, Multi-Page PDF | Font Outliner |
event | Meeting Planner, Event Name Badge, Wayfinding Signage, Calendar ICS, Booth Studio | Event Stationery, Bulk Name Badges, Room Agenda Cards |
product | - | CVE Alert, Product Release Announcement, Blog OG Image |
utility | Strip Hidden Data, Text Helper, Compress PDF, Convert Image, Convert Font, Redact, Run Web Code, Screen Capture, URL Screenshot | Konwertery jednostek/formatów, więcej narzędzi prywatności działających na urządzeniu |
Te komórki to przykłady, nie inwentarze. To, jakie narzędzia istnieją, jest właściwością zamontowanego profilu, nie tej strony: pakiet marki dodaje własne i może wykluczyć narzędzie społecznościowe, którego wolałby nie dostarczać. catalog/tools/index.json - wygenerowany z manifestów, rejestr faktycznie odczytywany przez galerię - jest listą autorytatywną; aby policzyć, co montuje profil, policz manifesty (ls community//tool.json brands//tools/*/tool.json) zamiast ufać liczbie zapisanej tutaj. (Id narzędzia obecne w dwóch pakietach montuje się raz, z pakietu, który wygrywa.)
Narzędzia są też klasyfikowane według statusu: official (zatwierdzone przez markę, bez znaku wodnego), community (wkład zewnętrzny), experimental (eksporty ze znakiem wodnym). Większość biblioteki to official; nowsze studia i narzędzia przechwytywania mają zwykle status community lub experimental, dopóki się nie ustabilizują. Każda powierzchnia pokazuje odznakę, więc czytelnik wie, co bierze, zanim to otworzy - i, podobnie jak komórki kategorii powyżej, przynależność per-status zmienia się zbyt szybko, by ją tu wyliczać. Odczytaj ją z galerii lub wygenerowanego indeksu.
Design to pierwsze narzędzie zbudowane na wolnej kanwie render.layout: "editor" - bezchromowej powierzchni bezpośredniej manipulacji, na której przeciągasz, zmieniasz rozmiar, obracasz i przyciągasz boksy tekstu, kształtów i obrazów, a następnie eksportujesz tą samą ścieżką renderowania co każde inne narzędzie.
Strip Hidden Data to pierwsze narzędzie on-device (privacy: "on-device"): narzędzie transformujące treść, które bierze plik dostarczony przez ciebie, przetwarza go całkowicie w przeglądarce i oddaje czystą kopię - nigdy nie przesłaną, nigdy nie oznaczoną znakiem wodnym, bez ostemplowanej proweniencji. Text Helper jest drugie - warsztat on-device do codziennych zadań typu wklej-do-strony (formatowanie JSON, dekodowanie JWT, Base64, kodowanie/dekodowanie URL, haszowanie SHA). Compress PDF jest trzecie - zmniejsza PDF, rekompresując jego obrazy, znów całkowicie on-device. Znacznik i tekst jego odznaki "Runs on your device - nothing is uploaded" obejmują teraz cały zbiór transformacji: Strip Hidden Data, Text Helper, Compress PDF, Convert Image (HEIC/TIFF/AVIF → WebP/JPG/PNG), Convert Font, Redact (niszczenie obszarów obrazu, SVG lub PDF), Prompt to Image i Rebrand a Deck (zmiana motywu .pptx w miejscu), tam gdzie profil je montuje. To kategoria narzędzi prywatności, która zastępuje przekazywanie poufnych plików jednofunkcyjnym stronom.
signed by Lollyvector SVGSprawdź samodzielnieGet the signed file154 paths~40k nodes234 groups802 KB
signed by Lollyvector SVGSprawdź samodzielnieGet the signed file154 paths~40k nodes234 groups803 KB
Uwaga:
categoryistatussą zdenormalizowane docatalog/tools/index.json(rejestru odczytywanego przez galerię) z każdegotool.json. Manifest jest źródłem prawdy - indeks jest generowany przeznpm run build:catalog, anpm run validate:catalogprzerywa CI, jeśli zatwierdzony indeks odbiega od manifestów.
Zobowiązania architektoniczne
Te decyzje są ustalone. Zmiana którejkolwiek z nich to poważne przedsięwzięcie - kształtują każdą inną decyzję w bazie kodu.
1. Deklaratywne narzędzia, z imperatywnym wyjściem awaryjnym
Narzędzie to manifest (tool.json) + szablon (template.html) + opcjonalne hooks.js.
Manifest deklaruje dane wejściowe. Nie szablon. Dane wejściowe nie są wywnioskowane z tokenów Handlebars. Manifest jest umową; szablon konsumuje nazwane zmienne przez {{id}}.
signed by Lollyvector SVGSprawdź samodzielnieGet the signed file39 paths~3.4k nodes70 groups2 images50 KB
signed by Lollyvector SVGSprawdź samodzielnieGet the signed file39 paths~3.4k nodes70 groups2 images50 KB
Hooki są opcjonalne. Większość narzędzi jest czysto deklaratywna - manifest + szablon wystarczą. Narzędzia potrzebujące obliczonych wartości (kodowanie QR, kształtowanie danych wykresu) dostarczają hooks.js eksponujące nazwane funkcje cyklu życia (onInit, onInput, onFrame - hook per-klatkowy kamery na żywo dla narzędzi reagujących na ruch - onLevel, beforeExport, afterExport, exportFile - ścieżka transformacji plik-wejście/plik-wyjście używana przez narzędzia on-device jak Strip Hidden Data - i exportStill, dla narzędzia, które ma własny głęboki raster). Host ładuje hooki przez new Function('host', …) z mostem możliwości wstrzykniętym jako zasięg domknięcia. To jest umowa przenośności, nie piaskownica bezpieczeństwa: hooki wciąż działają w realmie strony i mogą sięgać po window/fetch/document w powłoce przeglądarkowej - host. to wspierana, przenośna powierzchnia, nie wymuszona granica. Wyniki asynchronicznych hooków są ograniczone czasowo (onInit 5s, onInput 2s, beforeExport/afterExport 5s, exportFile/exportStill 10s), a spóźnione wyniki są odrzucane; rozbiegany synchroniczny* hook nie może zostać wywłaszczony. Niezaufany kod hooków stron trzecich nie jest więc bezpieczny do uruchamiania, dopóki nie pojawi się izolacja Worker.
Ma to znaczenie, ponieważ: narzędzia deklaratywne mogą być autorowane przez osoby niebędące programistami. Gdyby każde narzędzie było aplikacją webową, ryzyko "ograniczone umiejętności do tworzenia/utrzymywania szablonów roboczych" stałoby się permanentnym wąskim gardłem.
2. Narzędzia i zasoby to dane, nie spakowany kod
Aplikacje web i Tauri pobierają katalogi narzędzi i zasobów ze znanego URL przy starcie, buforują je lokalnie i działają na tym, co tam jest. Dodanie nowego kafelka wydarzenia lub sezonowego zasobu nie wymaga wydania aplikacji.
Bajty zasobów są sumowane kontrolnie SHA-256, by zapobiec zatruciu CDN. id + version zasobu napędzają unieważnianie pamięci podręcznej.
3. Most Możliwości to jedyne API, jakie widzą narzędzia
Narzędzia nigdy nie dotykają DOM poza obszarem swojego szablonu, nigdy nie wywołują fetch bezpośrednio, nigdy nie odczytują systemu plików. Wywołują wersjonowane metody host.*. Kanoniczną definicją umowy jest packages/core/src/host-v1.ts - SDK dla autorów narzędzi @lolly-tools/core, dzięki czemu strona trzecia może budować na tym bez zależności od silnika; engine/src/bridge/host-v1.ts jest jego reeksportem typu, a kod silnika/powłok nadal importuje z tej samej ścieżki bez zmian:
| API mostu | Co robi |
|---|---|
host.profile | Imię, e-mail, zdjęcie, miasto użytkownika itd. Wstępnie wypełnia dane wejściowe przez bindToProfile. |
host.assets | Zapytania do katalogu, rozwiązywanie zasobów, UI wyboru dostarczane przez hosta. |
host.state | Zapis / odczyt slotów danych wejściowych. IndexedDB na webie, system plików na Tauri, pamięć na CLI. |
host.clipboard | Zapis tekstu lub obrazu do schowka (z fallbackami platformowymi). |
host.export | Rasteryzuje lub serializuje cel renderowania. Nakłada znak wodny dla narzędzi eksperymentalnych. |
host.net | Fetch z listy dozwolonych - dostępny tylko jeśli narzędzie zadeklarowało możliwość "network". (Żadne dostarczane narzędzie obecnie tego nie używa.) |
Opcjonalne, addytywne powierzchnie pojawiają się tylko wtedy, gdy dostarcza je powłoka. Niektóre są bramkowane możliwościami - eksponowane tylko wtedy, gdy narzędzie zadeklaruje pasującą flagę: host.compose (osadzenie renderu innego narzędzia - compose), host.capture (przechwytywanie strony dla URL Screenshot - capture) i host.recorder (przechwytywanie mikrofonu/kamery/ekranu dla narzędzi nagrywających - microphone / camera / screen). Reszta jest wykrywana funkcjonalnie - obecna zawsze, gdy powłoka może ją dostarczyć, przy czym narzędzie zachowuje fallback dla powłok, które nie mogą.
Garść flagowych powierzchni, by pokazać zakres - Host API dokumentuje każdą z nich, a packages/core/src/host-v1.ts jest samą umową:
| Interfejs | Od wersji | Co dodaje |
|---|---|---|
host.tokens | 1.0 | Tokeny projektowe DTCG - własne prymitywy marki |
host.text | 1.0 | Zamiana tekstu na ścieżki przez HarfBuzz WASM (flaga możliwości wasm oznacza narzędzia, które z tego korzystają) |
host.media | 1.4 | Klatki z kamery na żywo napędzające hook onFrame. Stopniowe udoskonalenie, celowo nie uzależnione od flagi camera - takie narzędzie nadal działa jako zwykłe narzędzie do nieruchomych obrazów |
host.color | 1.40 | Percepcyjna matematyka koloru: ΔEOK, kontrast WCAG + APCA, rampy OKLab, podziały na klasy, palety kategoryczne, schematy harmonii (1.60), mieszanie CSS Color 4 i wypalanie gradientów (1.68). Czyste i synchroniczne - powłoki dołączają makeColorApi() silnika zamiast czegokolwiek implementować, więc nie może dojść do rozjazdu |
host.images | 1.60 | Dekodowanie / zmiana rozmiaru / ponowne kodowanie bajtów na urządzeniu - ścieżka konwersji (HEIC → JPEG, kompresja do WebP, pomniejszanie). Dostarczane w powłoce webowej jako leniwa fasada, więc dekoder HEIC nigdy nie trafia do fragmentu startowego |
host.geom | 1.64 | Dokładna geometria wektorowa: operacje logiczne na ścieżkach, offsetowanie, zamiana obrysu na wypełnienie, obniżanie splajnów, uproszczanie, wykrywanie trafień. Także czyste, synchroniczne i dołączane z silnika (makeGeomApi()); błędy są zwracane, nigdy nie rzucane |
Reszta stosuje się do tych samych zasad i jest dokumentowana obok nich: pdf (1.8) i pptx (1.58) do chirurgii dokumentów on-device, audio (1.71) i speech (1.96) do analizy klipów i TTS/transkrypcji on-device, viz (1.72) do umowy zastępczej MilkDrop, codec (1.100) i layers (1.102) do wyjścia głębokich bitów i warstwowej mapy bitowej, upscale (1.101) i matte (1.103) do modeli on-device, raster (1.105) dla hooków wykonujących własną pracę na pikselach, connectors (1.106) dla strzałek bezpiecznych przy eksporcie i c2pa (1.85) do podpisywania gotowych bajtów. Liczba rośnie; zasady nie.
Deklarowalne możliwości to: network, filesystem, clipboard, camera, microphone, screen, ffmpeg, wasm, capture, compose. (screen, dodana w 1.54, to przechwytywanie ekranu przez host.recorder - użytkownik wybiera ekran/okno/kartę w natywnym UI przeglądarki; różni się od capture, które rasteryzuje URL nazwany przez samo narzędzie.)
To samo narzędzie działa w przeglądarce, Tauri i bezgłowym CLI, ponieważ każda powłoka implementuje ten interfejs - narzędzie nigdy nie wie, w której jest.
Most jest wersjonowany. Dodanie metod to wersja pomniejsza. Usunięcie lub zmiana sygnatur to skok wersji głównej. Gdy wyjdzie v2, v1 musi nadal działać.
4. Id zasobów są wieczne
suse/logo/primary to umowa. Po opublikowaniu:
- Id nigdy się nie zmienia, nigdy nie jest ponownie używane.
- Zmiana bajtów → podbij
versionw manifeście. - Zastąpione nowym zasobem → ustaw
deprecated: truei opcjonalniereplacedBy. - Istniejące odwołania zawsze się rozwiązują.
To sprawia, że zapisane stany narzędzi i linki dzielone przez URL są trwałe przez lata.
5. Tryb URL jest pierwszorzędny
Każde dane wejściowe muszą dać się wyrazić jako parametr URL:
lolly.tools/#/tool/qr-code?url=https://suse.com&ecl=H
signed by Lollyvector SVGSprawdź samodzielnieGet the signed file17 paths~2.0k nodes39 groups24 KB
signed by Lollyvector SVGSprawdź samodzielnieGet the signed file17 paths~2.0k nodes39 groups24 KB
Tryb CLI to tryb URL pod innym transportem - powłoka CLI buduje obiekt stanu URL z argv i uruchamia ten sam potok silnika. Istnieje jedna ścieżka renderowania. CLI nie może dryfować od GUI, bo nie jest osobną implementacją.
url-mode.ts obsługuje przejazd tam i z powrotem (parsowanie i serializację). Zbiór zarezerwowanych parametrów nigdy nie jest przekazywany do narzędzia jako dane wejściowe: kontrolki wyjścia (format, export, copy, filename, width/w, height/h, unit, dpi), pokrętła druku i proweniencji (bleed, marks, profile, password, c2pa, imprint, durable, meta, hdr, depth, cuts) i nośniki stanu (template, z - spakowany token "Shortest link" - oraz zx, ten sam zaszyfrowany hasłem). Zbiór RESERVED w engine/src/url-mode.ts jest autorytetem i jest przypięty testem; Tryb URL dokumentuje każdy z nich, w tym garść niewymienionych tutaj. Dane wejściowe zasobów w trybie URL są serializowane przez ich id; runtime rozwiązuje je przez host.assets.get() przed hydratacją. width/height to wartości w unit (domyślnie px, także mm/cm/in/pt/pc); przy jednostce fizycznej dpi ustawia rozdzielczość rastra. Ustawiają rozmiar dokumentu kanwy i wstępnie wypełniają panel wymiarów eksportu.
Ponieważ każde dane wejściowe podróżują w linku, zmiana parametru to inny gotowy zasób. Cała ta paleta to jeden kolor bazowy, harmonia i liczba kroków:
signed by Lollyvector SVGSprawdź samodzielnieGet the signed file10 groups24 KB
signed by Lollyvector SVGSprawdź samodzielnieGet the signed file10 groups24 KB
6. Przechowywanie danych odbywa się przez mostek, nie bezpośrednio
Web shell: IndexedDB. Tauri: system plików. CLI: pamięć tymczasowa. Narzędzia widzą tylko host.state.save(slot, data) i host.state.load(slot). localStorage nie jest używany - jest zbyt mały i nie może przechowywać blobów.
Użytkownicy mogą zapisać wiele nazwanych slotów edycji dla każdego narzędzia i wrócić do każdej sesji później. Nie jest wymagane zakładanie konta; stan jest przechowywany lokalnie na urządzeniu. Ponieważ mostek jest jedynym punktem styku, ten lokalny stan jest też przenośny: shells/web/src/data-transfer.ts odczytuje wszystko z powrotem przez host.profile/host.state/host.assets do jednego pliku zip lolly-backup, który można zaimportować w dowolnej innej instalacji - offline'owa odpowiedź na "przeniesienie na nowe urządzenie", niewymagająca serwera (pełna specyfikacja: docs/data-transfer.md). Integracja z SUSE ID (synchronizacja wielourządzeniowa) to przyszły etap budowany na tej podstawie.
7. Znaczniki dojrzałości z założenia odpowiadają na ryzyko "zatwierdzenia przez markę"
Każde narzędzie deklaruje status: official | community | experimental w swoim manifeście. Galeria sortuje według statusu. Narzędzia eksperymentalne automatycznie znakują swoje eksporty znakiem wodnym - znak wodny jest nakładany przez host.export.render, a nie przez narzędzie, więc autor narzędzia niebędącego oficjalnym nie może z niego zrezygnować.
To strukturalna odpowiedź na ryzyko odbioru, że użycie dowolnego narzędzia sugeruje zatwierdzenie przez markę. Odpowiedzi procesowe (kolejka recenzji, bramkowanie przez SUSE ID) nakładają się na to dodatkowo.
8. Dane wejściowe narzędzia są typowane poprzez manifest, w tym zasoby
Dane wejściowe deklarują type: text, longtext, number, boolean, color, select, asset, date, time, datetime-local, url, blocks, vector, table i file. Host renderuje generyczną kontrolkę dla każdego typu na podstawie manifestu - narzędzia nie piszą ani jednej linii kodu kontrolek. (Wstępne wypełnianie z profilu użytkownika nie jest typem - każde pole wejściowe może mieć bindToProfile.) Trzy z nich mają większe znaczenie niż pozostałe:
asset(zfilteriallowUpload) to mostek do globalnego systemu zasobów;allowUpload: falseto dźwignia egzekwowania marki dla rzeczy takich jak logotypy w kafelkach sponsorskich, gdzie dozwolone są tylko zasoby z biblioteki. Przesłane przez użytkownika pliki mają tę samą strukturęAssetRefco zasoby biblioteczne, więc narzędzia obsługują je identycznie.blocksto powtarzalna grupa pól - mini-tabela wewnątrz jednego pola wejściowego, edytowana w panelu bocznym, z typowanym/rozróżnianym menu dodawania i polami zasobów dla każdego bloku. Kliknięcie wyrenderowanego bloku na canvasie ustawia fokus na wierszu tego bloku. Używane przezmeeting-planner,chart-creator,event-name-badge,wayfinding-signage,color-blockidigi-ad.vectorgrupuje ustalony zestaw liczb (np. transformację) w jedną złożoną kontrolkę;fileprzechowuje własny plik użytkownika jako bajty w pamięci dla narzędzi transformujących na urządzeniu (np.strip-dataicompress-pdf).
9. Szablony są bezlogikowe (Handlebars, nie EJS)
Handlebars został wybrany zamiast EJS celowo:
- Bezlogikowy. Szablony mogą tworzyć osoby niebędące programistami.
- Bezpieczny domyślnie.
{{x}}koduje HTML;{{{x}}}to opcjonalny surowy tryb. - Brak dowolnego JS w szablonach oznacza brak powierzchni audytu XSS dla każdego szablonu.
Logika żyje w hooks.js, gdzie jest jawna i możliwa do zrecenzowania. Dostępne helpery Handlebars: {{default}}, {{upper}}, {{lower}}, {{eq}}, {{markdown}}, {{asset ref}}, {{asset ref "property"}} (a także helpery formatowania danych icsStamp/rfcText/csvCell używane przez towarzyszące szablony .ics/.vcf/.csv).
10. Narzędzia komponują narzędzia
Narzędzie może osadzić render innego narzędzia bez importów między narzędziami - kompozycja jest rozwiązywana przez silnik, nigdy przez kod narzędzia. Istnieją dwie powierzchnie:
- Deklaratywny manifest -
composes: [{ id, tool, inputs, format?, width?, height? }]. Silnik renderuje nazwane dziecko i umieszcza wynik w bezlogikowym szablonie jako{{asset <id>}}.event-name-badgekomponuje dziśqr-codejako SVG. - Przenośny adres URL osadzenia -
<img src="https://lolly.tools/tool/<id>.<ext>?<inputs>">. Powłoka renderuje to dziecko lokalnie (do czasu rozwiązania lokalnego renderu widoczny jest piksel zastępczy); nic nigdy nie jest pobierane zlolly.tools.
Można komponować render dowolnego narzędzia: dziecko w formacie SVG pozostaje prawdziwym wektorem, gdy rodzic eksportuje do SVG lub PDF, i rasteryzuje się ostro dla PNG; dzieci PNG/JPG/WEBP osadzają się jako obrazy. Wymaga możliwości compose. Skomponowane dzieci są elementami pośrednimi - nigdy nie są znakowane wodnie ani stemplowane pochodzeniem - a kompozycja degraduje się łagodnie: powłoka, która nie potrafi wyrenderować dziecka, po prostu pomija to miejsce, a rodzic i tak się renderuje.
Czego celowo nie zrobiliśmy
- Brak EJS / brak dowolnego JS w szablonach. Powierzchnia ataku XSS wynosi zero. Logika mieszka w
hooks.js. - Brak obowiązkowego CMS-a zasobów. Poszczególne osoby wprowadzają własne pliki kreatywne prosto do swojego katalogu w aplikacji (widok Katalog oraz Brand Studio) - bez serwera, bez konsoli administracyjnej. Praca jest przekazywana dalej jako sesja: link udostępniający niesie cały stan, a ta sama sesja podróżuje w kopii zapasowej lub przez sesję współpracy. Kto kontroluje wdrożenie, może następnie zablokować udostępnioną sesję jako szablon - otworzyć link, zapisać jego wartości jako wpis szablonu w katalogu tego narzędzia w paczce marki i zatwierdzić commitem - po czym pojawia się on w selektorze narzędzia "New from template" i jest dostępny przez głęboki link jako
?template=<id>. Git jest krokiem blokującym po stronie właściciela wdrożenia, nigdy twórcy. Dla katalogu współdzielonego i zarządzanego organizacja może zarządzać katalogiem zasobów w ten sam sposób i bramkować aktualizacje przez przegląd PR - to dostępny model zarządzania, a nie wymóg aplikacji. - Brak wymuszonego RBAC. Otwarta aplikacja jest domyślnie publicznie dostępna; ryzyko dla marki zarządzane jest przez znaczniki dojrzałości i znaki wodne. Organizacja, która chce ściślejszej kontroli, dokłada własne uwierzytelnianie oraz katalog recenzowany przez git opisany wyżej.
- Brak centralnej bazy danych. Cały stan użytkownika jest przypisany do urządzenia. Integracja z SUSE ID jest w planach, ale nie blokuje startu.
- Brak wspólnej ścieżki kodu narzędzi/silnika. Silnik jest open source, podobnie jak narzędzia niezależne od marki w
community/; paczka marki, taka jak prywatnabrands/suse/, niesie własne narzędzia i katalog na własnych warunkach. Tak czy inaczej rozdzielenie jest egzekwowane (brak importów krzyżowych zengine/do treści narzędzi), więc podział pozostaje czysty.
Cykl życia od początku do końca
Użytkownik otwiera lolly.tools/#/tool/qr-code?url=https://suse.com&ecl=H:
- Uruchomienie. Powłoka webowa otwiera IndexedDB, buduje mostek możliwości, synchronizuje katalogi narzędzi i zasobów (lub wczytuje z pamięci podręcznej offline).
- Routing. Fragment URL → widok
tool, z wyodrębnionymiqr-codei parametrami URL. - Wczytanie.
loadTool('qr-code', fetchFile)pobieratool.json, waliduje go względem schematu JSON, pobieratemplate.html,styles.cssi kod źródłowyhooks.js. - Parsowanie stanu URL.
parseUrlStatetłumaczy parametry URL na początkowe wartości pól wejściowych. Referencje zasobów (?logo=suse/logo/primary) są parsowane jako lekkie obiekty{ id, _unresolved: true }. - Środowisko wykonawcze.
createRuntime(tool, host, initialValues)buduje model danych wejściowych (łącząc dane profilu, wartości domyślne i wartości początkowe), rozwiązuje referencje zasobów przezhost.assets.get(), wczytuje hooki (hostw zasięgu domknięcia, bez piaskownicy), wywołujehooks.onInit. - Renderowanie. Powłoka subskrybuje środowisko wykonawcze; przy każdej zmianie stanu otrzymuje
{ model, hydrated }. Renderuje kontrolki wejściowe na podstawie modelu i zapisuje uwodnioną treść HTML szablonu do#tool-canvas. - Interakcja. Użytkownik wpisuje w pole wejściowe →
runtime.setInput(id, value)→ zastosowanie ograniczeń → wywołaniehooks.onInput→ ponowne uwodnienie → ponowne renderowanie. Canvas aktualizuje się na żywo. - Eksport. Użytkownik klika Download(PNG) →
runtime.export(canvasNode, 'png')→host.export.render(rasteryzuje przez dom-to-image-more; SVG/PDF przechodzą przez dedykowane wektoryzatory przechodzące drzewo DOM) → blob →host.export.download. Zakres formatów, na które narzędzie może się zdecydować, jest szeroki, a wyliczenierender.formatswschemas/tool.schema.jsonjest tu autorytatywnym źródłem - rastry i rastry zmiennoprzecinkowe, wektory i pliki do wycinania, druk/CMYK, ruch, edytowalne dokumenty (pptx,docx,odt), palety oraz dane/wyjścia tekstowe, pliki audio i fontów. Tryb URL wymienia każdy identyfikator i to, co produkuje. Audio jest w tym wyliczeniu tak jak wszystko inne (wav,mp3,m4a,opus, deklarowane przez audiogram i narzędzia nagrywające); niezależnie od tego trybrender.capturenarzędzia nagrywającego sterujehost.recorder, którego nagranie przychodzi jako gotowy Blob w dowolnym kontenerze, w jakim nagrała je przeglądarka. (Narzędzia, które ustawiająrender.export: false- np. Color Palette, Countdown Timer, Strip Hidden Data, Text Helper, Compress PDF - ukrywają kontrolki pobierania/formatu/wymiarów.) Jednostki fizyczne są tu konwertowane dla każdego formatu (PDF → prawdziwe punkty strony, raster → piksele przy DPI z fragmentempHYs). Metadane autorstwa/pochodzenia (autor, narzędzie, źródło - budowane przezengine/src/metadata.ts) są osadzane dla każdego formatu: PNG iTXt, JPEG EXIF, słownik informacyjny PDF, SVG<metadata>, komentarz GIF. Narzędzia eksperymentalne otrzymują znak wodny wstawiany przez host, nie przez narzędzie.
signed by Lollyvector SVGSprawdź samodzielnieGet the signed file49 paths~3.3k nodes61 groups3 images74 KB
signed by Lollyvector SVGSprawdź samodzielnieGet the signed file49 paths~3.3k nodes61 groups3 images74 KB
Ten sam cykl życia w Tauri. Ten sam cykl życia w CLI - jsdom dostarcza bezgłowy DOM; wynik trafia do pliku lub na stdout.
Status open source
Kod jest na licencji MPL-2.0. engine/, shells/, services/, schemas/ i docs/ są open source na licencji MPL-2.0 - neutralna wobec dostawców platforma szkieletowa dla narzędzi marki, z każdą jednostką wydawniczą we własnym repozytorium pod github.com/lolly-tools.
Treść narzędzi jest dostarczana jako paczki marki, każda na własnych warunkach (zobacz NOTICE.md danej paczki). community/ to publiczne repozytorium lolly-tools, a jego narzędzia niezależne od marki także są na licencji MPL-2.0. brands/suse/ to prywatna paczka suse-lolly: narzędzia SUSE i katalog SUSE, własność SUSE, w tym licencjonowana muzyka PremiumBeat. brands/lolly-start/ to pusta marka startowa, której właścicielem jest to repozytorium. Czcionki są dostarczane wewnątrz paczki na licencji SIL Open Font License 1.1 - paczka SUSE niesie kroje SUSE i SUSE Mono.
tools/ i catalog/ w katalogu głównym repozytorium to ignorowane przez git widoki: profil składa je z community/ oraz aktywnej paczki marki, dlatego każdy skrypt i każda powłoka odczytują te dwie ścieżki, nigdy paczkę bezpośrednio.
Podział jest egzekwowany - nie ma importów krzyżowych z engine/ do treści narzędzi - dzięki czemu granica między platformą a treścią pozostaje czysta.
Gdzie kończy się silnik, a zaczyna host
Jeśli da się to opisać w czystych danych + Handlebars → silnik. Jeśli dotyka DOM, systemu plików, sieci lub dowolnego API przeglądarki/systemu operacyjnego → host.
Ta granica jest celowo ostra. Silnik to część open source. Wszystko, co wie o SUSE, konkretnych platformach czy środowiskach uruchomieniowych, pozostaje poza nim.
Kolejny poziom szczegółów: engine/README.md wymienia każdy moduł silnika i za co odpowiada, a Model zagrożeń i granice zaufania opisuje, gdzie ta sama granica jest jednocześnie granicą zaufania.