Ten dokument opisuje cel, strukturę i decyzje architektoniczne platformy Lolly. Odzwierciedla zarówno wizję produktu, jak i obecny stan kodu.
Status: Lolly zostało wydane. Wersja 1.0 ukazała się jako open source na licencji MPL-2.0 30 sierpnia 2026, a funkcje, ustawienia domyślne i katalog narzędzi nadal zmieniają się między wydaniami. Silnik jest deterministyczny, z jedną ścieżką renderowania za każdą powłoką. Jego bezpieczeństwo nie przeszło jeszcze niezależnego audytu, a dowody wdrożenia mają kilka miesięcy. Zobacz Adoption & Governance, by poznać bieżący stan i sposób mierzenia wdrożenia.
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
Powtarzalna praca kreatywna jest zbyt przewidywalna, by za każdym razem angażować wykwalifikowane ręce, i zbyt wrażliwa na jakość, by oddać ją bez zabezpieczeń. Pozostawiona samej sobie, przybiera jedną z trzech postaci: staje się powolna, niespójna lub zamknięta w szablonach dostawcy.
Ta platforma jest bezpośrednią odpowiedzią:
Programistyczna kreacja i treści na skalę - zasoby generowane z danych wejściowych, z regułami ustalonymi raz, dla każdego, kto ich potrzebuje.
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 dzięki narzędziom, które już niosą w sobie te reguły. 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 staje się wieloma wynikami, 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
Lolly includes lolly.work, the same project's separately deployed organisation service. Local creation needs no account; shared work and server rendering use the configured instance. Competitor scores: August 2026. Lolly coverage: 28 September 2026.
| Capability | Lolly+ lolly.work | 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: version 1.0 public since 30 August 2026 under MPL-2.0, and SUSE runs it as an internal deployment; no usage data is shared yet and there are no public case studies yet. 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 and CLI, plus lolly.work's recoverable server jobs and batches with retries, cancellation and retained outputs. 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: standalone creation works offline once its assets are available; lolly.work's organisation services need a reachable instance, which can run on an internal network. 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: local rendering and conversion in-browser or CLI need no upload. Choosing lolly.work's shared storage, work collabs or server rendering sends the relevant data to the configured instance. 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: templates fix layout rules and expose permitted inputs. lolly.work adds group access, input policies, shared catalogues, approvals and audit records. Copy and usage rights can still need review. 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: optional on-device signing without an account, plus lolly.work server signing with a configured organisation identity. A verifier must trust the signer's root to show a trusted identity. Version 1.0 is public and SUSE runs it internally, but no usage data is shared yet, so 75. Penpot: 50 via the official Lolly Export plugin - the same on-device engine signing Lolly uses, opt-in, as in Lolly (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 and URL mode, plus lolly.work's authenticated render API, recoverable batches and governed delivery. One engine across the local and server paths. 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)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: direct two-device private collabs without an account, plus authenticated work collabs through lolly.work with shared edits, cursors and saved team sessions. Partial reflects the current single-node work deployment and limited operating history. Private collabs work without internet on a shared network; work collabs need the organisation's instance. 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 using an existing tool, or publish a tool from Design through Share with rules. lolly.work manages access and input policy for the team. 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 and lolly.work: MPL-2.0 open source in separate repositories, both self-hostable. lolly.work provides the organisation services as part of the project. The current 75 reflects the young project and limited deployment history. Everything else is proprietary SaaS or proprietary desktop. |
75 | 100 | 0 | 0 | 0 | 0 | 0 | 0 |
Cost at production scaleLolly + lolly.work and Penpot: no per-seat software licence charge for the open-source self-hosted path; hardware, storage and operations remain costs. 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 + lolly.work: US$0 in software licence charges for self-hosting. The figure excludes devices, organisation hosting, storage, support and administration; these need a separate budget. Standalone Lolly does not need the organisation service. 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.htmlHTMLpixels, not shapes40 KBAI generatedgenerated by GPT-6Sprawdź samodzielniePobierz podpisany plikLuka 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 SVG367 paths~62k nodes773 groups3 images1453 KBSprawdź samodzielniePobierz podpisany plik
signed by Lollyvector SVG367 paths~62k nodes776 groups3 images1454 KBSprawdź samodzielniePobierz podpisany plik
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 SVG15 paths~1.3k nodes4 groups20 KBSprawdź samodzielniePobierz podpisany plik
signed by Lollyvector SVG15 paths~1.3k nodes4 groups20 KBSprawdź samodzielniePobierz podpisany plik
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.
Jedno narzędzie, wiele wyników
Reguły marki znajdują się w narzędziu, a nie w każdym pliku, który ono tworzy (zobacz Jak Lolly wypada na tle innych). Ustaw narzędzie poprawnie raz, a każdy wynik dziedziczy ten sam krój, kolor i odstępy, niezależnie od tego, czy to jedna karta, czy arkusz kalkulacyjny z wierszami w kilkunastu językach. To, jak sprawdzasz swoją pracę i kto to robi, pozostaje twoją sprawą; Lolly sprawia, że rzecz warta sprawdzenia jest mniejsza, a wynik szybszy do wykonania.
To samo deterministyczne narzędzie osiąga tę skalę na trzy sposoby, z których każdy daje identyczny 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 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 każdego wiersza 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ą, dla tylu wierszy, ile ma zadanie.
signed by Lollyvector SVG133 paths~15k nodes185 groups1 image195 KBSprawdź samodzielniePobierz podpisany plik
signed by Lollyvector SVG133 paths~15k nodes185 groups1 image195 KBSprawdź samodzielniePobierz podpisany plik
Jeden zestaw ograniczeń marki, ustalony raz przez projektanta; trzy drogi do identycznego wyniku.
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
Lolly to jedno repozytorium. engine/, schemas/, scripts/, tests/, api/, docs/, community/, brands/lolly-start/, każdy shells/ oraz oba services/ to zwykłe katalogi w tym repozytorium. Jedynym wyjątkiem jest brands/suse, prywatny submoduł git zawierający pakiet narzędzi SUSE i katalog SUSE, opcjonalny i nieobecny w publicznym klonie. To, które pakiety odczytuje dana kompilacja, określa profil treści (profiles.json), rozwiązywany dla każdego procesu, a nie przełączany globalnie. Zobacz Build Guide » Getting the source, aby poznać polecenie klonowania i sposób zatwierdzania zmian wewnątrz prywatnego pakietu.
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
│
├── community/ # the brand-agnostic tool pack - data, not code. Public (MPL-2.0).
│ # A SELECTION follows; a profile mounts these plus whatever
│ # tools the active brand pack carries of its own.
│ ├── qr-code/
│ ├── snippet/
│ ├── countdown-timer/
│ ├── color-palette/
│ ├── 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)
│ ├── chart/ # 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
│ ├── 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
│ ├── icon/ # favicon .ico / png / svg from text + colours
│ └── lottie-digi-ad/ # animated Lottie ad banners
│
├── brands/ # brand packs - a catalog each, and optionally tools of their own
│ ├── lolly-start/ # the blank starter brand, owned here
│ │ └── catalog/
│ │ ├── tools/index.json # tool registry, generated per brand
│ │ └── assets/
│ │ ├── index.json # asset registry
│ │ └── lolly/... # logo, palette, tokens
│ └── suse/ # PRIVATE submodule - the SUSE tools and the SUSE catalog
│
├── 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 + positioningModel 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 SVG131 paths~6.1k nodes158 groups1 image142 KBSprawdź samodzielniePobierz podpisany plik
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 SVG97 paths~3.3k nodes113 groups99 KBSprawdź samodzielniePobierz podpisany plik
signed by Lollyvector SVG97 paths~3.3k nodes113 groups100 KBSprawdź samodzielniePobierz podpisany plik
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 toolTUI
pnpm 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, Record | Employee Image Stationery |
designer | Brand Lockup, Design, Chart, Darkroom, Filter, Pose Geeko, Booklet | 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, Compress PDF, Convert Image, Convert Font, Redact, Run Web Code, Screen Capture, URL Screenshot | Unit/format converters, more on-device privacy utilities |
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 działające na urządzeniu (privacy: "on-device"): narzędzie do przekształcania treści, które przyjmuje plik dostarczony przez Ciebie, przetwarza go w całości w przeglądarce i zwraca czystą kopię - nigdy nieprzesyłaną na serwer, nigdy nieznakowaną znakiem wodnym, bez osadzonych metadanych pochodzenia. Text to drugie takie narzędzie - warsztat działający na urządzeniu do codziennych zadań typu wklej-na-stronę (formatowanie JSON, dekodowanie JWT, Base64, kodowanie/dekodowanie URL, haszowanie SHA). Compress PDF to trzecie - zmniejsza plik PDF poprzez ponowną kompresję jego obrazów, również w całości na urządzeniu. Znacznik i tekst jego odznaki "Działa na Twoim urządzeniu - nic nie jest przesyłane" obejmują teraz cały zestaw narzędzi transformujących: Strip Hidden Data, Text, Compress PDF, Convert Image (HEIC/TIFF/AVIF → WebP/JPG/PNG), Convert Font, Redact (niszczenie fragmentów obrazu, SVG lub PDF), Prompt Card i Rebrand (zmiana motywu pliku .pptx w miejscu), tam gdzie profil je montuje. To kategoria narzędzi prywatności, która zastępuje przekazywanie poufnych plików jednofunkcyjnym witrynom.
signed by Lollyvector SVG124 paths~29k nodes324 groups395 KBSprawdź samodzielniePobierz podpisany plik
signed by Lollyvector SVG124 paths~29k nodes324 groups396 KBSprawdź samodzielniePobierz podpisany plik
Uwaga:
categoryistatussą zdenormalizowane docatalog/tools/index.json(rejestru odczytywanego przez galerię) na podstawie każdegotool.json. Manifest jest źródłem prawdy - indeks jest generowany przezpnpm run build:catalog, apnpm run validate:catalogkończy się błędem w 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 SVG39 paths~2.6k nodes54 groups2 images43 KBSprawdź samodzielniePobierz podpisany plik
signed by Lollyvector SVG39 paths~2.6k nodes54 groups2 images43 KBSprawdź samodzielniePobierz podpisany plik
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 SVG55 paths~2.6k nodes38 groups60 KBSprawdź samodzielniePobierz podpisany plik
signed by Lollyvector SVG55 paths~2.6k nodes38 groups61 KBSprawdź samodzielniePobierz podpisany plik
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 SVG10 groups25 KBSprawdź samodzielniePobierz podpisany plik
signed by Lollyvector SVG10 groups25 KBSprawdź samodzielniePobierz podpisany plik
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 importuje się na dowolnej innej instalacji - offline'owa odpowiedź na "przeniesienie na nowe urządzenie", niewymagająca serwera (pełna specyfikacja: docs/data-transfer.md). Synchronizacja wielourządzeniowa działa już na tej podstawie, wysyłając tę samą paczkę do pamięci wybranej przez użytkownika (docs/sync.md).
7. Znaczniki dojrzałości mówią, czym jest narzędzie
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 każde narzędzie w galerii waży tyle samo. Jakikolwiek proces zespół nałoży na katalog, nakłada się on na to rozwiązanie.
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 Zasobów w aplikacji (Zasoby oraz Brand Studio) - bez serwera, bez konsoli administracyjnej. Praca jest przekazywana dalej jako sesja: link udostępniający niesie jej dane wejściowe i ustawienia (przesłane pliki podróżują w pliku
.lolly), 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; opcjonalna synchronizacja kopiuje go do pamięci wybranej przez użytkownika, nigdy do bazy danych Lolly.
- Brak współdzielonej ścieżki kodu narzędzi i silnika. Silnik jest open source, tak samo jak niezależne od marki narzędzia 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), dzięki czemu podział pozostaje czysty.
Cykl życia jednego renderu
Użytkownik otwiera lolly.tools/#/tool/qr-code?url=https://suse.com&ecl=H:
- Uruchomienie (Boot). Powłoka webowa otwiera IndexedDB, tworzy most możliwości (capability bridge), synchronizuje katalogi narzędzi i zasobów (lub wczytuje je z pamięci podręcznej w trybie offline).
- Routing. Hash URL → widok
tool, z wyodrębnionymiqr-codei parametrami URL. - Wczytywanie.
loadTool('qr-code', fetchFile)pobieratool.json, waliduje go względem schematu JSON, pobieratemplate.html,styles.cssi kod źródłowyhooks.js. - Parsowanie stanu URL.
parseUrlStateprzekształca parametry URL w początkowe wartości wejściowe. Odniesienia do zasobów (?logo=suse/logo/primary) są parsowane jako lekkie obiekty{ id, _unresolved: true }. - Runtime.
createRuntime(tool, host, initialValues)buduje model wejść (łącząc dane profilu, wartości domyślne i wartości początkowe), rozwiązuje odniesienia do zasobów przezhost.assets.get(), wczytuje hooki (hostw zasięgu domknięcia, bez piaskownicy), wywołujehooks.onInit. - Renderowanie. Powłoka subskrybuje runtime; przy każdej zmianie stanu otrzymuje
{ model, hydrated }. Renderuje kontrolki wejściowe na podstawie modelu i zapisuje uwodniony HTML szablonu do#tool-canvas. - Interakcja. Użytkownik wpisuje coś w polu wejściowym →
runtime.setInput(id, value)→ zastosowanie ograniczeń → wywołaniehooks.onInput→ ponowne uwodnienie → ponowne renderowanie. Płótno aktualizuje się na żywo. - Eksport. Użytkownik klika Pobierz (PNG) →
runtime.export(canvasNode, 'png')→host.export.render(rasteryzacja 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 może zdecydować się narzędzie, jest szeroki, a wyliczenierender.formatswschemas/tool.schema.jsonjest tu autorytetem - rastry i rastry zmiennoprzecinkowe, wektory i pliki do wycinania, druk/CMYK, ruch, dokumenty edytowalne (pptx,docx,odt), palety oraz dane/wyjścia tekstowe, pliki audio i czcionek. URL Mode wymienia każdy identyfikator i to, co produkuje. Audio znajduje się w tym wyliczeniu jak wszystko inne (wav,mp3,m4a,opus, deklarowane przez audiogram i narzędzia nagrywające); osobno, trybrender.capturenarzędzia nagrywającego sterujehost.recorder, którego nagranie trafia jako gotowy Blob w dowolnym kontenerze nagranym przez przeglądarkę. (Narzędzia ustawiającerender.export: false- np. Color Palette, Countdown Timer, Strip Hidden Data, Text, Compress PDF - ukrywają kontrolki pobierania, formatu i wymiarów.) Jednostki fizyczne są tu konwertowane osobno dla każdego formatu (PDF → rzeczywiste punkty strony, raster → piksele przy określonym DPI z fragmentempHYs). Metadane autorstwa/pochodzenia (autor, narzędzie, źródło - budowane przezengine/src/metadata.ts) są osadzane w zależności od formatu: PNG iTXt, JPEG EXIF, słownik informacyjny PDF,<metadata>w SVG, komentarz GIF. Narzędzia eksperymentalne otrzymują znak wodny wstawiany przez hosta, nie przez samo narzędzie.
signed by Lollyvector SVG77 paths~6.0k nodes87 groups3 images88 KBSprawdź samodzielniePobierz podpisany plik
signed by Lollyvector SVG77 paths~6.0k nodes87 groups3 images88 KBSprawdź samodzielniePobierz podpisany plik
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/*.ts są open source na licencji MPL-2.0 - neutralna wobec dostawców platforma szkieletowa dla narzędzi marki, cała w jednym publicznym repozytorium, lolly-tools/lolly.
Treść narzędzi jest dostarczana jako pakiety marki (brand packs), każdy z własnymi warunkami (zobacz plik NOTICE.md danego pakietu). community/ to katalog tego repozytorium, a jego narzędzia niezależne od marki są również na licencji MPL-2.0. brands/suse/ to prywatny pakiet suse-lolly, jedyny submoduł: 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 pakietu na licencji SIL Open Font License 1.1 - pakiet SUSE zawiera kroje pisma SUSE i SUSE Mono.
Nie istnieje katalog tools/ ani catalog/ w katalogu głównym repozytorium. packages/node-shell/src/content-roots.ts odpowiada na pytania „gdzie znajduje się narzędzie <id>” i „gdzie jest katalog” na podstawie profiles.json w momencie odczytu, więc profil jest odpowiedzią ustalaną dla danego procesu i nie trzeba wcześniej budować żadnego drzewa katalogów. Prawdziwa para tools/ + catalog/ jest zapisywana wyłącznie w wyniku builda - dist/, ładunku RPM, obrazie kontenera - ponieważ przeglądarka pobiera te dwie ścieżki przez HTTP.
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.