Lolly
Mở ứng dụng

Tổng quan

signed by Lollyoverview.htmlHTMLpixels, not shapes12 KBAI generatedgenerated by ClaudeTự kiểm chứngTải tệp đã ký

Biểu tượng Lolly - kẹo mút lớn màu xanh lá và trắng

Tài liệu này ghi lại mục đích, cấu trúc và các quyết định kiến trúc cho nền tảng Lolly. Nó phản ánh cả tầm nhìn sản phẩm lẫn hiện trạng của codebase.

Trạng thái: Lolly đã được phát hành. Phiên bản 1.0 ra mắt dưới dạng mã nguồn mở theo giấy phép MPL-2.0 vào ngày 30 tháng 8 năm 2026, và các tính năng, giá trị mặc định cùng danh mục công cụ vẫn thay đổi giữa các bản phát hành. Engine có tính tất định, với một render path duy nhất phía sau mọi shell. Bảo mật của nó chưa được kiểm toán độc lập, và bằng chứng về mức độ áp dụng đã có từ vài tháng trước. Xem Áp dụng & Quản trị để biết tình trạng hiện tại và cách đo lường mức độ áp dụng.

Cách đọc trang này. Trang này chứa hai loại nội dung, theo thứ tự. Nửa đầu là vì sao điều này tồn tại: vấn đề, định vị và vòng đời mà một tài sản đơn lẻ trải qua. Từ Bức tranh toàn cảnh trở đi là các lớp khớp với nhau ra sao: tài liệu kiến trúc dành cho người đóng góp, bao gồm sự phân tách engine/shell/pack, bố cục kho mã, các đích triển khai và các cam kết ràng buộc mọi thay đổi lên nền tảng. Nếu bạn ở đây để thay đổi codebase thay vì tìm hiểu sản phẩm, hãy bắt đầu từ bức tranh toàn cảnh.

Có hai tài liệu đồng hành đi sâu hơn trang này. engine/README.md trong kho mã là bản đồ engine theo từng module, với một bảng được tạo tự động liệt kê mọi module và những gì nó phân tích hay ghi ra. Mô hình đe dọa & Ranh giới tin cậy là cùng một kiến trúc được đọc dưới góc độ ranh giới tin cậy, và là trang đúng cho bất kỳ câu hỏi nào về những gì engine coi là không đáng tin cậy.


Vì sao điều này tồn tại

Công việc sáng tạo lặp đi lặp lại quá dễ đoán để cần đến bàn tay chuyên nghiệp mỗi lần, và quá nhạy về chất lượng để giao phó mà không có rào chắn. Nếu cứ để vậy, nó sẽ đi theo một trong ba hướng: chậm, thiếu nhất quán, hoặc bị khóa vào template của một nhà cung cấp.

Nền tảng này là câu trả lời trực tiếp:

Sáng tạo và nội dung theo chương trình ở quy mô lớn - tài sản được tạo ra từ đầu vào, với các quy tắc chỉ cần thiết lập một lần, dành cho bất kỳ ai cần đến chúng.

Lolly không phải nơi một hệ thống thiết kế được phát minh ra - đó là nơi nó được sản xuất ra. Hãy hình dung nó như một máy bán hàng tự động cho thiết kế: chọn một lựa chọn, nhận về một kết quả. Mọi lần đều vậy. Engine luôn hướng tới chất lượng cao nhất mà mỗi định dạng có thể tạo ra trên phần cứng trước mặt bạn, và cùng một engine đó tạo ra cùng một tệp trên mọi nền tảng nó chạy trên.

Kết quả là sự dồi dào: mọi sự kiện có bảng hiệu đúng chuẩn, mọi cảnh báo CVE khớp phong cách công ty, mọi nhãn in sạch, mọi chữ ký email luôn cập nhật - tất cả đều đến từ các công cụ vốn đã mang sẵn quy tắc. Nền tảng xử lý công việc sáng tạo mang tính vận hành lặp lại. Nó cố tình không phải là một công cụ sáng tạo tùy biến - các nhà thiết kế vẫn giữ quyền sở hữu các công việc chủ lực.

Đổi mới theo xác suất, mở rộng theo tất định

Mọi cuộc tranh luận về AI trong một pipeline sáng tạo đều mắc kẹt ở cùng một câu hỏi: phần nào trong việc này là việc của máy móc? Đây là một câu hỏi cũ đã có đáp án ổn định. Các thầy chép sách và họa sĩ minh họa từ xưa đã làm việc giữa hai công cụ - bản phác thảo tự do, nơi không gì cố định và mọi thứ đều có thể thử, và máy in, đáng gờm chính vì nó cam kết. Các bản phác thảo là nơi nghệ thuật diễn ra. Máy in là cách nó đến được với mọi người. Không ai nhầm lẫn hai thứ đó, và cả hai đều tiếp tục tiến bộ - mực mới, kiểu chữ mới, máy in mới - mỗi thứ cải tiến hài hòa với tay nghề và mục đích nó phục vụ.

Lolly kẻ cùng một ranh giới đó. Khám phá theo xác suất: một mô hình, một nhà thiết kế, một ý tưởng thô, một câu lệnh dẫn tới nơi không ai định trước. Rồi mở rộng theo tất định - thứ trở thành nhiều kết quả là một công cụ, và một công cụ kết xuất giống hệt nhau mỗi lần từ các đầu vào mà bạn có thể đọc được. Việc khám phá vẫn tự do vì không có gì ở phía sau phụ thuộc vào việc nó ra kết quả giống nhau hai lần. Đầu ra giành được lòng tin vì nó không phải một phỏng đoán. Đưa việc thử nghiệm AI vào những kết quả có thể dự đoán, tái lập được không phải một ngành mới; đó chính là sự phân công lao động đã từng khiến bản in đáng tin cậy ngay từ đầu.

Tin tưởng quá trình sáng tạo, mở rộng bằng sự nghiêm ngặt.

So với các lựa chọn khác

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

Mức độ hoàn thiện năng lực trên các công cụ sáng tạo hiện nay, khảo sát tháng 8/2026. Thang điểm: 0 không có, 25 mức giải pháp tạm, 50 có thật nhưng bị giới hạn hoặc một phần, 75 mạnh nhưng có lưu ý, 100 năng lực cốt lõi.

signed by Lollypositioning-comparison.htmlHTMLpixels, not shapes40 KBAI generatedgenerated by GPT-6Tự kiểm chứngTải tệp đã ký

Khoảng trống rất rõ: không có công cụ nào hiện đang bán ra cho chúng ta đầu ra ưu tiên ràng buộc, chạy offline, kỹ năng thấp, truy cập nội bộ được. Lolly thậm chí còn có một canvas mở - Design - nơi màu sắc, kiểu chữ và tài sản tuân theo các biến toàn cục của thương hiệu, để việc sắp xếp tự do vẫn ưu tiên ràng buộc. Điều nó không phải là một bộ công cụ thiết kế không giới hạn: các nhà thiết kế vẫn dùng Illustrator và Figma cho công việc chủ lực tùy biến. Các hoán vị có thể được lắp ráp bằng công cụ này.

Mọi công cụ trong thư viện dưới dạng thẻ, nhóm theo danh mục, để một nhà sản xuất chọn một cái và bắt đầu signed by Lollyvector SVG367 paths~62k nodes773 groups3 images1.453 KBTự kiểm chứngTải tệp đã kýMọi công cụ trong thư viện dưới dạng thẻ, nhóm theo danh mục, để một nhà sản xuất chọn một cái và bắt đầu signed by Lollyvector SVG367 paths~62k nodes776 groups3 images1.454 KBTự kiểm chứngTải tệp đã ký

Dùng cho: Tạo nhanh các tài sản sáng tạo mang tính vận hành - ô sự kiện, thẻ tên, chữ ký, cảnh báo CVE, mã QR, thẻ mạng xã hội, nhãn lô hàng, báo cáo có cấu trúc.

Không dùng cho: Nội dung chủ lực tùy biến.


Vòng đời của một chiến dịch

Cách rõ ràng nhất để thấy Lolly là gì không phải là một danh sách tính năng - mà là theo dõi một tài sản duy nhất khi nó chuyển từ tay người này sang tay người khác. Hãy quan sát một thẻ chiến dịch đã bản địa hóa di chuyển qua tổ chức:

  1. Người sáng tạo đặt ra quy tắc. Một nhà thiết kế soạn template gốc trong công cụ Design, cố định sẵn các biến kiểu chữ và màu sắc của thương hiệu. Họ không làm một thẻ duy nhất - họ đang làm công việc nền tảng một lần để không bao giờ phải bản địa hóa thủ công lại nữa.
  2. Nhà phát triển mở rộng nó. Cùng template đó được nối vào một pipeline chạy hàng đêm qua CLI, để một biểu đồ mới hay một biến thể ngôn ngữ mới được tạo tự động - không nhà thiết kế nào phải mở lại file.
  3. Nhà sản xuất chỉ việc dùng nó. Một đại diện bán hàng, offline trên máy bay, mở cùng công cụ đó và tạo ra một bản trình chiếu hoàn toàn đúng thương hiệu cho một cuộc gặp khách hàng. Không cần kỹ năng thiết kế, không cần mạng, không chờ đợi.

"Biểu đồ mới" ở bước hai là một bản kết xuất như thế này, được tạo ra từ một chuỗi dữ liệu và vài tham số mà không ai mở file thiết kế:

Một biểu đồ vùng xếp chồng có tiêu đề, ba chuỗi dữ liệu của nó được tô theo dải màu lạnh, với trục, chú giải và tiêu đề đều được đặt bởi mẫu (template) chứ không phải thủ công signed by Lollyvector SVG15 paths~1.3k nodes4 groups20 KBTự kiểm chứngTải tệp đã kýMột biểu đồ vùng xếp chồng có tiêu đề, ba chuỗi dữ liệu của nó được tô theo dải màu lạnh, với trục, chú giải và tiêu đề đều được đặt bởi mẫu (template) chứ không phải thủ công signed by Lollyvector SVG15 paths~1.3k nodes4 groups20 KBTự kiểm chứngTải tệp đã ký

Điểm mấu chốt không phải là Lolly tốt cho nhà thiết kế và tốt cho nhà phát triển và tốt cho bán hàng, mỗi thứ trong khoảng chân không riêng. Đó là một cuộc chạy tiếp sức: công việc ban đầu của người sáng tạo được nhà phát triển mở rộng, từ đó trao quyền cho nhà sản xuất. Trải nghiệm không tốn công cho đại diện phi kỹ thuật trên máy bay chỉ khả thi nhờ vào sự nghiêm ngặt mà nhà thiết kế đặt ra và nhà phát triển triển khai.

Đó là bộ khuếch đại lực. Lolly không phải một ngăn kéo các công cụ riêng lẻ cho từng vai trò riêng lẻ - mà là một vòng đời tài sản tất định duy nhất mà mọi vai trò đều chạm vào, và mỗi bàn tay nó đi qua nhân lên giá trị của bàn tay trước đó.


Một công cụ, nhiều kết quả

Các quy tắc thương hiệu nằm trong công cụ, chứ không phải trong từng file mà nó tạo ra (xem Lolly so sánh thế nào). Làm đúng công cụ một lần và mọi đầu ra đều thừa hưởng cùng kiểu chữ, màu sắc và khoảng cách, cho dù đó là một thẻ hay một bảng tính gồm nhiều hàng bằng hàng chục ngôn ngữ. Cách bạn kiểm tra công việc của mình, và ai làm việc đó, vẫn là việc của bạn; Lolly chỉ làm cho thứ cần kiểm tra nhỏ hơn và việc tạo ra đầu ra nhanh hơn.

Cùng một công cụ tất định đạt tới quy mô đó theo ba cách, tất cả đều cho ra đầu ra giống hệt nhau:

Chế độ Batch trên một bản cài đặt mới: một hàng trống đang chờ một công cụ, với toàn bộ bề mặt bảng tính và nút Render đã sẵn sàng trước khi có bất kỳ dữ liệu nào signed by Lollyvector SVG133 paths~15k nodes185 groups1 image195 KBTự kiểm chứngTải tệp đã kýChế độ Batch trên một bản cài đặt mới: một hàng trống đang chờ một công cụ, với toàn bộ bề mặt bảng tính và nút Render đã sẵn sàng trước khi có bất kỳ dữ liệu nào signed by Lollyvector SVG133 paths~15k nodes185 groups1 image195 KBTự kiểm chứngTải tệp đã ký

Một bộ ràng buộc thương hiệu duy nhất, được một nhà thiết kế ấn định một lần; ba con đường dẫn tới cùng một đầu ra.


Bức tranh toàn cảnh: các lớp khớp với nhau ra sao

Mọi thứ từ đây trở xuống là kiến trúc. Sơ đồ là toàn bộ hệ thống trong một cái nhìn: các công cụ là dữ liệu ở trên cùng, engine ở giữa không biết gì về bất kỳ nền tảng nào, các shell bên dưới nó triển khai một hợp đồng duy nhất, và các catalog cung cấp nội dung.

                ┌─────────────────────────────────────────────┐
                │              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   │
                └─────────────────────────────────────────────┘

Bố cục kho mã

Lolly là một kho lưu trữ (repository) duy nhất. engine/, schemas/, scripts/, tests/, api/, docs/, community/, brands/lolly-start/, mọi shells/ và cả hai services/ đều là các thư mục thông thường trong đó. Ngoại lệ duy nhất là brands/suse, một submodule git riêng tư chứa gói công cụ và catalog của SUSE, cần đăng ký tham gia và không có trong bản sao công khai. Bộ gói mà một bản build cụ thể đọc là một hồ sơ nội dung (content profile, profiles.json), được xác định theo từng tiến trình chứ không chuyển đổi toàn cục. Xem Build Guide » Getting the source để biết lệnh clone và cách một thay đổi bên trong gói riêng tư được commit.

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 + positioning

Mô hình triển khai nền tảng

Nền tảng chạy trên nhiều bề mặt - PWA web, Tauri desktop/mobile, CLI có thể viết script và TUI tương tác. Tất cả đều dùng cùng một engine và cùng các file công cụ.

Web (PWA) - phân phối chính

Được lưu trữ tại một URL do SUSE kiểm soát. Hoạt động offline khi service worker đã cache công cụ và tài sản. Đây là nơi phần lớn nhân viên, nhà cung cấp và đối tác sẽ dùng nền tảng. Không cần tài khoản - trạng thái được lưu trong IndexedDB theo từng thiết bị.

Shell web đáp ứng đa thiết bị từ một bố cục duy nhất. Trên desktop, một công cụ là một thanh bên điều khiển có thể đổi cỡ bên cạnh một sân khấu xem trước với điều hướng canvas gốc trackpad (Cmd/Ctrl-cuộn hoặc chụm để thu phóng quanh con trỏ, Space- hoặc kéo bằng nút giữa để lia, các phím 0/1/+/− và một HUD Fit/%). Trên di động (≤640px), các điều khiển trở thành một tấm neo trên cùng với một tay cầm kéo tự khớp vào peek/half/full (chạm để chuyển đổi) phủ trên một bản xem trước toàn màn hình tĩnh, và một nút Render nổi mở các điều khiển Export trong một popup dạng tấm dưới. Chạm nhận chụm-thu phóng và kéo-lia trên bản xem trước. Đường kết xuất và các điều khiển xuất giống hệt nhau trên cả hai - chỉ phần khung giao diện là bố trí lại.

Chế độ chia đôi trên desktop - các control được tạo từ manifest ở bên trái, canvas trực tiếp ở bên phải signed by Lollyvector SVG131 paths~6.1k nodes158 groups1 image142 KBTự kiểm chứngTải tệp đã ký

Cùng một công cụ ở độ rộng điện thoại, không cần duy trì layout thứ hai: các control trở thành một sheet ở phía trên, bản xem trước chiếm toàn màn hình và nút render nổi trên đó.

Một audiogram trên màn hình rộng 430px - bảng điều khiển ở trên, tác phẩm vuông hoàn chỉnh ở dưới và viên (pill) kết xuất nổi signed by Lollyvector SVG97 paths~3.3k nodes113 groups99 KBTự kiểm chứngTải tệp đã kýMột audiogram trên màn hình rộng 430px - bảng điều khiển ở trên, tác phẩm vuông hoàn chỉnh ở dưới và viên (pill) kết xuất nổi signed by Lollyvector SVG97 paths~3.3k nodes113 groups100 KBTự kiểm chứngTải tệp đã ký

Chế độ hàng loạt (/pro). Web shell cũng đi kèm một lưới hàng loạt kiểu bảng tính (shells/web/src/pro/) render nhiều hàng cùng lúc trên một hoặc nhiều công cụ. Nó hỗ trợ chuyển đổi qua lại CSV/TSV cộng với dán từ bảng tính, template/format/kích thước/đơn vị/dpi theo từng hàng, một side panel blocks-editor với bản xem trước trực tiếp, các cột export có thể thu gọn, một thanh nhãn "mức độ liên quan" theo từng hàng, sắp xếp lại hàng bằng tay kéo bên trái, xác nhận xóa hai bước, các phiên hàng loạt đã lưu và tải xuống dạng .zip. Đây là bề mặt một-đến-nhiều đứng sau định vị "tạo nội dung hàng loạt".

Tauri desktop / mobile

Ứng dụng native đóng gói (dung lượng nhỏ nhờ Tauri). Cung cấp khả năng hoạt động offline đầy đủ, quyền truy cập hệ thống tệp cho các công cụ phụ thuộc CLI (PDF Smasher, Font Outliner) và quyền truy cập camera. Dự kiến nâng cấp công cụ vào giữa 2026.

CLI

lolly <tool-id> [--input=value ...] --output=file.png

Người dùng desktop có thể gọi nhiều công cụ từ terminal. CLI shell tải cùng một engine, tạo một DOM jsdom, chạy cùng render path và ghi tệp. URL mode chính là lớp vận chuyển - CLI không phải là một cài đặt riêng biệt. Điều này đảm bảo đầu ra của CLI và GUI giống hệt nhau.

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

pnpm run tui

Phiên bản tương tác song hành với CLI: một ứng dụng terminal toàn màn hình, ưu tiên bàn phím (xây trên Ink) để duyệt công cụ, điền input, lưu dự án và export - tất cả không cần GUI. Host bridge của nó tái sử dụng cài đặt của CLI cho các định dạng không cần DOM (SVG/EMF/EPS/HTML + text/data), và bổ sung state trên đĩa dưới ~/.lolly cùng bản xem trước nội tuyến tùy chọn. Ngoài ra nó còn có một lớp render trình duyệt: một Chromium headless phạm vi hẹp (cùng bản mà MCP server cài đặt) tạo ra raster/PDF/video và chụp URL trực tiếp theo yêu cầu - vận hành một bản build của web shell nên đầu ra giống hệt nhau, và chỉ khởi chạy khi bạn export định dạng đó lần đầu. Vì vậy url-shot (kèm crop + đổi màu + PDF/SVG vector) và mọi công cụ raster/pdf đều chạy được trong terminal. Xem hướng dẫn TUI.

Dù đang ở bề mặt nào, tab Capabilities của dashboard là bản đồ đầy đủ những gì nền tảng khai báo có thể làm, được nhóm lại và dễ đọc mà không cần mở bất kỳ công cụ nào.


Danh mục công cụ

Các công cụ được gắn thẻ category trong manifest để nhóm trong gallery.

Các hàng được liệt kê theo thứ tự phần trong gallery. Phần utility luôn hiển thị cuối cùng trong gallery (sau mọi danh mục khác, kể cả những danh mục tương lai) - đây là ngăn kéo "Offline Utilities" chạy trên thiết bị.

Danh mụcVí dụDự kiến
everyoneQR Code Generator, Quote Card, Email Signature, Logo, Wordmark, Audiogram, Battlecards, Sequence, RecordEmployee Image Stationery
designerBrand Lockup, Design, Chart, Darkroom, Filter, Pose Geeko, BookletFont Outliner
eventMeeting Planner, Event Name Badge, Wayfinding Signage, Calendar ICS, Booth StudioEvent Stationery, Bulk Name Badges, Room Agenda Cards
product-CVE Alert, Product Release Announcement, Blog OG Image
utilityStrip Hidden Data, Text, Compress PDF, Convert Image, Convert Font, Redact, Run Web Code, Screen Capture, URL ScreenshotUnit/format converters, more on-device privacy utilities

Các ô đó là ví dụ, không phải danh mục đầy đủ. Những công cụ nào tồn tại là thuộc tính của profile bạn đã mount, không phải của trang này: một brand pack thêm công cụ riêng của nó, và có thể loại trừ một công cụ cộng đồng mà nó không muốn phân phối. catalog/tools/index.json - được tạo ra từ các manifest, và là registry mà gallery thực sự đọc - là danh sách chính thức; để đếm những gì một profile mount, hãy đếm các manifest (ls community//tool.json brands//tools/*/tool.json) thay vì tin vào một con số ghi ở đây. (Một tool id xuất hiện trong hai pack chỉ mount một lần, từ pack thắng.)

Các công cụ cũng được phân loại theo status: official (được brand phê duyệt, không watermark), community (đóng góp bên ngoài), experimental (export có watermark). Phần lớn thư viện là official; các studio mới hơn và các công cụ chụp thường ở mức community hoặc experimental trong khi ổn định dần. Mọi bề mặt đều hiển thị badge, để người đọc biết mình đang lấy gì trước khi mở nó - và, giống như các ô danh mục ở trên, số lượng thành viên theo status thay đổi quá nhanh để liệt kê ở đây. Hãy đọc trực tiếp từ gallery hoặc index được tạo ra.

Design là công cụ đầu tiên xây trên chế độ canvas tự do render.layout: "editor" - một bề mặt thao tác trực tiếp, không khung viền, nơi bạn kéo, thay đổi kích thước, xoay và snap các hộp văn bản, hình dạng và hình ảnh, rồi export qua cùng render path như mọi công cụ khác.

Strip Hidden Data là tiện ích chạy trên thiết bị (on-device) đầu tiên (privacy: "on-device"): một công cụ biến đổi nội dung nhận một tệp do bạn cung cấp, xử lý toàn bộ ngay trong trình duyệt và trả lại một bản sao sạch - không bao giờ được tải lên, không bao giờ bị đóng watermark, không đóng dấu nguồn gốc (provenance). Text là tiện ích thứ hai - một không gian làm việc trên thiết bị cho các tác vụ dán-vào-một-trang-web hàng ngày (định dạng JSON, giải mã JWT, Base64, mã hóa/giải mã URL, băm SHA). Compress PDF là tiện ích thứ ba - nó thu nhỏ một tệp PDF bằng cách nén lại hình ảnh bên trong, cũng hoàn toàn trên thiết bị. Điểm đánh dấu và văn bản trên huy hiệu của nó "Chạy trên thiết bị của bạn - không có gì được tải lên" giờ đây bao phủ toàn bộ nhóm biến đổi: Strip Hidden Data, Text, Compress PDF, Convert Image (HEIC/TIFF/AVIF → WebP/JPG/PNG), Convert Font, Redact (xóa bỏ các vùng của một hình ảnh, SVG hoặc PDF), Prompt Card và Rebrand (đổi giao diện thương hiệu của một tệp .pptx tại chỗ) ở những hồ sơ (profile) có tích hợp nó. Đây là một danh mục tiện ích bảo mật thay thế cho việc giao các tệp bảo mật cho các trang web chuyên biệt đơn lẻ.

Ngăn kéo Utilities, nơi mỗi thẻ là một công cụ chuyển đổi một tệp bạn đã có sẵn signed by Lollyvector SVG124 paths~29k nodes324 groups395 KBTự kiểm chứngTải tệp đã kýNgăn kéo Utilities, nơi mỗi thẻ là một công cụ chuyển đổi một tệp bạn đã có sẵn signed by Lollyvector SVG124 paths~29k nodes324 groups396 KBTự kiểm chứngTải tệp đã ký

Lưu ý: category và status được phi chuẩn hóa (denormalised) vào catalog/tools/index.json (registry mà gallery đọc) từ mỗi tool.json. Manifest là nguồn thông tin gốc (source of truth) - chỉ mục (index) được tạo ra bởi pnpm run build:catalog và pnpm run validate:catalog sẽ khiến CI thất bại nếu chỉ mục đã commit lệch khỏi các manifest.


Cam kết kiến trúc

Những quyết định này đã được chốt. Thay đổi bất kỳ cái nào cũng là một việc lớn - chúng định hình mọi quyết định khác trong codebase.

1. Công cụ khai báo, kèm lối thoát mệnh lệnh

Một công cụ là một manifest (tool.json) + một template (template.html) + hooks.js tùy chọn.

Manifest khai báo các input. Không phải template. Các input không được suy ra từ token Handlebars. Manifest là hợp đồng; template tiêu thụ các biến được đặt tên qua {{id}}.

Chồng control của Street Map - một dropdown thành phố, một select theme, các slider độ dày và các trigger màu, mỗi cái đều được vẽ từ một dòng manifest signed by Lollyvector SVG39 paths~2.6k nodes54 groups2 images43 KBTự kiểm chứngTải tệp đã kýChồng control của Street Map - một dropdown thành phố, một select theme, các slider độ dày và các trigger màu, mỗi cái đều được vẽ từ một dòng manifest signed by Lollyvector SVG39 paths~2.6k nodes54 groups2 images43 KBTự kiểm chứngTải tệp đã ký

Hooks là tùy chọn. Phần lớn công cụ hoàn toàn khai báo - manifest + template là đủ. Các công cụ cần giá trị tính toán (mã hóa QR, tạo hình dữ liệu biểu đồ) cung cấp hooks.js để lộ ra các hàm vòng đời được đặt tên (onInit, onInput, onFrame - hook camera trực tiếp theo từng khung hình cho các công cụ phản ứng chuyển động - onLevel, beforeExport, afterExport, exportFile - đường chuyển đổi file-vào/file-ra dùng bởi các tiện ích trên thiết bị như Strip Hidden Data - và exportStill, cho một công cụ tự sở hữu bản raster độ sâu riêng). Host tải hooks qua new Function('host', …) với capability bridge được tiêm vào làm closure scope. Đây là một hợp đồng khả chuyển, không phải một sandbox bảo mật: hooks vẫn chạy trong realm của trang và có thể truy cập window/fetch/document trong một web shell - host. là bề mặt được hỗ trợ, khả chuyển, chứ không phải một ranh giới được thực thi. Kết quả hook bất đồng bộ có giới hạn thời gian (onInit 5s, onInput 2s, beforeExport/afterExport 5s, exportFile/exportStill 10s) và kết quả đến trễ bị loại bỏ; một hook đồng bộ* chạy vượt thời gian không thể bị ngắt trước. Do đó mã hook bên thứ ba chưa tin cậy không an toàn để chạy cho đến khi cách ly Worker được triển khai.

Điều này quan trọng vì: công cụ khai báo có thể được người không lập trình tạo ra. Nếu mỗi công cụ đều là một ứng dụng web, ghi chú rủi ro "kỹ năng hạn chế để tạo/duy trì các template chủ lực" sẽ trở thành một nút thắt cổ chai vĩnh viễn.

2. Công cụ và asset là dữ liệu, không phải mã đóng gói

Ứng dụng web và Tauri lấy các catalog công cụ và asset từ một URL đã biết khi khởi động, cache chúng cục bộ và vận hành trên bất cứ thứ gì có ở đó. Thêm một ô sự kiện mới hoặc asset theo mùa không cần một bản phát hành ứng dụng.

Byte của asset được kiểm tra checksum SHA-256 để ngăn chặn đầu độc CDN. id + version của asset điều khiển việc vô hiệu hóa cache.

3. Capability Bridge là API duy nhất mà công cụ thấy được

Công cụ không bao giờ chạm vào DOM ngoài khu vực template của nó, không bao giờ gọi fetch trực tiếp, không bao giờ đọc hệ thống tệp. Chúng gọi các phương thức host.* đã được đánh version. Định nghĩa chính thức của hợp đồng là packages/core/src/host-v1.ts - SDK dành cho tác giả công cụ @lolly-tools/core, để bên thứ ba có thể xây dựng dựa trên nó mà không cần phụ thuộc vào engine; engine/src/bridge/host-v1.ts là một bản re-export kiểu (type) của nó, và mã engine/shell vẫn import từ đường dẫn đó không đổi:

API BridgeChức năng
host.profileTên riêng, email, ảnh chân dung, thành phố của người dùng, v.v. Điền sẵn input qua bindToProfile.
host.assetsTruy vấn catalog, phân giải asset, giao diện chọn asset do host cung cấp.
host.stateLưu / tải các slot input. IndexedDB trên web, hệ thống tệp trên Tauri, bộ nhớ trên CLI.
host.clipboardGhi văn bản hoặc hình ảnh vào clipboard (kèm dự phòng theo nền tảng).
host.exportChuyển đổi thành raster hoặc tuần tự hóa mục tiêu render. Áp dụng watermark cho các công cụ experimental.
host.netFetch có danh sách cho phép - chỉ khả dụng nếu công cụ khai báo capability "network". (Hiện chưa có công cụ nào đang phân phối sử dụng nó.)

Các bề mặt tùy chọn, bổ sung chỉ xuất hiện khi một shell cung cấp chúng. Một số được khóa theo capability - chỉ lộ ra khi công cụ khai báo cờ tương ứng: host.compose (nhúng render của công cụ khác - compose), host.capture (chụp trang cho URL Screenshot - capture) và host.recorder (chụp mic/camera/màn hình cho các công cụ ghi âm/ghi hình - microphone / camera / screen). Phần còn lại được phát hiện theo tính năng - có mặt bất cứ khi nào shell có thể cung cấp chúng, với công cụ giữ một phương án dự phòng cho các shell không thể.

Một vài bề mặt tiêu biểu, để cho thấy phạm vi bao phủ - Host API ghi lại từng cái một, và packages/core/src/host-v1.ts chính là hợp đồng:

SurfaceTừ phiên bảnNó thêm gì
host.tokens1.0Design token DTCG - các nguyên tố (primitives) riêng của thương hiệu
host.text1.0Chuyển văn bản thành path qua HarfBuzz WASM (cờ khả năng wasm đánh dấu các công cụ phụ thuộc vào nó)
host.media1.4Khung hình camera trực tiếp điều khiển hook onFrame. Tăng cường tiệm tiến, cố tình không bị chặn bởi cờ camera - một công cụ như vậy vẫn hoạt động như một công cụ ảnh tĩnh thông thường
host.color1.40Toán học màu theo tri giác: ΔEOK, độ tương phản WCAG + APCA, dải màu OKLab, class-break, bảng màu phân loại, sơ đồ hài hòa (1.60), pha trộn CSS Color 4 và bake gradient (1.68). Thuần túy và đồng bộ - các shell gắn makeColorApi() của engine thay vì tự triển khai bất cứ điều gì, nên nó không thể trôi lệch
host.images1.60Giải mã / thay đổi kích thước / mã hóa lại byte ngay trên thiết bị - đường chuyển đổi (HEIC → JPEG, nén sang WebP, giảm kích thước). Được cung cấp trong web shell dưới dạng một lazy facade, nên bộ giải mã HEIC không bao giờ vào chunk khởi động
host.geom1.64Hình học vector chính xác: phép toán boolean trên path, offset, chuyển nét thành fill, hạ cấp spline, đơn giản hóa, kiểm tra va chạm (hit testing). Cũng thuần túy, đồng bộ và được gắn từ engine (makeGeomApi()); lỗi được trả về, không bao giờ ném ra (throw)

Phần còn lại tuân theo cùng quy tắc và được ghi lại cùng với chúng: pdf (1.8) và pptx (1.58) cho phẫu thuật tài liệu trên thiết bị, audio (1.71) và speech (1.96) cho phân tích clip và TTS/phiên âm trên thiết bị, viz (1.72) cho hợp đồng placeholder MilkDrop, codec (1.100) và layers (1.102) cho đầu ra bit sâu và bitmap phân lớp, upscale (1.101) và matte (1.103) cho các model trên thiết bị, raster (1.105) cho các hook tự xử lý pixel riêng, connectors (1.106) cho mũi tên an toàn khi export và c2pa (1.85) để ký byte đã hoàn tất. Số lượng tăng lên; quy tắc thì không.

Các capability có thể khai báo là: network, filesystem, clipboard, camera, microphone, screen, ffmpeg, wasm, capture, compose. (screen, được thêm ở 1.54, là chụp màn hình qua host.recorder - người dùng chọn một màn hình/cửa sổ/tab trong giao diện gốc của trình duyệt; khác với capture, vốn render một URL do chính công cụ đặt tên.)

Cùng một công cụ chạy trên trình duyệt, Tauri và CLI headless vì mỗi shell cài đặt giao diện này - công cụ không bao giờ biết nó đang ở đâu.

Bridge được đánh version. Thêm phương thức là một minor version. Xóa hoặc thay đổi chữ ký là một bước nhảy major version. Khi v2 ra mắt, v1 phải tiếp tục hoạt động.

4. Asset ID là vĩnh viễn

suse/logo/primary là một hợp đồng. Khi đã xuất bản:

Điều này khiến các trạng thái công cụ đã lưu và các liên kết chia sẻ qua URL bền vững qua nhiều năm.

5. URL mode là hạng nhất

Mọi input phải có thể biểu diễn được dưới dạng tham số URL:

lolly.tools/#/tool/qr-code?url=https://suse.com&ecl=H

Riêng liên kết đó, không kèm gì khác, chính là tác phẩm hoàn chỉnh signed by Lollyvector SVG55 paths~2.6k nodes38 groups60 KBTự kiểm chứngTải tệp đã kýRiêng liên kết đó, không kèm gì khác, chính là tác phẩm hoàn chỉnh signed by Lollyvector SVG55 paths~2.6k nodes38 groups61 KBTự kiểm chứngTải tệp đã ký

Chế độ CLI chính là URL mode dưới một lớp vận chuyển khác - CLI shell dựng một đối tượng trạng thái URL từ argv và chạy cùng pipeline engine. Chỉ có một render path. CLI không thể lệch khỏi GUI vì nó không phải là một cài đặt riêng biệt.

url-mode.ts xử lý việc chuyển đổi qua lại (parse và serialize). Một tập các tham số dành riêng không bao giờ được chuyển tới công cụ dưới dạng input: các control đầu ra (format, export, copy, filename, width/w, height/h, unit, dpi), các nút xoay in ấn và nguồn gốc (bleed, marks, profile, password, c2pa, imprint, durable, meta, hdr, depth, cuts) và các thành phần mang trạng thái (template, z - token đóng gói "Liên kết ngắn nhất" - và zx, cùng loại đó nhưng được mã hóa dưới một mật khẩu). Tập RESERVED trong engine/src/url-mode.ts là nguồn thẩm quyền và được một bài test ghim chặt; URL Mode ghi lại từng tham số một, kể cả một vài cái không liệt kê ở đây. Các input asset trong URL mode được tuần tự hóa theo id của chúng; runtime phân giải chúng qua host.assets.get() trước khi hydrate. width/height là các giá trị theo unit (mặc định px, cũng có mm/cm/in/pt/pc); với đơn vị vật lý, dpi đặt độ phân giải raster. Chúng đặt kích thước tài liệu của canvas và điền sẵn bảng kích thước export.

Vì mọi input đều đi theo trong liên kết, một thay đổi tham số là một tác phẩm hoàn chỉnh khác. Toàn bộ bảng màu này chỉ là một màu gốc, một sơ đồ hài hòa và một số bước:

Chín bước qua bốn tông màu, tất cả đều lớn lên từ một màu hạt giống duy nhất mang trong liên kết signed by Lollyvector SVG10 groups25 KBTự kiểm chứngTải tệp đã kýChín bước qua bốn tông màu, tất cả đều lớn lên từ một màu hạt giống duy nhất mang trong liên kết signed by Lollyvector SVG10 groups25 KBTự kiểm chứngTải tệp đã ký

6. Lưu trữ đi qua cầu nối, không truy cập trực tiếp

Web shell: IndexedDB. Tauri: hệ thống tệp. CLI: trong bộ nhớ. Các công cụ chỉ thấy host.state.save(slot, data) và host.state.load(slot). localStorage không được dùng - nó quá nhỏ và không thể chứa blob.

Người dùng có thể lưu nhiều vị trí chỉnh sửa có tên riêng cho mỗi công cụ và quay lại từng phiên sau đó. Không cần tạo tài khoản; trạng thái là theo từng thiết bị. Vì bridge là điểm nối duy nhất, trạng thái theo thiết bị đó cũng có thể mang đi được: shells/web/src/data-transfer.ts đọc lại mọi thứ qua host.profile/host.state/host.assets thành một tệp zip lolly-backup duy nhất, nhập được vào bất kỳ bản cài đặt nào khác - câu trả lời ngoại tuyến cho việc "chuyển sang thiết bị mới" mà không cần máy chủ (đặc tả đầy đủ: docs/data-transfer.md). Đồng bộ đa thiết bị đã chạy trên nền này, gửi cùng một gói đến nơi lưu trữ mà người dùng chọn (docs/sync.md).

7. Nhãn độ trưởng thành cho biết một công cụ là gì

Mỗi công cụ khai báo status: official | community | experimental trong manifest của nó. Gallery sắp xếp theo status. Các công cụ thử nghiệm tự động đóng dấu bản quyền (watermark) khi xuất - watermark được áp dụng bởi host.export.render, không phải bởi công cụ, nên tác giả của một công cụ không chính thức không thể tắt nó.

Đây là câu trả lời mang tính cấu trúc cho rủi ro nhận thức rằng mọi công cụ trong gallery đều mang trọng lượng như nhau. Bất kỳ quy trình nào một đội nhóm đặt quanh danh mục đều xếp chồng lên trên đó.

8. Đầu vào của công cụ được định kiểu qua manifest, kể cả tài sản

Các đầu vào khai báo một type: text, longtext, number, boolean, color, select, asset, date, time, datetime-local, url, blocks, vector, table và file. Host hiển thị một control chung cho mỗi loại từ manifest - các công cụ không viết bất kỳ mã control nào. (Tự điền sẵn từ hồ sơ người dùng không phải là một loại - bất kỳ đầu vào nào cũng có thể mang bindToProfile.) Ba loại mang trọng lượng hơn các loại còn lại:

9. Template không chứa logic (Handlebars, không phải EJS)

Handlebars được chọn thay cho EJS một cách có chủ đích:

Logic nằm trong hooks.js, nơi nó rõ ràng và có thể xem xét được. Các helper Handlebars có sẵn: {{default}}, {{upper}}, {{lower}}, {{eq}}, {{markdown}}, {{asset ref}}, {{asset ref "property"}} (cùng các helper định dạng dữ liệu icsStamp/rfcText/csvCell dùng bởi các template .ics/.vcf/.csv song hành).

10. Công cụ ghép công cụ

Một công cụ có thể nhúng bản kết xuất của một công cụ khác mà không cần import công cụ-tới-công cụ - việc ghép được engine giải quyết, không bao giờ do mã của công cụ. Có hai bề mặt:

Ghép bản kết xuất của bất kỳ công cụ nào: một công cụ con SVG vẫn giữ nguyên là vector thật khi công cụ cha xuất sang SVG hoặc PDF và rasterize sắc nét cho PNG; công cụ con PNG/JPG/WEBP nhúng dưới dạng hình ảnh. Yêu cầu khả năng compose. Các công cụ con được ghép là trung gian - không bao giờ bị đóng watermark hay đóng dấu nguồn gốc - và việc ghép suy giảm một cách nhẹ nhàng: một shell không thể kết xuất một công cụ con chỉ đơn giản bỏ qua slot đó và công cụ cha vẫn kết xuất.


Những gì chúng tôi cố tình chọn không làm


Vòng đời của một lượt render

Một người dùng mở lolly.tools/#/tool/qr-code?url=https://suse.com&ecl=H:

  1. Khởi động (Boot). Web shell mở IndexedDB, khởi tạo capability bridge, đồng bộ catalog công cụ và tài sản (asset) (hoặc tải từ cache khi ngoại tuyến).
  2. Định tuyến (Route). URL hash → view tool, với qr-code và các tham số URL được trích xuất.
  3. Tải (Load). loadTool('qr-code', fetchFile) lấy tool.json, xác thực theo JSON Schema, lấy template.html, styles.css và mã nguồn hooks.js.
  4. Phân tích trạng thái URL. parseUrlState chuyển các tham số URL thành giá trị đầu vào ban đầu. Các tham chiếu tài sản (asset ref, ?logo=suse/logo/primary) được phân tích thành các đối tượng nhẹ { id, _unresolved: true }.
  5. Runtime. createRuntime(tool, host, initialValues) xây dựng mô hình đầu vào (input model) (hợp nhất dữ liệu hồ sơ, giá trị mặc định và giá trị ban đầu), phân giải các tham chiếu tài sản qua host.assets.get(), tải các hook (host nằm trong closure-scope, không phải sandbox), gọi hooks.onInit.
  6. Kết xuất (Render). Shell đăng ký (subscribe) với runtime; mỗi khi trạng thái thay đổi, nó nhận { model, hydrated }. Nó kết xuất các điều khiển đầu vào từ model và ghi HTML của template đã được hydrate vào #tool-canvas.
  7. Tương tác. Người dùng gõ vào một trường đầu vào → runtime.setInput(id, value) → áp dụng các ràng buộc → gọi hooks.onInput → hydrate lại → kết xuất lại. Canvas cập nhật theo thời gian thực.
  8. Xuất (Export). Người dùng nhấp Download(PNG) → runtime.export(canvasNode, 'png') → host.export.render (raster hóa qua dom-to-image-more; SVG/PDF đi qua các bộ vector hóa (vectoriser) chuyên dụng duyệt DOM) → blob → host.export.download. Phạm vi định dạng mà một công cụ có thể chọn tham gia rất rộng, và enum render.formats trong schemas/tool.schema.json là nguồn thẩm quyền cho việc này - ảnh raster và raster dấu phẩy động, vector và tệp cắt (cut file), in ấn/CMYK, chuyển động (motion), tài liệu có thể chỉnh sửa (pptx, docx, odt), bảng màu (palette) và đầu ra dữ liệu/văn bản, âm thanh và tệp phông chữ. URL Mode liệt kê từng id và những gì nó tạo ra. Âm thanh nằm trong enum đó như mọi thứ khác (wav, mp3, m4a, opus, được khai báo bởi audiogram và các công cụ ghi âm); riêng biệt, chế độ render.capture của một công cụ ghi âm điều khiển host.recorder, có bản ghi đến dưới dạng một Blob hoàn chỉnh trong bất kỳ container nào mà trình duyệt đã ghi. (Các công cụ đặt render.export: false - ví dụ Color Palette, Countdown Timer, Strip Hidden Data, Text, Compress PDF - ẩn các điều khiển tải xuống/định dạng/kích thước.) Đơn vị vật lý được chuyển đổi theo từng định dạng ở đây (PDF → điểm trang thực, raster → pixel theo DPI kèm khối pHYs). Siêu dữ liệu tác giả/nguồn gốc (author, tool, source - được xây dựng bởi engine/src/metadata.ts) được nhúng theo từng định dạng: PNG iTXt, JPEG EXIF, PDF info dict, SVG <metadata>, GIF comment. Các công cụ thử nghiệm (experimental) sẽ được host chèn watermark, không phải do công cụ tự làm.

Bảng xuất mà ?options mở ra: cặp tên tệp và định dạng, kích thước đầu ra và các control ghi tệp signed by Lollyvector SVG77 paths~6.0k nodes87 groups3 images88 KBTự kiểm chứngTải tệp đã kýBảng xuất mà ?options mở ra: cặp tên tệp và định dạng, kích thước đầu ra và các control ghi tệp signed by Lollyvector SVG77 paths~6.0k nodes87 groups3 images88 KBTự kiểm chứngTải tệp đã ký

Cùng vòng đời trong Tauri. Cùng vòng đời trong CLI - jsdom cung cấp DOM không giao diện; đầu ra đi vào một tệp hoặc stdout.


Trạng thái mã nguồn mở

Mã nguồn theo giấy phép MPL-2.0. engine/, shells/, services/, schemas/ và docs/*.ts là mã nguồn mở theo MPL-2.0 - một nền tảng khung sườn (scaffolding) trung lập với nhà cung cấp cho công cụ thương hiệu, tất cả nằm trong một kho lưu trữ công khai duy nhất, lolly-tools/lolly.

Nội dung công cụ được phân phối dưới dạng các gói thương hiệu (brand pack), mỗi gói có điều khoản riêng (xem NOTICE.md của gói). community/ là một thư mục của kho lưu trữ này và các công cụ trung lập về thương hiệu (brand-agnostic) của nó cũng theo MPL-2.0. brands/suse/ là gói riêng tư suse-lolly, submodule duy nhất: các công cụ SUSE và catalog SUSE, thuộc sở hữu độc quyền của SUSE, bao gồm cả nhạc nền PremiumBeat đã được cấp phép. brands/lolly-start/ là thương hiệu khởi đầu trống mà kho lưu trữ này sở hữu. Phông chữ được phân phối bên trong một gói theo SIL Open Font License 1.1 - gói SUSE mang theo các kiểu chữ SUSE và SUSE Mono.

Không có thư mục tools/ hay catalog/ ở gốc kho lưu trữ. packages/node-shell/src/content-roots.ts trả lời câu hỏi "công cụ <id> nằm ở đâu" và "catalog ở đâu" từ profiles.json tại thời điểm đọc, vì vậy một hồ sơ (profile) là một câu trả lời theo từng tiến trình và không cần phải dựng sẵn cây thư mục trước. Một cặp tools/ + catalog/ thực sự chỉ được ghi ra trong một sản phẩm build - dist/, một payload RPM, một image container - vì trình duyệt lấy hai đường dẫn đó qua HTTP.

Sự tách biệt này được thực thi - không có import chéo nào từ engine/ vào nội dung công cụ - nên ranh giới giữa nền tảng và nội dung luôn gọn gàng.


Nơi engine kết thúc và host bắt đầu

Nếu bạn có thể mô tả nó bằng dữ liệu thuần túy + Handlebars → engine. Nếu nó chạm vào DOM, hệ thống tệp, mạng hoặc bất kỳ API trình duyệt/hệ điều hành nào → host.

Ranh giới này rõ ràng một cách có chủ đích. Engine là phần mã nguồn mở. Mọi thứ biết về SUSE, các nền tảng cụ thể hay môi trường runtime đều nằm ngoài nó.

Để biết thêm chi tiết, engine/README.md liệt kê mọi module của engine và chức năng của nó, và Threat Model & Trust Boundaries ghi lại nơi cùng ranh giới đó cũng đóng vai trò là ranh giới tin cậy.