Общ преглед
![]()
Този документ описва целта, структурата и архитектурните решения на платформата Lolly. Той отразява както продуктовата визия, така и текущото състояние на кодовата база.
Статус: Lolly е вътрешен прототип в затворен пилот, който още не е приключил. Двигателят е детерминистичен и вътрешно консистентен, но продуктът е в ранен етап — SUSE е клиент номер едно — и неговите двигатели за криптография и парсване на файлове в момента преминават през строгото инфраструктурно укрепване на SUSE в подготовка за корпоративен мащаб (в това сме наистина добри). Чети архитектурата по-долу като проектно намерение в процес на проверка, а не като завършен, сертифициран продукт. Виж Внедряване и управление за това как се провежда и измерва пилотът.
Защо съществува това
Екипите се сблъскват с повтарящ се проблем: повторяема креативна и съдържателна работа, която е твърде предвидима, за да оправдава всеки път ръцете на специалист, но и твърде чувствителна към качеството, за да бъде предадена без предпазни механизми. Резултатът е или бавна производителност (тясно място при специалистите), или непоследователност (всеки ползва какъвто инструмент има подръка), или обвързване с доставчик (SaaS DAM, който контролира шаблоните ти).
Тази платформа е структурният отговор:
Програмно генерирана креативност и съдържание в мащаб — създаване на активи с нулев труд, с правила под централен контрол, за служители, доставчици и партньори.
Резултатът е изобилие: всяко събитие има коректни табели, всяко CVE известие следва фирмения стил, всеки етикет се печата чисто, всеки имейл подпис е актуален — всичко това без тикет към дизайн екипа. Платформата поема повтарящата се операционализирана креативна работа. Тя нарочно не е инструмент за авторска креативна работа — дизайнерите продължават да притежават флагманските проекти.
Къде се вписва в пейзажа

| Възможност | Canva | Брандови портали | Illustrator | Figma / Penpot | Lolly |
|---|---|---|---|---|---|
| Масово генериране на съдържание | частично | ✗ | ✗ | ✗ | ✓ |
| Работи изцяло офлайн | ✗ | ✗ | ✓ | частично | ✓ |
| Шаблонна логика и твърди ограничения | ✗ | частично | ✗ | частично | ✓ |
| Не изисква дизайнерски умения | частично | ✓ | ✗ | ✗ | ✓ |
| Автоматични Content Credentials | ✗ | ✗ | частично | ✗ | ✓ |
| Инструменти, композиращи други инструменти | ✗ | ✗ | ✗ | ✗ | ✓ |
| Отворен двигател, без SaaS обвързване | ✗ | ✗ | ✗ | частично | ✓ |
| C2PA Content Credentials | ✗ | ✗ | ✗ | ✗ | ✓ |
| Произход на криминалистично ниво (по избор) | ✗ | ✗ | ✗ | ✗ | ✓ |
| Мобилни и десктоп приложения | ✓ | ✗ | ✗ | частично | ✓ |
| Команден ред и TUI | ✗ | ✗ | ✗ | ✗ | ✓ |
Празнината е ясна: нищо в съществуващия пейзаж не ни дава резултат, който е едновременно с ограничения на първо място, работещ офлайн, без изискване за умения и вътрешно достъпен. Lolly дори включва отворено платно — Layout Studio — където цветовете, типографията и активите се подчиняват на глобалните правила на бранда, така че свободното подреждане остава подчинено на ограниченията. Това, което Lolly не е, е дизайн пакет без ограничения: дизайнерите продължават да използват Illustrator и Figma за авторска флагманска работа. С този инструмент могат да се сглобяват пермутации.
Използвай го за: Бързо генериране на операционализирани креативни активи — плочки за събития, баджове с имена, подписи, CVE известия, QR кодове, карти за социални мрежи, товарителни етикети, структурирани отчети.
Не го използвай за: Авторско знаково (hero) съдържание.
Жизненият цикъл на една кампания
Най-ясният начин да видиш какво е Lolly не е списък с функции — а да проследиш един актив, докато минава от ръка на ръка. Гледай как една локализирана кампанийна карта се движи през организацията:
- Креативният задава правилата. Дизайнер създава базовия шаблон в Layout Studio и заковава в него типографията и цветовите променливи на бранда. Той не прави една карта — свършва основната работа веднъж, за да не му се налага никога повече да я локализира на ръка.
- Разработчикът я мащабира. Същият шаблон се включва в нощен конвейер през CLI, така че нова диаграма или нов езиков вариант се генерира автоматично — никой дизайнер не отваря файла отново.
- Продуцентът просто я използва. Търговски представител, офлайн в самолета, отваря същия инструмент и генерира перфектно съобразена с бранда презентация за среща с клиент. Без дизайнерски умения, без мрежа, без чакане.
„Новата диаграма“ от втората стъпка е рендер като този — направен от един низ с данни и няколко параметъра, без никой да отваря дизайнерски файл:
Смисълът не е, че Lolly е добра за дизайнери и добра за разработчици и добра за продажби, всяко поотделно във вакуум. Това е щафета: началната работа на креативния се мащабира от разработчика, което на свой ред дава сила на продуцента. Безусилното преживяване на нетехническия представител в самолета е възможно само заради строгостта, която дизайнерът е задал, а разработчикът е внедрил.
Това е умножителят на силата. Lolly не е шкаф с отделни инструменти за отделни роли — тя е един детерминиран жизнен цикъл на актива, до който се докосва всяка роля, и всяка ръка, през която минава, умножава стойността на предишната.
Едно одобрение, десет хиляди актива
Тъй като одобрението живее в инструмента, а не във файла (виж Как се сравнява Lolly), мащабът престава да е проблем на прегледа. Одобри веднъж инструмент за локализирани карти за социални мрежи и после генерирай 10 000 актива на 12 езика от електронна таблица — и нито един от тях не се нуждае от нова проверка от правния отдел или от бранда, защото шаблонът, от който всички идват, вече е одобрен.
Същият детерминиран инструмент стига до този мащаб по три начина и трите дават идентичен, предварително одобрен резултат:
- Човек, в приложението. Пакетната решетка
/pro: постави или импортирай редовете, получи по един готов актив на ред, изтегли zip. Без дизайнерски умения, без тикет, без чакане. - Разработчик, от командния ред. CLI върти същия двигател и същия път на рендиране без интерфейс, така че инструментът може да бъде подкаран по всичките 10 000 реда в скрипт или нощен конвейер. Едно извикване
lolly <tool> --field=…в цикъл е цялата интеграция. - Система или AI агент, през MCP. Същият инструмент, управляван програмно, със същата точност и в още по-голям мащаб — защото машината няма да се отегчи, докато хиляди файлове се изсипват.
Един набор ограничения на бранда, фиксиран веднъж от дизайнер; три пътя до идентичния предварително одобрен резултат — и машинният път мащабира най-далеч от всички, защото никога не се изморява, докато файловете се изсипват.
Голямата картина
┌─────────────────────────────────────────────┐
│ 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 │
└─────────────────────────────────────────────┘
Структура на хранилището
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 # TypeScript interface — the bridge 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).
│ ├── qr-code/
│ ├── quotes/
│ ├── email-signature/
│ ├── daily-card/ # "Day Brief" — weather/time/map (fetched by an inline template script)
│ ├── code-canvas/
│ ├── 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)
│ ├── bag-video/
│ ├── chart-creator/ # SVG charts from structured data
│ ├── filter-duotone/ # two-color photo treatment
│ ├── filter-halftone/ # photo → vector halftone dot grid
│ ├── filter-scanline/ # photo → retro posterised scanline grid (SVG / transparent 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)
│ ├── layout-studio/ # "Layout Studio" — 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
│ ├── web-icon/ # favicon .ico / png / svg from text + colours
│ ├── filter-posterize/ # photo → flat posterised vector separations
│ ├── filter-pixel-stretch/ # photo → pixel-smear effect
│ ├── 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
Модел на доставка на платформата
Платформата работи на няколко повърхности — уеб PWA, Tauri за десктоп/мобилни устройства, скриптируемия CLI и интерактивния TUI. Всички те използват един и същ двигател и едни и същи файлове на инструментите.
Уеб (PWA) — основен канал за разпространение

Хоства се на URL, контролиран от SUSE. Работи офлайн, след като service worker-ът кешира инструментите и активите. Тук повечето служители, доставчици и партньори ще използват платформата. Не се изисква акаунт — състоянието се съхранява в IndexedDB на всяко устройство.
Уеб обвивката е отзивчива от един-единствен лейаут. На десктоп инструментът представлява преоразмерима странична лента с контроли до сцена за преглед с естествена за тракпад навигация по платното (Cmd/Ctrl + колелце или щипване за мащабиране около курсора, влачене със Space или среден бутон за панорамиране, клавиши 0/1/+/− и HUD с Fit/%). На мобилни устройства (≤640px) контролите се превръщат в закотвен отгоре панел с дръжка за влачене, който прищраква в позиции peek/half/full (докосване превключва) върху статичен преглед на цял екран, а плаващ бутон Render отваря контролите за Export в изскачащ долен панел. При докосване има мащабиране с щипване и панорамиране с влачене върху прегледа. Пътят на рендиране и контролите за експорт са идентични и в двата случая — само обвивката на интерфейса се пренарежда.
Същият инструмент на ширина на телефон, без втори лейаут за поддържане: контролите се превръщат в панел горе, прегледът заема целия екран, а бутонът Render плава над него.
Пакетен режим (/pro). Уеб обвивката включва и пакетна решетка в стил електронна таблица (shells/web/src/pro/), която рендира много редове наведнъж през един или много инструменти. Поддържа двупосочен CSV/TSV обмен плюс поставяне от електронна таблица, шаблон/формат/размер/мерна единица/dpi за всеки ред, страничен панел с редактор на блокове и преглед на живо, сгъваеми колони за експорт, лента с тагове за „релевантност“ на всеки ред, пренареждане на редовете с лява дръжка за влачене, двустъпково потвърждение при изтриване, запазени пакетни сесии и изтегляне като .zip. Това е повърхността „от едно към много“ зад позиционирането „масово генериране на съдържание“.
Tauri десктоп / мобилни
Пакетирано нативно приложение (малък отпечатък благодарение на Tauri). Осигурява пълна офлайн наличност, достъп до файловата система за инструменти, зависещи от CLI (PDF Smasher, Font Outliner), и достъп до камерата. Планирано за подобрение на инструментариума в средата на 2026 г.
CLI
lolly <tool-id> [--input=value ...] --output=file.png
Десктоп потребителите могат да извикват много от инструментите от терминала. CLI обвивката зарежда същия двигател, създава jsdom DOM, изпълнява същия път на рендиране и записва файла. URL режимът е транспортът — CLI не е отделна имплементация. Това гарантира, че резултатите от CLI и GUI са идентични.
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
Интерактивният аналог на CLI: терминално приложение на цял екран, ориентирано към клавиатурата (изградено върху Ink), за разглеждане на инструменти, попълване на входове, запазване на проекти и експортиране — всичко без GUI. Неговият хост мост преизползва имплементацията на CLI за форматите без DOM (SVG/EMF/EPS/HTML + текст/данни) и добавя състояние на диска в ~/.lolly плюс вграден преглед по избор. Освен това има браузърно ниво за рендиране: обхватно ограничен headless Chromium (същият, който инсталира MCP сървърът), който при поискване произвежда растер/PDF/видео и заснемане на URL на живо — управлявайки билднато копие на уеб обвивката, така че резултатът е идентичен, и стартирайки едва когато за първи път експортираш такъв формат. Така url-shot (с изрязване + преоцветяване + векторни PDF/SVG) и всеки растерен/pdf инструмент работят и в терминала. Виж ръководството за TUI.
На която и повърхност да си, разделът Capabilities на таблото е пълната карта на това, което платформата декларира, че може — групирана и четима, без да отваряш нито един инструмент.
Категории инструменти

Инструментите са маркирани с category в манифеста си за групиране в галерията.
Редовете са изброени в реда на секциите в галерията. Секцията utility винаги се рендира последна в галерията (след всяка друга категория, включително бъдещи) — това е чекмеджето „Офлайн помощни инструменти“, работещи на устройството.
| Категория | Пуснати инструменти | Планирани |
|---|---|---|
everyone | QR Code Generator, Quote Card, Email Signature, Day Brief, Code Canvas, Color Block, Dynamic Layout, Logo, Web Icon Maker | Employee Image Stationery |
designer | Brand Lockup, Bag Video, Chart Creator, Street Map, Animated Ad, Multi-Page PDF, Diagram Builder, Logo Lockup: Grid (NASCAR), Logo Lockup: Partner, Filter: Duotone, Filter: Halftone, Filter: Scanline, Filter: Posterize Bitmap, Filter: Pixel Stretch | Font Outliner |
event | Meeting Planner, Event Name Badge, Wayfinding Signage, Calendar ICS | Event Stationery, Bulk Name Badges, Room Agenda Cards |
product | — | CVE Alert, Product Release Announcement, Blog OG Image |
utility | Countdown Timer, Color Palette, URL Screenshot, Strip Hidden Data, Text Helper, Compress PDF, Layout Studio | Конвертори на единици/формати, още помощни инструменти за поверителност на устройството |
Инструментите се класифицират и по статус: official (одобрени от бранда, без воден знак), community (външен принос), experimental (експорти с воден знак). Dynamic Layout, URL Screenshot, Logo Lockup: Grid (NASCAR), Filter: Posterize Bitmap и Diagram Builder в момента носят статус experimental; Web Icon Maker и Layout Studio се доставят като community инструменти.
Layout Studio е първият инструмент, изграден върху режима на свободно платно render.layout: "editor" — повърхност без интерфейсен хром, с директна манипулация, където влачиш, преоразмеряваш, завърташ и прилепваш кутии с текст, форми и изображения, а после експортираш през същия път на рендиране като всеки друг инструмент.
Strip Hidden Data е първият помощен инструмент на устройството (privacy: "on-device"): инструмент за трансформация на съдържание, който взема файл, предоставен от теб, обработва го изцяло в браузъра и връща чисто копие — никога не се качва, никога не получава воден знак, не се вгражда произход. Text Helper е вторият — работна маса на устройството за ежедневните задачи от типа „постави в някой сайт“ (JSON форматиране, JWT декодиране, Base64, URL кодиране/декодиране, SHA хеширане). Compress PDF е третият — свива PDF, като рекомпресира изображенията му, отново изцяло на устройството. И трите носят значката с текст „Работи на твоето устройство — нищо не се качва“. Това е началото на категория помощни инструменти за поверителност, която заменя предаването на поверителни файлове на еднофункционални уебсайтове.
Забележка:
categoryиstatusсе денормализират вcatalog/tools/index.json(регистъра, който галерията чете) от всекиtool.json. Манифестът е източникът на истина — индексът се генерира отnpm run build:catalog, аnpm run validate:catalogпроваля CI, ако комитнатият индекс се разминава с манифестите.
Архитектурни ангажименти
Тези решения са окончателни. Промяната на което и да е от тях е сериозно начинание — те оформят всяко друго решение в кодовата база.
1. Декларативни инструменти, с императивен авариен изход
Инструментът е манифест (tool.json) + шаблон (template.html) + незадължителен hooks.js.
Манифестът декларира входовете. Не шаблонът. Входовете не се извеждат от Handlebars токени. Манифестът е договорът; шаблонът консумира именувани променливи чрез {{id}}.
Хуковете са незадължителни. Повечето инструменти са чисто декларативни — манифест + шаблон стигат. Инструменти, които се нуждаят от изчислени стойности (QR кодиране, оформяне на данни за диаграми), предоставят hooks.js, който излага именувани функции от жизнения цикъл (onInit, onInput, onFrame — хукът за всеки кадър от камерата на живо за инструменти, реагиращи на движение — beforeExport, afterExport и exportFile — трансформационният път файл-вход/файл-изход, използван от помощните инструменти на устройството като Strip Hidden Data). (beforeRender е запазен в договора за хукове, но в момента няма място на извикване — не разчитай на него.) Хостът зарежда хуковете чрез new Function('host', …) с моста на възможностите, инжектиран като closure обхват. Това е договор за преносимост, а не сандбокс за сигурност: хуковете все пак се изпълняват в realm-а на страницата и могат да достигнат window/fetch/document в браузърна обвивка — host. е поддържаната, преносима повърхност, а не наложена граница. Асинхронните резултати от хукове са ограничени по време (onInit 5s, onInput 2s, останалите 5s) и закъснелите резултати се отхвърлят; избягал синхронен* хук не може да бъде прекъснат. Затова недоверен код на хукове от трети страни не е безопасен за изпълнение, докато не бъде доставена изолация чрез Worker.
Това е важно, защото: декларативните инструменти могат да бъдат създавани от хора, които не са разработчици. Ако всеки инструмент беше уеб приложение, рисковата бележка „ограничени умения за създаване/поддръжка на работните шаблони“ се превръща в постоянно тясно място.
2. Инструментите и активите са данни, а не пакетиран код
Уеб и Tauri приложенията изтеглят каталозите с инструменти и активи от известен URL при стартиране, кешират ги локално и работят с каквото е налично. Добавянето на нова плочка за събитие или сезонен актив не изисква ново издание на приложението.
Байтовете на активите имат SHA-256 контролни суми за предотвратяване на отравяне на CDN. id + version на актива управляват инвалидирането на кеша.
3. Capability Bridge е единственият API, който инструментите виждат
Инструментите никога не докосват DOM извън зоната на шаблона си, никога не извикват fetch директно, никога не четат файловата система. Те извикват версионирани host.* методи. Мостът е дефиниран в engine/src/bridge/host-v1.ts:
| Bridge API | Какво прави |
|---|---|
host.profile | Име, имейл, портретна снимка, град и т.н. на потребителя. Предварително попълва входове чрез bindToProfile. |
host.assets | Заявки към каталога, резолване на активи, предоставен от хоста интерфейс за избор. |
host.state | Запазване / зареждане на слотове с входове. IndexedDB в уеб, файлова система в Tauri, памет в CLI. |
host.clipboard | Записва текст или изображение в клипборда (с резервни варианти по платформи). |
host.export | Растеризира или сериализира целта на рендиране. Прилага воден знак за експериментални инструменти. |
host.net | Fetch със списък с разрешения — достъпен само ако инструментът е декларирал възможността "network". (В момента никой доставян инструмент не го използва.) |
Незадължителните, добавъчни повърхности се появяват само когато обвивката ги предоставя. Две са зад флаг за възможност — излагат се само когато инструментът декларира съответния флаг: host.compose (вграждане на рендер на друг инструмент — compose) и host.capture (заснемане на страница за URL Screenshot — capture). Останалите се откриват като функционалност — присъстват винаги, когато обвивката може да ги предостави: host.text (текст към пътища чрез HarfBuzz WASM; възможността wasm маркира инструментите, които разчитат на нея), host.pdf (парсване/компресия на PDF, използвано от Strip Hidden Data и Compress PDF) и host.tokens (DTCG дизайн токени). Декларируемите възможности са: network, filesystem, clipboard, camera, ffmpeg, wasm, capture, compose.
Един и същ инструмент работи в браузър, Tauri и headless CLI, защото всяка обвивка имплементира този интерфейс — инструментът никога не знае в коя от тях се намира.
Мостът е версиониран. Добавянето на методи е минорна версия. Премахването или промяната на сигнатури е мажорно вдигане на версията. Когато v2 излезе, v1 трябва да продължи да работи.
4. ID-тата на активите са завинаги
suse/logo/primary е договор. Веднъж публикуван:
- ID-то никога не се променя, никога не се преизползва.
- Промени в байтовете → вдигни
versionв манифеста. - Заменен от нов актив → задай
deprecated: trueи по изборreplacedBy. - Съществуващите препратки винаги се резолват.
Това прави запазените състояния на инструменти и споделените чрез URL връзки устойчиви през годините.
5. URL режимът е първокласен
Всеки вход трябва да може да се изрази като URL параметър:
lolly.tools/#/tool/qr-code?url=https://suse.com&ecl=H
CLI режимът е URL режим с различен транспорт — CLI обвивката изгражда обект с URL състояние от argv и изпълнява същия конвейер на двигателя. Има един път на рендиране. CLI не може да се разминава с GUI, защото не е отделна имплементация.
url-mode.ts се грижи за двупосочното преобразуване (парсване и сериализиране). Запазени параметри (никога не се предават на инструмента като входове): format, export, copy, slot, output, filename, _v, z (пакетирано състояние — токенът за „Най-кратка връзка“), width/w, height/h, unit, dpi, profile, password, bleed, marks, full, options, nostage. Входовете от тип актив в URL режим се сериализират чрез своето id; рънтаймът ги резолва чрез host.assets.get() преди хидратацията. width/height са стойности в unit (по подразбиране px, също mm/cm/in/pt/pc); при физическа единица dpi задава растерната резолюция. Те задават размера на документа на платното и предварително попълват панела с размери за експорт.
Тъй като всеки вход пътува в линка, промяната на параметър е различен готов актив. Цялата тази палитра е един изходен цвят, хармония и брой стъпки:
6. Съхранението минава през моста, а не директно
Уеб обвивка: IndexedDB. Tauri: файлова система. CLI: в паметта. Инструментите виждат само host.state.save(slot, data) и host.state.load(slot). localStorage не се използва — твърде малък е и не може да съхранява blob-ове.
Потребителите могат да запазват няколко именувани слота с редакции за всеки инструмент и да се връщат към всяка сесия по-късно. Не се изисква създаване на акаунт; състоянието е на устройство. Понеже мостът е единственият шев, това състояние на устройството е и преносимо: shells/web/src/data-transfer.ts изчита всичко обратно през host.profile/host.state/host.assets в един-единствен lolly-backup zip, който се импортира на всяка друга инсталация — офлайн отговорът на „преместване на ново устройство“, който не се нуждае от сървър (пълна спецификация: docs/data-transfer.md). Интеграцията със SUSE ID (синхронизация между устройства) е бъдещ етап върху това.
7. Таговете за зрялост отговарят структурно на риска „одобрено от бранда“
Всеки инструмент декларира status: official | community | experimental в манифеста си. Галерията сортира по статус. Експерименталните инструменти автоматично поставят воден знак на експортите си — водният знак се прилага от host.export.render, а не от инструмента, така че автор на неофициален инструмент не може да се откаже от него.
Това е структурен отговор на риска от възприятието, че използването на който и да е инструмент предполага одобрение от бранда. Процесните отговори (опашка за преглед, ограничаване чрез SUSE ID) се наслагват отгоре.
8. Входовете на инструментите са типизирани чрез манифеста, включително активите
Входовете декларират type: text, longtext, number, boolean, color, select, asset, date, time, datetime-local, url, profile, blocks, vector и file. Хостът рендира генерична контрола за всеки тип от манифеста — инструментите не пишат никакъв код за контроли. Три от типовете тежат повече от останалите:
asset(сfilterиallowUpload) е мостът към глобалната система за активи;allowUpload: falseе лостът за налагане на бранда при неща като лога върху спонсорски плочки, където са позволени само активи от библиотеката. Потребителските качвания използват същата формаAssetRefкато библиотечните активи, така че инструментите ги обработват еднакво.blocksе повтаряща се група полета — мини-таблица в рамките на един вход, редактирана в страничен панел, с типизирано/дискриминирано меню за добавяне и полета за активи на всеки блок. Щракването върху рендиран блок на платното фокусира реда на този блок. Използва се отmeeting-planner,chart-creator,event-name-badge,wayfinding-signage,color-blockиdigi-ad.vectorгрупира фиксиран набор от числа (напр. трансформация) в една съставна контрола;fileдържи собствения файл на потребителя като байтове в паметта за трансформиращи помощни инструменти на устройството (напр.strip-dataиcompress-pdf).
9. Шаблоните са без логика (Handlebars, а не EJS)
Handlebars беше избран пред EJS съзнателно:
- Без логика. Шаблоните могат да се създават от хора, които не са разработчици.
- Безопасен по подразбиране.
{{x}}екранира HTML;{{{x}}}е суров изход по изричен избор. - Липсата на произволен JS в шаблоните означава, че няма повърхност за XSS одит на всеки отделен шаблон.
Логиката живее в hooks.js, където е явна и подлежи на преглед. Налични Handlebars помощници: {{default}}, {{upper}}, {{lower}}, {{eq}}, {{markdown}}, {{asset ref}}, {{asset ref "property"}} (плюс помощниците за формати на данни icsStamp/rfcText/csvCell, използвани от съседните шаблони .ics/.vcf/.csv).
10. Инструментите композират инструменти
Един инструмент може да вгради рендера на друг инструмент без импорти между инструментите — композицията се резолва от двигателя, никога от кода на инструмента. Има две повърхности:
- Декларативен манифест —
composes: [{ id, tool, inputs, format?, width?, height? }]. Двигателят рендира посоченото дете и поставя резултата в шаблона без логика като{{asset <id>}}. Днесevent-name-badgeкомпозираqr-codeкато SVG. - Преносим URL за вграждане —
<img src="https://lolly.tools/tool/<id>.<ext>?<inputs>">. Обвивката рендира това дете локално (показва се заместващ пиксел, докато локалният рендер завърши); нищо никога не се изтегля отlolly.tools.
Инструментът Slides е изграден върху тази втора повърхност: всеки слот на всеки слайд може да съдържа друг инструмент Lolly вместо изображение.
Композирай рендера на който и да е инструмент: SVG дете остава истински вектор, когато родителят експортира към SVG или PDF, и се растеризира ясно за PNG; PNG/JPG/WEBP децата се вграждат като изображения. Изисква възможността compose. Композираните деца са междинни продукти — никога не получават воден знак или печат за произход — и композицията деградира елегантно: обвивка, която не може да рендира дете, просто пропуска слота и родителят пак се рендира.
Какво изрично избрахме да не правим
- Без EJS / без произволен JS в шаблоните. XSS повърхността е нула. Логиката живее в
hooks.js. - Без задължителна CMS за активи. Отделните потребители вкарват собствените си креативни файлове направо в каталога си в приложението (изгледът Каталог и Brand Studio) и създават собствени инструменти, като запазват сесии в Layout Studio — без сървър, без административна конзола. За споделен, управляван каталог организацията може да поддържа директорията с активи като git и да пропуска обновленията през преглед на PR — това е наличен модел на управление, а не изискване на приложението.
- Без принудителен RBAC. Отвореното приложение е с публичен достъп по подразбиране; брандовият риск се управлява чрез тагове за зрялост + водни знаци. Организация, която иска по-строг контрол, наслагва собствена автентикация и описания по-горе преглеждан през git каталог.
- Без централна база данни. Цялото потребителско състояние е на устройство. Интеграцията със SUSE ID е в пътната карта, но не е блокер за пускането.
- Без общ кодов път между инструменти и двигател. Двигателят е с отворен код;
tools/иassets/остават собственическо съдържание на SUSE в отделни хранилища. Разделението е наложено (без кръстосани импорти), за да остане границата чиста.
Жизненият цикъл от край до край
Потребител отваря lolly.tools/#/tool/qr-code?url=https://suse.com&ecl=H:
- Стартиране. Уеб обвивката отваря IndexedDB, конструира моста на възможностите, синхронизира каталозите с инструменти и активи (или зарежда от кеша, когато е офлайн).
- Маршрутизиране. URL хешът → изглед
tool, с извлечениqr-codeи URL параметрите. - Зареждане.
loadTool('qr-code', fetchFile)изтегляtool.json, валидира срещу JSON схемата, изтегляtemplate.html,styles.cssи източника наhooks.js. - Парсване на URL състоянието.
parseUrlStateпревежда URL параметрите в начални стойности на входовете. Препратките към активи (?logo=suse/logo/primary) се парсват като леки обекти{ id, _unresolved: true }. - Рънтайм.
createRuntime(tool, host, initialValues)изгражда входния модел (сливайки профилни данни, стойности по подразбиране и начални стойности), резолва препратките към активи чрезhost.assets.get(), зарежда хуковете (hostв closure обхват, без сандбокс), извикваhooks.onInit. - Рендиране. Обвивката се абонира за рънтайма; при всяка промяна на състоянието получава
{ model, hydrated }. Тя рендира контролите за вход от модела и записва хидратирания HTML на шаблона в#tool-canvas. - Взаимодействие. Потребителят пише във вход →
runtime.setInput(id, value)→ прилагат се ограниченията → извиква сеhooks.onInput→ повторна хидратация → повторно рендиране. Платното се обновява на живо. - Експорт. Потребителят щраква Download(PNG) →
runtime.export(canvasNode, 'png')→host.export.render(растеризира чрез dom-to-image-more; SVG/PDF минават през специализирани векторизатори, обхождащи DOM) → blob →host.export.download. Диапазонът от формати, към които един инструмент може да се включи, е широк:svg,png,jpg/jpeg,webp,avif,pdf, векторните форматиemf,eps, плюс форматите за печат/CMYKpdf-cmyk,cmyk-tiff,eps-cmyk; видео форматитеwebm,mp4,gif; и форматите за данни/текстhtml,md,txt,json,csv,ics,vcf,ico,zip. (Инструменти, които задаватrender.export: false— напр. Color Palette, Countdown Timer, Strip Hidden Data, Text Helper, Compress PDF — скриват контролите за изтегляне/формат/размери.) Физическите единици се конвертират по формат тук (PDF → истински точки на страницата, растер → пиксели при зададеното DPI сpHYschunk). Метаданните за авторство/произход (автор, инструмент, източник — изградени отengine/src/metadata.ts) се вграждат по формат: PNG iTXt, JPEG EXIF, PDF info dict, SVG<metadata>, GIF коментар. Експерименталните инструменти получават воден знак, вмъкнат от хоста, а не от инструмента.
Същият жизнен цикъл в Tauri. Същият жизнен цикъл в CLI — jsdom осигурява headless DOM; резултатът отива във файл или на stdout.
Статус на отворения код
Директориите engine/, shells/, schemas/ и docs/ са с отворен код под MPL-2.0 — неутрална спрямо доставчици платформа-скеле за брандови инструменти, като всяка доставима единица е отделена в собствено хранилище под github.com/lolly-tools. tools/ и catalog/assets/ са специфично за SUSE съдържание и остават собственост на SUSE (всички права запазени — виж NOTICE.md на всяко хранилище); те не са покрити от MPL.
Разделението е наложено — няма кръстосани импорти от engine/ към tools/ или assets/ — така че границата платформа/съдържание остава чиста.
Пътна карта
| Етап | Срок | Какво |
|---|---|---|
| Първоначални инструменти | ✅ Готово | QR Code, Quote Card, Email Signature, Day Brief, Code Canvas, Countdown Timer, Color Palette, Brand Lockup, Bag Video, Chart Creator, Filter: Duotone, Meeting Planner — уеб обвивката е на живо |
| Подобряване на текущия инструментариум | Средата на 2026 ✅ Готово | Изтегляемо офлайн приложение (Tauri); допълнителни инструменти за служители и събития; по-богат конвейер за експорт (стабилност на текст-към-пътища, метаданни, допълнителни формати — виж plans.md) |
| Отваряне на кода на двигателя | Края на 2026 ✅ Готово | Двигателят, обвивките, схемите и документацията стават публични — не и брандираните инструменти/активи |
| Прехвърляне от устройство на устройство | ✅ Готово | Преносим пакет lolly-backup пренася профил, запазени сесии, качени изображения и предпочитания между всеки две инсталации — офлайн или онлайн, без акаунт. Съвместим занапред, проверяван за цялост плик (спецификация: docs/data-transfer.md) |
| Установяване на формална пътна карта за инструментите | Края на 2026 | Референтни комплекти за клиенти, AI поглъщане на дизайн, GET/URL режим на заявки |
| Помощни инструменти за поверителност на устройството | 🚧 В процес | Инструменти за трансформация на съдържание, които обработват твоя собствен файл локално (файл вход → чист файл изход), заменяйки изнасянето към еднофункционални SaaS. Готово: тип вход file + трансформационният път exportFile + конвенциите privacy:"on-device" (без воден знак/произход) + Strip Hidden Data (метаданни на JPEG/PNG/SVG/PDF, PDF чрез моста host.pdf) и Text Helper (работната маса на устройството за ежедневните задачи от типа „постави в някой сайт“ — JSON форматиране, JWT декодиране, Base64, URL кодиране/декодиране, SHA хеширане, плюс група Novelty). Следва: изрязване/преоразмеряване, конвертиране/компресия на изображения; после мост за кодеци host.image (спецификация: plans/exfiltration-app-content.md) |
| Дизайн токени (DTCG) | 🚧 Цветовете са доставени | Брандовите примитиви като канонични W3C Design Tokens (DTCG) — форматът, който Penpot импортира/експортира. Готово: цветови токени (suse/tokens/brand), мост host.tokens, мостри в пикера + стойности, свързани с референции (спецификация: docs/design-tokens.md). Следва: токени за размери/типография, Penpot импорт/експорт, потребителски токени в пакета за прехвърляне (tokens.json) |
| MCP агентска крайна точка (рендиране) | ✅ Готово | MCP сървър излага каталога + пътя на рендиране като извикваеми инструменти (lolly_list_tools / describe_tool / build_url / render / transform), така че всеки агент да може да произвежда завършени, подчинени на правилата активи — добави го към всеки MCP клиент като персонализиран конектор (OAuth 2.1) или насочи CLI/HTTP клиент към него с bearer токен. На живо на mcp.lolly.tools (пълна крайна точка: растер/PDF/анимация/видео чрез хостван headless браузър) и lolly.tools/api/mcp (сървърлес ниво без браузър). Различен от описания по-долу Penpot MCP за авторство, който е за създаване на инструменти (спецификация: plans/mcp-server.md; ръководство: docs/mcp.md + docs/ai-agents.md) |
| Поглъщане на Penpot файлове като инструменти | 2027+ | Импортиране на Penpot файл и представянето му като Lolly инструмент (декларативен, с ограничения на първо място), превръщайки дизайни, създадени в Penpot, в детерминистични генератори |
| MCP + Penpot разширение (авторство само онлайн) | 2027+ | Penpot MCP сървър формулира нови инструменти с AI — най-визуалният начин за създаване на детерминистични шаблони: първи кръг, информиран от бранда, усъвършенстван с човек в цикъла, с цел с времето нови контексти от първи опит. Създаването на инструменти е само онлайн; инструментите, които то произвежда, работят навсякъде |
| RBAC + SUSE ID | 2027+ | Ограничаване на конкретни инструменти зад SUSE ID; запазено състояние на много устройства; внасяне/изнасяне през Google Drive |
Къде свършва двигателят и къде започва хостът
Ако можеш да го опишеш с чисти данни + Handlebars → двигател. Ако докосва DOM, файловата система, мрежата или какъвто и да е API на браузъра/ОС → хост.
Линията е рязка нарочно. Двигателят е частта с отворен код. Всичко, което знае за SUSE, конкретни платформи или среди за изпълнение, остава извън него.