Огляд

Іконка Lolly — велика зелено-біла карамелька-льодяник

Цей документ фіксує призначення, структуру й архітектурні рішення платформи Lolly. Він відображає як бачення продукту, так і поточний стан кодової бази.

Статус: Lolly — це внутрішній прототип на етапі закритого пілоту, який ще не завершено. Рушій детермінований і внутрішньо узгоджений, але продукт перебуває на ранній стадії — SUSE є клієнтом номер один — а його рушії криптографії та розбору файлів наразі проходять сувору інфраструктурну підготовку SUSE, готуючись до корпоративного масштабу (у цьому ми справді сильні). Сприймайте наведену нижче архітектуру як проєктний задум, що проходить випробування, а не як завершений, сертифікований продукт. Див. Прийняття та управління, щоб дізнатися, як проводиться й вимірюється пілот.


Навіщо це існує

Команди стикаються з повторюваною проблемою: рутинна творча й контентна робота, надто передбачувана, щоб щоразу залучати кваліфікованих фахівців, але надто чутлива до якості, щоб делегувати її без запобіжників. Наслідком є або низька пропускна здатність (вузьке місце на фахівцеві), або неузгодженість (кожен використовує той інструмент, який має), або залежність від постачальника (SaaS DAM, який контролює ваші шаблони).

Ця платформа — структурна відповідь:

Програмна творчість і контент у масштабі — генерація ресурсів без ручної праці, з правилами під централізованим контролем, для співробітників, підрядників і партнерів.

Результат — достаток: кожна подія має правильну навігаційну систему, кожне сповіщення про CVE відповідає фірмовому стилю, кожна етикетка друкується чисто, кожен підпис в електронній пошті актуальний — і все це без заявки до дизайнера. Платформа бере на себе повторювану операціоналізовану творчість. Вона свідомо не є інструментом для індивідуальної творчості — флагманська робота досі належить дизайнерам.

Де це вписується в ландшафт

Every tool in the library as a card, grouped by category, so a producer picks one and starts

МожливістьCanvaБренд-порталиIllustratorFigma / PenpotLolly
Масова генерація контентучастково
Повністю працює офлайнчастково
Логіка шаблонів і жорсткі обмеженнячастковочастково
Не потрібні навички дизайнучастково
Автоматичні Content Credentialsчастково
Інструменти компонують інші інструменти
Відкритий рушій, без прив'язки до SaaSчастково
C2PA content credentials
Опціональне походження криміналістичного рівня
Мобільні та десктопні застосункичастково
Командний рядок і TUI

Прогалина очевидна: ніщо в наявному ландшафті не дає нам результату, який ставить обмеження на перше місце, працює офлайн, не потребує спеціальних навичок і є внутрішньо доступним. Lolly навіть містить відкрите полотно — Layout Studio — де кольори, шрифти й ресурси відповідають глобальним параметрам бренду, тож вільне компонування залишається таким, що ставить обмеження на перше місце. Чим воно не є — то це необмеженим дизайнерським пакетом: дизайнери й далі використовують Illustrator і Figma для індивідуальної флагманської роботи. За допомогою цього інструмента можна збирати різні варіанти комбінацій.

Використовуйте для: швидкої генерації операціоналізованих творчих ресурсів — плиток подій, іменних бейджів, підписів, сповіщень про CVE, QR-кодів, карток для соцмереж, транспортних етикеток, структурованих звітів.

Не використовуйте для: індивідуального ключового контенту.


Життєвий цикл кампанії

A titled stacked area chart, its three series banded in a cool palette with axes, legend and title all placed by the template rather than by hand

Найясніше видно, чим є Lolly, не зі списку функцій — а якщо простежити за одним ресурсом, як він переходить з рук у руки. Погляньте, як одна локалізована картка кампанії рухається через організацію:

  1. Креативник задає правила. Дизайнер створює базовий шаблон у Layout Studio, жорстко закодувавши в ньому шрифти й змінні кольорів бренду. Він робить не одну картку — він виконує фундаментальну роботу один раз, щоб більше ніколи не локалізувати її вручну.
  2. Розробник це масштабує. Той самий шаблон під'єднують до нічного конвеєра через CLI, тож свіжа діаграма або новий мовний варіант з'являється автоматично — жоден дизайнер не відкриває файл заново.
  3. Продюсер просто цим користується. Менеджер із продажів, офлайн у літаку, відкриває той самий інструмент і генерує ідеально відповідну бренду презентацію для зустрічі з клієнтом. Без дизайнерських навичок, без мережі, без очікування.

«Свіжа діаграма» з другого кроку — це рендер, як-от цей, зроблений із рядка даних і кількох параметрів, і жодного дизайнерського файлу ніхто не відкривав:

Річ не в тім, що Lolly добра для дизайнерів і добра для розробників і добра для продажів, кожне окремо у вакуумі. Це естафета: початкову роботу креативника масштабує розробник, що, у свою чергу, дає силу продюсеру. Легкий досвід нетехнічного менеджера в літаку можливий лише завдяки тій строгості, яку задав дизайнер і розгорнув розробник.

Ось у чому множник сили. Lolly — не шухляда з окремими інструментами для окремих ролей, а один детермінований життєвий цикл ресурсу, до якого дотична кожна роль, і кожні руки, через які він проходить, множать цінність попередніх.


Одне схвалення, десять тисяч ресурсів

Batch mode on a fresh install: one empty row waiting for a tool, with the whole spreadsheet surface and its Render button in place before any data arrives

Оскільки схвалення живе в інструменті, а не у файлі (див. Як Lolly порівнюється з іншими), масштаб перестає бути проблемою рецензування. Схваліть інструмент для локалізованих карток для соцмереж один раз, а потім згенеруйте з таблиці 10 000 ресурсів 12 мовами — і жоден із них не потребує нової перевірки від юристів чи від бренд-менеджера, бо шаблон, з якого всі вони походять, уже схвалений.

Той самий детермінований інструмент досягає цього масштабу трьома шляхами, і всі вони дають ідентичний, попередньо схвалений результат:

Один набір обмежень бренду, зафіксований дизайнером один раз; три маршрути до ідентичного попередньо схваленого результату — і машинний маршрут масштабується найдалі, бо він не втомлюється, поки сиплються файли.


Загальна картина

                ┌─────────────────────────────────────────────┐
                │              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) — основний канал розповсюдження

The desktop split view - controls generated from the manifest on the left, the live canvas on the right

An audiogram on a 430px-wide screen - the controls sheet above, the finished square artwork below, and the floating render pill

Розміщено за 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 завантажує той самий рушій, створює DOM через jsdom, виконує той самий шлях рендерингу й записує файл. Транспортом виступає 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 на дашборді — це повна карта того, що платформа декларує як свої вміння, згрупована й читабельна без відкривання жодного інструмента.


Категорії інструментів

The Utilities drawer, where every card is a tool that transforms a file you already have

Інструменти позначені category у своєму маніфесті для групування в галереї.

Рядки перелічені в порядку розділів галереї. Розділ utility завжди рендериться останнім у галереї (після кожної іншої категорії, зокрема майбутніх) — це шухляда «Offline Utilities», що працює на пристрої.

КатегоріяГотові інструментиЗаплановані
everyoneQR Code Generator, Quote Card, Email Signature, Day Brief, Code Canvas, Color Block, Dynamic Layout, Logo, Web Icon MakerEmployee Image Stationery
designerBrand 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 StretchFont Outliner
eventMeeting Planner, Event Name Badge, Wayfinding Signage, Calendar ICSEvent Stationery, Bulk Name Badges, Room Agenda Cards
productCVE Alert, Product Release Announcement, Blog OG Image
utilityCountdown 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, повторно стискаючи його зображення, знову ж таки повністю на пристрої. Усі три несуть текст значка «Runs on your device — nothing is uploaded». Це початок категорії приватних утиліт, яка замінює передавання конфіденційних файлів вузькоспеціалізованим вебсайтам.

Примітка: category і status денормалізуються в catalog/tools/index.json (реєстр, який читає галерея) із кожного tool.json. Маніфест є джерелом істини — індекс генерується через npm run build:catalog, а npm run validate:catalog завалює CI, якщо закомічений індекс розходиться з маніфестами.


Архітектурні зобов'язання

Ці рішення остаточні. Зміна будь-якого з них — це велика робота: вони формують кожне інше рішення в кодовій базі.

1. Декларативні інструменти з імперативним запасним виходом

Street Map's control stack - a city dropdown, a theme select, weight sliders and colour triggers, every one of them drawn from a manifest line

Інструмент — це маніфест (tool.json) + шаблон (template.html) + необов'язковий hooks.js.

Маніфест декларує вхідні дані. Не шаблон. Вхідні дані не виводяться з токенів Handlebars. Маніфест є контрактом; шаблон споживає іменовані змінні через {{id}}.

Хуки необов'язкові. Більшість інструментів суто декларативні — маніфесту + шаблону достатньо. Інструменти, яким потрібні обчислювані значення (кодування QR, формування даних діаграм), надають hooks.js, що виставляє іменовані функції життєвого циклу (onInit, onInput, onFrame — покадровий хук живої камери для інструментів, що реагують на рух, — beforeExport, afterExport і exportFile — шлях перетворення файл-у/файл-із, який використовують локальні утиліти на кшталт Strip Hidden Data). (beforeRender зарезервовано в контракті хуків, але наразі він ніде не викликається — не покладайтеся на нього.) Хост завантажує хуки через new Function('host', …) з місткісним мостом, впровадженим у замикання. Це контракт переносимості, а не пісочниця безпеки: хуки все одно виконуються в реалмі сторінки й можуть дотягнутися до window/fetch/document у браузерній оболонці — host. є підтримуваною, переносимою поверхнею, а не примусовою межею. Результати асинхронних хуків обмежені в часі (onInit 5 с, onInput 2 с, решта 5 с), а запізнілі результати відкидаються; некерований синхронний* хук неможливо перервати. Тому небезпечно запускати недовірений сторонній код хуків, поки не з'явиться ізоляція через Worker.

Це важливо, бо: декларативні інструменти можуть створювати нерозробники. Якби кожен інструмент був вебзастосунком, застереження про ризик «обмежені навички для створення/підтримки робочих шаблонів» стало б постійним вузьким місцем.

2. Інструменти й ресурси — це дані, а не вбудований код

Вебзастосунок і застосунок Tauri отримують каталоги інструментів та ресурсів із відомого URL під час завантаження, кешують їх локально й працюють із тим, що там є. Додавання нової плитки події чи сезонного ресурсу не потребує випуску нової версії застосунку.

Байти ресурсів мають контрольну суму SHA-256 для запобігання отруєнню CDN. Інвалідацію кешу керує id + version ресурсу.

3. Місткісний міст — єдиний API, який бачать інструменти

Інструменти ніколи не торкаються DOM поза межами своєї області шаблону, ніколи не викликають fetch напряму, ніколи не читають файлову систему. Вони викликають версійовані методи host.*. Міст визначено в engine/src/bridge/host-v1.ts:

API мостаЩо робить
host.profileІм'я, email, портрет, місто користувача тощо. Попередньо заповнює вхідні дані через bindToProfile.
host.assetsЗапити до каталогу, розв'язання ресурсів, надана хостом UI-вибірка.
host.stateЗбереження / завантаження слотів вхідних даних. IndexedDB у вебі, файлова система в Tauri, пам'ять у CLI.
host.clipboardЗапис тексту або зображення в буфер обміну (з платформними запасними варіантами).
host.exportРастеризує або серіалізує ціль рендеру. Застосовує водяний знак для експериментальних інструментів.
host.netFetch за списком дозволених — доступний лише якщо інструмент задекларував можливість "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 та безголовому CLI, бо кожна оболонка реалізує цей інтерфейс — інструмент ніколи не знає, у якому з них він перебуває.

Міст версійовано. Додавання методів — це мінорна версія. Видалення або зміна сигнатур — це стрибок мажорної версії. Коли вийде v2, v1 має продовжувати працювати.

4. ID ресурсів — назавжди

suse/logo/primary — це контракт. Після публікації:

Це робить збережені сесії інструментів та посилання, поширені через URL, довговічними впродовж років.

5. Режим URL — першокласний

That link on its own, with nothing else in it, is the finished asset

Nine steps across four hues, all grown from the single seed colour carried in the link

Кожні вхідні дані мають бути виражені як параметр 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. Вхідні дані типу asset у режимі 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 не використовується — він замалий і не може вміщати блоби.

Користувачі можуть зберігати кілька іменованих слотів редагування на інструмент і повертатися до кожної сесії згодом. Створення облікового запису не потрібне; стан прив'язаний до пристрою. Оскільки міст є єдиним швом, цей стан на пристрої також переносний: shells/web/src/data-transfer.ts зчитує все назад через host.profile/host.state/host.assets в один zip lolly-backup, який імпортується на будь-якому іншому встановленні — офлайн-відповідь на «перехід на новий пристрій», що не потребує сервера (повна специфікація: 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. Хост рендерить загальний елемент керування для кожного типу з маніфесту — інструменти не пишуть жодного коду керування. Три несуть більше ваги, ніж решта:

9. Шаблони без логіки (Handlebars, а не EJS)

Handlebars обрано замість EJS свідомо:

Логіка живе в hooks.js, де вона явна й придатна для рецензування. Доступні хелпери Handlebars: {{default}}, {{upper}}, {{lower}}, {{eq}}, {{markdown}}, {{asset ref}}, {{asset ref "property"}} (плюс хелпери форматів даних icsStamp/rfcText/csvCell, що використовуються сусідніми шаблонами .ics/.vcf/.csv).

10. Інструменти компонують інструменти

The opening slide of the default deck, whose own subtitle states that every slide can hold another Lolly tool

Інструмент може вбудувати рендер іншого інструмента без імпортів між інструментами — композицію розв'язує рушій, ніколи код інструмента. Є дві поверхні:

Інструмент Slides побудований саме на цій другій поверхні: будь-який слот на будь-якому слайді може містити інший інструмент Lolly замість зображення.

Компонуйте рендер будь-якого інструмента: дочірній SVG залишається справжнім вектором, коли батьківський інструмент експортує в SVG чи PDF, і чітко растеризується для PNG; дочірні PNG/JPG/WEBP вбудовуються як зображення. Потребує можливості compose. Компоновані дочірні елементи — це проміжні результати: ніколи не отримують водяного знака чи штампа походження, а композиція деградує граційно — оболонка, що не може відрендерити дочірній елемент, просто пропускає слот, і батьківський інструмент усе одно рендериться.


Що ми свідомо вирішили не робити


Життєвий цикл, від початку до кінця

The export panel that <code>?options</code> opens: the filename and format pair, the output size, and the controls that write the file

Користувач відкриває lolly.tools/#/tool/qr-code?url=https://suse.com&ecl=H:

  1. Завантаження. Веб-оболонка відкриває IndexedDB, конструює міст можливостей, синхронізує каталоги інструментів та ресурсів (або завантажує їх із кешу, коли ви офлайн).
  2. Маршрутизація. Хеш URL → подання tool, з витягнутими qr-code та параметрами URL.
  3. Завантаження. loadTool('qr-code', fetchFile) отримує tool.json, перевіряє його за JSON Schema, отримує template.html, styles.css та джерело hooks.js.
  4. Розбір стану з URL. parseUrlState перетворює параметри URL на початкові значення вхідних даних. Посилання на ресурси (?logo=suse/logo/primary) розбираються як полегшені об'єкти { id, _unresolved: true }.
  5. Runtime. createRuntime(tool, host, initialValues) будує модель вхідних даних (об'єднуючи дані профілю, значення за замовчуванням та початкові значення), розв'язує посилання на ресурси через host.assets.get(), завантажує hooks (host в межах замикання, без пісочниці), викликає hooks.onInit.
  6. Рендеринг. Оболонка підписується на runtime; за кожної зміни стану вона отримує { model, hydrated }. Вона рендерить елементи керування вхідними даними з моделі та записує гідрований HTML шаблону в #tool-canvas.
  7. Взаємодія. Користувач вводить дані в поле → runtime.setInput(id, value) → застосовуються обмеження → викликається hooks.onInput → повторна гідрація → повторний рендеринг. Полотно оновлюється наживо.
  8. Експорт. Користувач натискає 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, а також друкарські/CMYK-формати pdf-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 із фрагментом pHYs). Метадані авторства/походження (автор, інструмент, джерело — будуються engine/src/metadata.ts) вбудовуються для кожного формату: PNG iTXt, JPEG EXIF, словник info в PDF, <metadata> у SVG, коментар у 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); додаткові інструменти для співробітників та подій; багатший конвеєр експорту (стабільність text-to-path, метадані, додаткові формати — див. plans.md)
Відкрити код рушіяКінець 2026 ✅ ГотовоРушій, оболонки, схеми, документація стають публічними — але не брендові інструменти/ресурси
Передача між пристроями✅ ГотовоПортативний пакунок lolly-backup переносить профіль, збережені сесії, завантажені зображення та налаштування між будь-якими двома інсталяціями — офлайн або онлайн, без облікового запису. Прямо-сумісна оболонка з перевіркою цілісності (специфікація: docs/data-transfer.md)
Створити формальну дорожню карту інструментівКінець 2026Референсні набори для клієнтів, ШІ-приймання дизайну, режим запитів 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 (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 (безсерверний рівень без браузера). Відрізняється від MCP авторингу Penpot нижче, який стосується створення інструментів (специфікація: plans/mcp-server.md; посібник: docs/mcp.md + docs/ai-agents.md)
Приймання файлів Penpot як інструментів2027+Імпортуйте файл Penpot і подавайте його як інструмент Lolly (декларативний, орієнтований на обмеження), перетворюючи дизайни, створені в Penpot, на детерміновані генератори
Розширення MCP + Penpot (авторинг лише онлайн)2027+MCP-сервер Penpot формулює нові інструменти за допомогою ШІ — найвізуальніший спосіб створювати детерміновані шаблони: перший раунд з урахуванням бренду, доопрацьований людиною в циклі, з прицілом на нові контексти в один прохід із часом. Створення інструментів — лише онлайн; інструменти, які воно виробляє, працюють будь-де
RBAC + SUSE ID2027+Обмеження доступу до конкретних інструментів за SUSE ID; збережений стан на кількох пристроях; приймання/експорт Google Drive

Де закінчується рушій і починається хост

Якщо це можна описати чистими даними + Handlebars → рушій. Якщо це торкається DOM, файлової системи, мережі чи будь-якого API браузера/ОС → хост.

Межа проведена чітко навмисно. Рушій — це частина з відкритим кодом. Усе, що знає про SUSE, конкретні платформи чи середовища виконання, залишається поза ним.