このページは、Lollyのコードを変更する人向けです。エンジン、シェル、ツールパックがどう組み合わさるか、それぞれがリポジトリのどこにあるか、あらゆる変更を縛る取り決めを説明します。Lollyが何をし、誰が使うのかを知りたい場合は、まずLollyの仕組みをお読みください。
さらに深く知るための補足が2つあります。engine/README.mdは、コードから生成されたエンジンのモジュールごとの地図です。脅威モデルと信頼境界は、同じアーキテクチャを信頼境界として読み解いたもので、エンジンが何を信頼できないものとして扱うかについての疑問に答えるページです。
全体像
最上位のツールはデータです。中間のエンジンはどのプラットフォームも知りません。最下位のシェルは1つの契約を実装し、カタログが内容を供給します。
純粋なデータとHandlebarsで記述できるなら、それはエンジンに属します。DOM、ファイルシステム、ネットワーク、あるいはブラウザやオペレーティングシステムのAPIに触れるなら、それはホスト、つまりブリッジのシェル側に属します。エンジンはオープンソースであり、特定のブランドやプラットフォームを知るものはエンジンに入りません。
リポジトリの構成
Lollyは1つのリポジトリです。以下のディレクトリはすべて、その中の通常のディレクトリですが、brands/suseは例外で、公開クローンが取得しない、SUSEのツールパックとカタログを収めた非公開のgitサブモジュールです。ビルドがどのパックを読むかはコンテンツプロファイル(profiles.json)で決まり、グローバルに切り替えるのではなく、プロセスごとに解決されます。クローンのコマンドと、非公開パックの中の変更をコミットする方法は、ビルドガイドにあります。
| ディレクトリ | 収めるもの |
|---|---|
engine/ | プラットフォームに依存しないコア: ローダー、ランタイム、入力、テンプレート、URLモード、単位、形式モジュール |
shells/ | Webアプリ、Tauriのデスクトップ・モバイルアプリ、CLI、TUI、ブラウザ拡張機能 |
packages/ | ツール作者向けSDK(@lolly-tools/core)、共有のNodeシェル部品、ドキュメントレンダラーなど |
community/ | ブランドに依存しないツールと、共有の絵文字パック |
brands/ | ブランドパック: lolly-demo(lolly.toolsが使うデザインシステムのLolly Demo)、lolly-start(空のスターター)、非公開のsuse |
services/ | 任意のMCP、証明書、Penpotのサービスと、それらが共有するサーバーコード |
schemas/ | ツールマニフェスト、アセットエントリ、アセット参照のJSON Schema |
scripts/、tests/、docs/、api/ | ビルドとカタログのスクリプト、エンジンのテストスイート、これらのドキュメント、生成されたサーバーレスバンドル |
最初に目にするエンジンとシェルのファイル
engine/src/
index.ts public surface: loader, runtime, template, inputs, url-mode
loader.ts fetches and validates tool files
runtime.ts orchestrates one mounted tool, from load to export
template.ts Handlebars hydration and annotateTemplate
inputs.ts manifest to runtime input model
url-mode.ts URL to input state and back
validate.ts JSON Schema validation of manifests
compose.ts nested tool renders (composes)
embed.ts portable lolly.tools embed URLs
bridge/host-v1.ts type re-export of the @lolly-tools/core contract
shells/web/src/
main.ts boot and routing
bridge/ the web implementations of the host APIs
catalog/sync.ts boot-time catalog sync and offline cache
views/ the gallery, tool, projects, free canvas and the other views
pro/ Batch (#/batch)
shells/cli/ bin/lolly.ts (entry), src/run.ts (headless render), src/bridge.ts
shells/tui/ src/main.tsx (the full-screen app), src/bridge.tsリポジトリのルートにtools/やcatalog/ディレクトリはありません。packages/node-shell/src/content-roots.tsが、profiles.jsonから、問われたときに「ツール<id>はどこにあるか」「カタログはどこにあるか」に答えます。実際のtools/とcatalog/の組が書き込まれるのは、dist/、RPMのペイロード、コンテナイメージなどのビルド出力だけです。ブラウザがその2つのパスをHTTPで取得するためです。
Lollyが動作する場所
どの環境も、同じエンジンと同じツールファイルを使います。
- Webアプリ。 サービスワーカーがツールとアセットをキャッシュした後はオフラインで動作するプログレッシブWebアプリです。アカウントは不要で、状態は各デバイスのIndexedDBにあります。1つのレスポンシブなレイアウトがデスクトップとスマートフォンに対応し、スマートフォンではコントロールがシートになり、書き出しコントロールはフローティングピルから開きます。
- デスクトップアプリとモバイルアプリ。 同じWebアプリのTauriパッケージで、ネイティブのファイルダイアログ、ファイルシステムによる状態、完全なオフライン利用を備えます。
- CLI。
lolly <tool-id> --input=value --output=file.pngは、ヘッドレスのDOMで同じエンジンを読み込み、ファイルを書き出します。これは別の実装ではなく、別の伝送路でのURLモードです。CLIをご覧ください。 - TUI。 全画面でキーボード中心のターミナルアプリで、CLIのブリッジを再利用し、保存したセッションをディスクに保持し(アプリがインストールされていればデスクトップアプリ自身のフォルダ、そうでなければ
~/.lollyの下)、形式がブラウザを必要とする場合にだけ、範囲を限定したヘッドレスブラウザを起動します。TUIをご覧ください。
signed by Lollyvector SVG131 paths~6.1k nodes158 groups1 image142 KBCheck it yourself署名済みファイルを取得
同じツールをスマートフォンの幅で表示しても、別のレイアウトは要りません。コントロールが上部のシートになり、プレビューが画面を占めます。
signed by Lollyvector SVG97 paths~3.3k nodes113 groups99 KBCheck it yourself署名済みファイルを取得
signed by Lollyvector SVG97 paths~3.3k nodes113 groups100 KBCheck it yourself署名済みファイルを取得
Webアプリには、Batch(#/batch、shells/web/src/pro/)も同梱されています。1つまたは複数のツールにわたって多数の行を一度にレンダリングする、スプレッドシート形式のグリッドで、BatchについてはBatchとMulti-editで扱っています。Settings → Capabilitiesには、プラットフォームができると宣言しているすべてのことの地図があります。
signed by Lollyvector SVG133 paths~15k nodes185 groups1 image195 KBCheck it yourself署名済みファイルを取得
signed by Lollyvector SVG133 paths~15k nodes185 groups1 image195 KBCheck it yourself署名済みファイルを取得
アーキテクチャ上のコミットメント
これらの決定は確定済みです。コードベースのあらゆる他の決定を形作っているため、どれを変更するにも大きな取り組みが必要です。
1. 宣言的なツール、命令的な逃げ道付き
ツールは、マニフェスト(tool.json)、テンプレート(template.html)、そして任意のhooks.jsです。マニフェストが入力を宣言し、テンプレートは宣言しません。入力はHandlebarsのトークンから推測されません。ほとんどのツールはマニフェストとテンプレートだけで、そのおかげで開発者でない人も作成できます。
signed by Lollyvector SVG39 paths~2.6k nodes54 groups2 images43 KBCheck it yourself署名済みファイルを取得
signed by Lollyvector SVG39 paths~2.6k nodes54 groups2 images43 KBCheck it yourself署名済みファイルを取得
QRのエンコードやグラフの整形など、値を計算するツールにはフックを追加します。これは、ケイパビリティブリッジが注入された状態でランタイムが呼び出す、名前付きのライフサイクル関数です。フックはセキュリティのサンドボックスではなく移植性の契約であり、時間の予算の範囲内で実行されます。フックがページのグローバルを使わないことが確認されたツールにはisolate: trueが付き、Workerで実行されます。ライフサイクルと予算はツールのフックに、ページ内の実行機構が何を封じ込め、何を封じ込めないかは脅威モデルに書かれています。
2. ツールとアセットはバンドルされたコードではなくデータである
WebアプリとTauriアプリは、起動時にツールとアセットのカタログを取得してキャッシュし、そこにあるもので動作するため、新しいツールやアセットのためにアプリのリリースは不要です。アセットのバイト列にはSHA-256のチェックサムが付き、アセットのidとversionがキャッシュの無効化を左右します。
3. ケイパビリティブリッジがツールの見る唯一のAPI
ツールは、テンプレートの外のDOMに触れず、fetchを直接呼ばず、ファイルシステムも読みません。バージョン付きのhost.*メソッドを呼び出します。契約の正式な定義は、ツール作者向けSDKの@lolly-tools/coreであるpackages/core/src/host-v1.tsにあり、第三者がエンジンに依存せずにこれに対してビルドできます。engine/src/bridge/host-v1.tsはその型を再エクスポートします。
| 必須API | 内容 |
|---|---|
host.profile | ユーザーの詳細。bindToProfileを通じて入力を自動入力する |
host.assets | カタログのクエリ、アセットの解決、ホストのピッカー |
host.state | 入力スロットの保存と読み込み: WebではIndexedDB、Tauriではファイルシステム、CLIではメモリ |
host.clipboard | テキストまたは画像をクリップボードに書き込む(プラットフォームごとの代替付き) |
host.export | レンダリング対象のラスタライズまたはシリアライズと、デバイス上のファイル変換経路 |
host.log | ホストへのレベル付きログ |
それ以外のAPIはすべて任意で追加的なものです。tokens、text、color、geom、pdf、compose、media、recorderなど多数があります。ツールのマニフェストは、フックが確認せずに呼び出す任意のAPIをrequiresに列挙し、それを欠くホストはツールのマウントを拒否します。残りについては、フックが機能を検出します。recorderなど一部は、ツールが宣言するデバイスのケイパビリティも必要とします。packages/core/src/host-v1/apis.tsにすべてが一覧されており、それぞれはHost APIに記載されています。メソッドの追加はマイナーバージョン、削除や変更はメジャーバージョンであり、v2が出てもv1は動作し続けます。
4. アセットIDは永久
lolly/logo/primaryは契約です。一度公開されたIDは変更されず、再利用もされません。バイト列の変更ではアセットエントリのversionが上がり、置き換えではdeprecated: trueと、必要に応じてreplacedByが設定されるため、既存の参照は常に解決されます。これが、保存したセッションと共有リンクが何年も動き続ける理由です。
5. URLモードはファーストクラスである
すべての入力はURLパラメーターとして表現できるため、リンクは完成したファイルです。
https://lolly.tools/t/qr-code?url=https://example.com&ecl=H signed by Lollyvector SVG55 paths~2.6k nodes38 groups60 KBCheck it yourself署名済みファイルを取得
signed by Lollyvector SVG55 paths~2.6k nodes38 groups61 KBCheck it yourself署名済みファイルを取得
パラメーターを変えると、別のファイルになります。このパレット全体は、1つのシード色、ハーモニー、ステップ数からできています。
signed by Lollyvector SVG10 groups25 KBCheck it yourself署名済みファイルを取得
signed by Lollyvector SVG10 groups25 KBCheck it yourself署名済みファイルを取得
CLIは、引数から同じURL状態を作って同じパイプラインを実行するため、CLIがアプリとずれることはありません。engine/src/url-mode.tsが解析とシリアライズを行い、予約された名前(format、width、dpi、c2pa、zなど)はツールに渡されません。すべては予約済みURLパラメーターに一覧があります。アセット入力はidで渡され、テンプレートが埋められる前にhost.assets.get()で解決されます。
6. ストレージはブリッジを通る
WebアプリはIndexedDB、Tauriはファイルシステム、CLIはメモリを使います。ツールに見えるのはhost.state.save(slot, data)とhost.state.load(slot)だけで、localStorageは使いません。アカウントなしで、ツールごとに名前付きの複数のセッションを保持できます。ブリッジが唯一の接点であるため、その状態は可搬でもあります。shells/web/src/data-transfer.tsがそれを1つのlolly-backupファイルに読み出し、他のどのインストールにもインポートできます(データ移行)。同期は、同じバンドルを利用者が選んだストレージに送ります。
7. 成熟度タグは、ツールが何であるかを示す
すべてのツールはstatus: official | community | experimentalを宣言します。ギャラリーはステータス順に並び、experimentalのツールは既定で書き出しに透かしを入れます。ランタイムは、呼び出し側がwatermark: falseを渡さないかぎり透かしをオンにし、デバイス上で動作するツールは対象外です。チームがカタログの周りにどんなプロセスを置いても、それはこの上に載ります。
8. 入力はマニフェストで型付けされる
入力はtypeを宣言します。text、longtext、number、boolean、color、select、asset、date、time、datetime-local、url、blocks、vector、table、fileのいずれかです。ホストは型ごとにコントロールを描画するため、ツールはコントロールのコードを書かず、どの入力にもbindToProfileを付けられます。特に重要なものが3つあります。
assetは、filterとallowUploadを持ち、アセットシステムへの橋渡しです。allowUpload: falseはスロットをライブラリのアセットに限定し、ユーザーのアップロードはライブラリのAssetRefと同じ形を共有します。blocksは、サイドパネルで編集する繰り返しのフィールドグループで、Meeting Planner、Wayfinding、Diagramsなどで使われます。描画されたブロックをクリックすると、その行にフォーカスが移ります。fileは、Strip Hidden DataやCompressなどのデバイス上のユーティリティのために、ユーザー自身のファイルをメモリに保持します。vectorは、固定個数の数値を1つのコントロールにまとめます。
9. テンプレートにロジックはない
テンプレートはHandlebarsで、開発者でない人にも書けるように選ばれています。{{x}}はエスケープされ、{{{x}}}は明示的なオプトインです。ロジックはhooks.jsにあり、明示的で、レビューできます。多くのテンプレートは、フックが計算したマークアップに{{{を使うため、各フックは渡すものをエスケープしなければなりません。ヘルパーはdefault、upper、lower、eq、markdown、asset、framing、mediaに加え、.ics、.vcf、.csvの兄弟テンプレート向けのicsStamp、rfcText、csvCell、arrowです。これらはテンプレートとレンダリングで扱っています。
10. ツールはツールを合成する
ツールは、ツール同士のインポートなしに、他のツールのレンダリングを埋め込めます。合成はエンジンが解決します。マニフェストはcomposes: [{ id, tool, inputs }]を宣言して子を{{asset <id>}}で配置でき、ポータブルな埋め込みURL(https://lolly.tools/tool/<id>.svg?…)が子をローカルでレンダリングします。DesignがライブのQRコードやグラフを配置するのは、この仕組みです。SVGの子は、SVGまたはPDFの親の中でもベクターのままです。子は中間生成物であり、透かしも署名も付かず、子をレンダリングできないシェルはそのスロットを空にしますが、親は引き続きレンダリングされます。詳細は合成とブランドオーバーレイにあります。
あえてやらないこと
- テンプレートに任意のJavaScriptは使わない。 ロジックは
hooks.jsにあります。 - 必須のアセットサーバーはない。 アプリ内のAssetsにご自身のファイルを追加し、作業はセッションとして引き継ぎます。入力と設定にはリンク、アップロードも運ぶ場合には
.lollyファイルを使います。共有セッションは、ツールの選択画面でテンプレートにできます。管理されたカタログを求める組織は、Lolly Workのカタログ、承認、ポリシーを使うか、gitでブランドパックを管理してそこで変更をレビューできます。 - 強制的なアクセス制御はない。 公開のアプリは既定で公開されており、成熟度タグと透かしがブランドのリスクを担います。組織のサインイン、ロール、ポリシーは、チームが望む場合にLolly Workから提供されます。
- 中央のデータベースはない。 ユーザーの状態は各デバイスにあり、任意の同期が、それを利用者が選んだストレージにコピーします。Lollyのデータベースにコピーされることはありません。
- ツールとエンジンの間で共有されるコードの経路はない。 エンジンとコミュニティツールはオープンソースで、非公開の
brands/suse/のようなブランドパックは、独自のツールとカタログを独自の条件で持ちます。どのツールもengine/からインポートしないため、分離はきれいに保たれます。
1回のレンダリングのライフサイクル
誰かがhttps://lolly.tools/t/qr-code?url=https://example.com&ecl=Hを開きます。
- 起動。 WebアプリはIndexedDBを開き、ケイパビリティブリッジを構築し、ツールとアセットのカタログを同期するか、オフラインならキャッシュから読み込みます。
- ルーティング。 パスが
qr-codeのツールビューを選び、クエリがその初期値になります。 - 読み込み。
loadToolがtool.jsonを取得してスキーマで検証し、テンプレート、スタイル、フックを取得します。 - リンクの解析。
parseUrlStateがパラメーターを入力値に変換します。?logo=lolly/logo/primaryのようなアセット参照は、未解決の{ id }になります。 - ランタイムの開始。
createRuntime(tool, host, initialValues)が、プロフィールデータ、既定値、リンクから入力モデルを構築し、アセット参照を解決し、フックを読み込んでonInitを呼び出します。 - レンダリング。 シェルはランタイムを購読し、モデルからコントロールを描画し、埋めたテンプレートを
#tool-canvasに書き込みます。 - 操作。 入力すると
runtime.setInputが呼ばれ、制約を適用し、onInputを呼び出し、テンプレートを再び埋めて再描画します。 - 書き出し。 Downloadが
runtime.export(node, format)を呼び、シェルのhost.exportがファイルを生成します。ラスター、DOMウォーカーによるベクター、PDF、ドキュメント、schemas/tool.schema.jsonにあるその他の形式のいずれかです。物理単位は形式ごとに変換され、メタデータとContent Credentialsは、形式が保持できる場合に埋め込まれます。experimentalのツールの透かしは、ツールではなくホストが付けます。書き出しの手順はテンプレートとレンダリングとファイルを書き出すで扱っています。
signed by Lollyvector SVG77 paths~6.0k nodes87 groups3 images88 KBCheck it yourself署名済みファイルを取得
signed by Lollyvector SVG77 paths~6.0k nodes87 groups3 images88 KBCheck it yourself署名済みファイルを取得
同じライフサイクルは、Tauriでも、ヘッドレスのDOMを使うCLIでも動作し、出力はファイルまたは標準出力に送られます。
ライセンス
engine/、shells/、services/、schemas/、ドキュメントジェネレーターを含むコードは、1つの公開リポジトリlolly-tools/lollyでMPL-2.0です。ドキュメントの文章はCC BY-SA 4.0です。ブランドパックは、各パックのNOTICE.mdに独自の条件を持ちます。コミュニティツールはMPL-2.0で、非公開のSUSEパックはSUSEの専有です。ライセンスに関する全文の注記は概要にあります。