コンテンツにスキップ

コミュニティのスキンとパック

FolderSkinを使うすべての人と、誰でも無料でスキンを共有できます。共有するスキンのまとまりをパックと呼び、スキン1つだけでも1つのパックになります。パックは専用のリポジトリfolderskin-communityのpacks/に置かれていて、追加するのにアカウントは要りません。FolderSkinには最初から入っているスキンがありません。スキンの出どころは、パック、自分の画像、AIの生成結果のいずれかです。

FolderSkinを初めて開くと、ライブラリの手始めになるパックが表示されます。それ以降は、アプリでコミュニティを開いてください。上部のフィルタは、パックに付いているタグです。追加を押すとパックのスキンがライブラリに入り、パックのタグも一緒に付きます。各スキンの⋯メニューには、どのパックから来たか、誰が共有したかが表示されます。削除を押すと、パック全体をまた取り除けます。そのパックのスキンをすでに使っているフォルダでは、アイコンはそのまま残ります。アイコンはフォルダそのものに保存されているからです。

フォルダから追加は、コンピュータ上にあるパックのフォルダで同じことを行います。共有する前にパックを試してみるときも、この方法を使います。

folderskin.appのギャラリーでは、どのパックにもインストールボタンがあります。押すとFolderSkinが開き、コミュニティでそのパックを表示して追加します。パックの追加ボタンを押したときとまったく同じです(下のインストールリンクを参照)。公式の印が付いたパックは、メンテナのお墨付きです。

パックは丸ごと追加されるか、まったく追加されないかのどちらかです。まずすべての画像をダウンロードして検査し、そのあとで一度にまとめて保存するので、接続が切れたりディスクがいっぱいになったりしても、パックが中途半端にライブラリに残ることはありません。スキンはパックで決められた順に並びます。

共有はアプリから行います。FolderSkinがパックをコミュニティサービス(community.folderskin.app)に送り、そこでメンテナが審査します。GitHubのアカウントは要りません。FolderSkin 0.1.6以前では、GitHubにプルリクエストを作成する方法も選べましたが、0.1.7でこの方法はなくなりました。

  1. 共有したいスキンにタグを付けます(⋯ → タグ)。スキンを1つだけ共有するなら、⋯ → コミュニティで共有を使います。複数を共有するなら、コミュニティ → スキンを共有を開いてタグを選びます。
  2. パックの名前、タグ、ライセンスを入力し、画像の出どころを書いて、自分が共有してよい画像であることを確認するチェックを入れます。
  3. 初回だけ、パックの作者として表示される名前で、FolderSkinがブラウザ上でこのコンピュータを確認します。確認はコンピュータごとに1回だけです。
  4. 送信します。FolderSkinは、何かがコンピュータの外に出る前に、パックが下記の仕様に合っているかどうかを検査します。送信履歴には送ったパックが一覧で表示され、却下されたものはその理由もわかります。

画像はすべてロスレスで共有されるので、完成したフォルダの透明なふちまで含めて、作ったとおりの見た目で届きます。FolderSkinは送信前に各画像をロスレスWebPに変換します。1枚につき数秒かかり、変換が終わった枚数を数えながら進みます。1024pxでは1.5MBに収まらないほど細かい画像は、ロスレスのまま896px、それでも無理なら768pxにして、どの画像を小さくしたかを知らせます。パックの画像は合計64MBまでです。それを超えるパックは受け付けられず、2つのパックに分けるよう提案されます。

どのパックも、ほかの人の目に触れる前に人が確認します。承認されると、15分ほどで自動的に公開されます(下の承認で公開されるしくみを参照)。同じ名前のパックがいくつあってもかまいません。選んだ名前がそのまま全員に表示され、パックにはそれとは別に固有のIDが付きます(パックのID)。

パックは手作業でも追加できます。folderskin-communityに、packs/の下へフォルダを1つ追加するプルリクエストを送ってください。フォルダはpacks makeで作ります(画像からパックを作る)。そうすると生成されたIDが付き、プルリクエストではアプリと同じチェックが実行されます。アプリのフォルダとして保存でも、下記のルールをすべて満たすパックのフォルダを書き出せます。

パックにはそれぞれIDがあります。IDはパックのフォルダ名であり、パックへのリンクにも必ず含まれます。IDはパックを作るときに一度だけ、名前とランダムな6文字から作られます。たとえばClassic Artというパックなら、classic-art-k7q2mxのようなIDになります。名前は自由に重複してよいので、Classic Artという名前のパックが100個あってもかまいません。一意でなければならないのはIDだけです。手作業で作るパックのIDはpacks makeが、アプリから共有されたパックのIDはコミュニティサービスが作ります。一度決まったIDは、パックの名前が変わっても変わりません。

ランダムな部分は、aからzまでと2から7までの文字を使った6文字で、システムの安全な乱数源から生成されます。新しいIDが、packs/にあるフォルダの名前や、moved.jsonにある古いIDと重なることはありません。

IDが生成されるようになる前に作られたパックは、classic-artのように名前だけから作ったIDを持っていました。これらのパックにはpacks renameで生成したIDが付け直され、packs/の隣にあるmoved.jsonに、古いIDと現在のIDの対応が記録されています。

{ "version": 1, "moved": { "classic-art": "classic-art-k7q2mx" } }
  • 古いIDは、packs/のどのフォルダも使っていないパックIDです。新しいパックに与えられることもありません。
  • 新しいIDは、どれもpacks/にあるパックを指します。別の古いIDを指すことはありません。パックをもう一度リネームすると、それまでそのパックを指していたものがすべて最新のIDを指すように書き換えられます。
  • packs indexとpacks catalogは、この対応表を"moved"としてindex.jsonとhead.jsonにコピーします。これにより、アプリ、Webサイト、コミュニティサービスが古いIDからパックをたどれます。0.1.7以降のアプリは、古いIDで追加したパックを新しいIDに移します。古いIDのインストールリンクからでも、目的のパックが見つかります。
  • リネームしたパックも、最初に公開された日付を保ちます。packs indexは、そのパックのいずれかのIDを追加した最も古いコミットの日付を使います。
  • pack.jsonには何も追加しません。pack.jsonは仕様にないフィールドを受け付けず、追加するとアプリ0.1.4〜0.1.6がそのパックを拒否してしまいます。
ターミナルウィンドウ
cargo run -p folderskin-tools -- packs rename --dir ../folderskin-community --all
cargo run -p folderskin-tools -- packs rename --dir ../folderskin-community classic-art
cargo run -p folderskin-tools -- packs rename --dir ../folderskin-community classic-art --to classic-art-k7q2mx

folderskin-communityのgitチェックアウトの中で、パックに生成したIDを付けます。各フォルダはgit mvで移動するので、履歴も一緒に引き継がれます。featured.jsonとofficial.jsonは順序を保ったまま新しいIDに書き換えられ、すべての移動がmoved.jsonに記録されます(なければ作成されます)。変更はすべてステージされ、そのままコミットできる状態になります。

--allは、IDが生成されたものではないパックをすべてリネームし、それ以外はそのままにします。判定はIDの形だけで行います。そのため、data-structures-in-bricksのように最後の単語がたまたま6文字の古いIDは、生成されたIDに見えてしまいます。こうしたパックは、IDを指定してリネームしてください。IDを指定したパックは、現在のIDが何であれ、新しく生成されたIDに移ります。--toを付けた場合はそのIDに移りますが、これは生成された形式のIDで、どのパックも今も過去も使っていないものでなければなりません。もう一度実行しても何も変わりません。移動済みのパックはmoved.jsonで見つかり、すでに移動済みと表示されます。

パックは承認されると公開されます。誰かが手作業でファイルをコピーすることはありません。

  1. メンテナがパックを承認すると、コミュニティサービスがパックにIDを付けます。サービスがGitHubのトークン(GITHUB_DISPATCH_TOKEN)を持っている場合は、pack-approvedのrepository dispatchで、folderskin-communityのPacksワークフローもすぐに開始します。
  2. トークンがない場合は、ワークフローが自分でパックを見つけます。15分ごとにhttps://community.folderskin.app/v1/exports/pendingへ、承認済みで公開を待っているパックの数を問い合わせ(数秒で済みます)、待っているパックがあるときだけ残りの処理を行います。また、待っているパックの有無にかかわらず毎日と毎週実行されるほか、メンテナが手動で開始したときにも実行されます。
  3. community pull --no-doneが承認済みの各パックをpacks/に書き込み、すべてのファイルのサイズとSHA-256を、アップロード時にサービスが記録した値と照合します。サービスが付けたIDは生成された形式でなければならず、すでにあるフォルダが上書きされたり、番号を付けて別名にされたりすることはありません。パックの完成したフォルダは、チェックの前に形をそろえます(パックのフォルダの形をそろえる)。その形から離れすぎているフォルダはそのまま残し、実行ログに警告を出します。
  4. packs checkが、プルリクエストのときと同じようにすべてのパックをチェックします。
  5. 各パックはgithub-actions[bot]によってAdd the <name> packというメッセージでコミットされ、mainにプッシュされます。
  6. そのあとで初めて、community doneがサービスにパックの公開を伝えます。チェックやプッシュに失敗したパックはサービス側で待機したままになり、次の実行でもう一度試されます。
  7. 同じ実行の中で、index.json、プレビュー、v2/を作り直し、v2/をミラーにコピーして(後述)、それらをコミットします。ワークフロー自身のトークンで行ったプッシュでは別のワークフローが起動しないため、すべてを1回の実行で行っています。

つまりパックは、承認から15分ほどで公開されます。サービスがワークフローを直接開始した場合は、数分で公開されます。失敗した実行では何も公開されず、ワークフローが失敗したことをGitHubがメンテナにメールで知らせます。GitHubは混雑しているときにスケジュール実行を遅らせることがあり、60日間動きのないリポジトリではスケジュールを止めてしまいます。repository dispatchは、このどちらの影響も受けません。

ワークフローには、メンテナの署名鍵(community keygenが書き出したファイル全体)が、リポジトリシークレットFOLDERSKIN_ADMIN_KEYとして必要です。これがないと承認済みのパックはサービスで待機したままになり、実行ログにもそう表示されます。リポジトリ変数REQUIRE_GENERATED_IDSをtrueにすると、生成されたIDを持たないパックはすべてのチェックで拒否されます。

手作業でのプルも引き続き使えます。community pullはパックを書き込むと、すぐにサービスへ伝えます。実行した人が書き込まれた内容をコミットする前提だからです。--no-done --pulled pulled.jsonを付けると、community done --from pulled.jsonを実行するまでサービスへの通知を保留します。ワークフローはこの方法で実行しています。サービスに2回伝えても問題はありません。

アプリは、ツリー全体をhttps://packs.folderskin.appから読み込めます。これはリポジトリと同じv2/を保持するCloudflare R2のバケットです。バケットに書き込むのはコミュニティサービスなので、ワークフロー自体はCloudflareのトークンを必要としません。community mirrorが各ファイルにメンテナの鍵で署名し、サービス経由で送ります。

ターミナルウィンドウ
cargo run -p folderskin-tools -- community mirror --tree ../folderskin-community \
--public https://packs.folderskin.app --api https://community.folderskin.app --key ~/folderskin-admin.key

すべてのファイルについてHEADリクエストでミラーに問い合わせ、同じ長さですでに配信されているファイルはそのままにします。head.json以外のファイル名は、中身のハッシュだからです。残りのファイルはPUT /v1/admin/tree/<path>でアップロードし、バケット側で検証できるよう、それぞれのSHA-256をX-Content-SHA256に付けます。head.jsonは最後に、ほかのファイルがすべてそろってから送るので、ミラーが持っていないカタログを指すことはありません。時間をおけば通る可能性のあるリクエスト(応答なし、5xx、429)は、待ち時間を1秒から倍々に延ばしながら合計5回まで試し、Retry-Afterには30秒まで従います。ワークフローはコミットの前にこれを実行するので、GitHub上のhead.jsonが更新されるのは、そこに書かれたものがすべてミラーにそろってからです。ミラーはリポジトリ変数COMMUNITY_MIRROR_URLで有効になり、head.jsonにミラーが載るのは有効な間だけです。

パックは1つのフォルダです。

packs/night-prints-h4x2qe/
pack.json
koi.webp
fox-in-the-rain.webp

pack.jsonは次のとおりです。

{
"version": 1,
"name": "Night prints",
"author": "your-github-name",
"license": "CC0-1.0",
"tags": ["woodblock", "night"],
"skins": [
{ "file": "koi.webp", "name": "Koi over the wave", "tags": ["animals"] },
{ "file": "fox-in-the-rain.webp", "name": "Fox in the rain" }
]
}
フィールドルール
version1
name1〜40文字
authorGitHubのユーザ名
licenseCC0-1.0、CC-BY-4.0、MITのいずれか
tagsタグ1〜5個。パックのすべてのスキンに付き、最初のタグがみんなのフィルタでそのパックを表す名前になります
skins1〜50項目
skins[].fileフォルダ内の画像
skins[].name1〜60文字
skins[].tags任意。そのスキンだけに最大3個まで追加できます

ほかのフィールドは使えません。そのため"tag"のような打ち間違いは、無視されずにチェックで失敗します。

制限
パック内のスキン1〜50個
各画像ロスレス(PNGまたはロスレスWebP)。最大1.5MB
パックの画像の合計最大64MB
画像の辺の長さ256〜1024px
ファイル名英字、数字、.、-、_のみで、.pngか.webpで終わる
ID(フォルダ名)名前とランダムな6文字。例:night-prints-h4x2qe(パックのID)。小文字の英字と数字でできた単語を1つのハイフンでつなぎ、最大40文字
タグ小文字の英字、数字、スペース、ハイフンで、最大24文字
pack.json最大64KB

50個と64MBにしている理由は、パックがテーマのあるセットで、追加する人は全体をダウンロードするからです。スキン50個なら審査もすぐに済み、64MBあれば1枚1.3MBの画像が50枚、最大サイズの画像なら42枚収まります。

FolderSkin 0.1.7より前に公開されたパックは、PNG、JPEG、または任意のWebPで1枚2MBまでという基準で作られていて、アプリは今も読み込めます。packs makeで作り直せば、上のルールに従うようになります。packs checkに--require-losslessを付けると、パックをこのルールでチェックします(パックを自分でチェックする)。コミュニティサービスは、このルールを満たすパックしか受け付けません。

画像は2種類のどちらかで、ウィンドウにドロップした画像と同じ方法で見分けます。

  • 完成したフォルダ:透明な背景、または単色のマゼンタ#FF00FFの背景に描かれたもの。マゼンタはFolderSkinが切り取ります。描かれたとおりにそのままアイコンになります。
  • それ以外:FolderSkinのフォルダにはめ込まれます。フォルダが画像のどこを切り取るかはSKINS.mdで説明しているので、主題が切れないようにできます。

3つのOSのどれでも、描かれるアイコンの最大サイズは1024pxなので、それより大きな画像にしても意味はありません。

画像はすべてロスレスなので、パックは作ったとおりの見た目になります。グラデーションにブロックノイズが出ることも、文字のまわりにリンギングが出ることもなく、完成したフォルダのふちも描いたときのままきれいです。ロスレスWebPは同じ画像のPNGより3分の1ほど小さいので、アプリもpacks makeもWebPで書き出します。細かく描き込んだ1024pxの画像は0.6〜1.5MBほどで、ほとんどは800KB前後です。1.5MBに収まらない画像は、ぼかして押し込むのではなく、ロスレスのまま896px、さらに768pxと小さくします。

パックのフォルダの形をそろえる

Section titled “パックのフォルダの形をそろえる”

FolderSkinは、完成したフォルダの画像全体をアイコンに収めます。1枚ずつ作ったフォルダは、それぞれ自分の輪郭ぎりぎりで切り抜かれていて、縦横の比率がまったく同じレンダリングは2つとありません。あるパックでは、幅が高さの1.03倍から1.30倍までばらついていました。Finderで並べると、ずんぐりしたものは背の高いものより小さく見えます。そこで、パック内の完成したフォルダはひとつの形にそろえます。

  • パックの形は、各フォルダの形の中央値です。フォルダは、画像のうち不透明度が半分を超える部分の幅÷高さで測るので、やわらかいふちやうっすらした影は数に入りません。
  • 各フォルダをその形で正確に描き直します。フォルダの部分で切り抜き、幅962px(1024pxのテンプレートでのFolderSkin自身のフォルダの幅で、folderskin-tools templateで確認できます)、高さはその形から決まる値にリサイズします。それを透明な1024 × 1024の画像の中で、テンプレートのフォルダと同じ位置、つまり同じ左端と同じベースラインに置き、ロスレスWebPで保存します。PNGは同じ名前の.webpになり、pack.jsonもそれに合わせて更新されます。
  • 形を変えるのは最大8%までです。その程度の変化なら誰も気づきません。それ以上の変形が必要なフォルダは外れ値です。そこまで引き伸ばすと文字や顔がつぶれて見えるので、形は変えません。外れ値をどう扱うかはコマンドによって異なり、最終的には人が判断します。
  • アートワークには手を加えません。FolderSkinが自分のフォルダにはめ込むので、そろえるべき形がそもそもありません。完成したフォルダが1つしかないパックも同様です。

この処理は、packs makeが作るすべてのパック、community pullが取り込むすべてのパックに対して行われ、packs/にある既存のパックにはpacks normalizeで行います。2回実行しても何も変わりません。すでにパックの形になっていて正しい位置にあるフォルダは描き直されず、書き込む内容とすでに同じファイルは書き換えられません。

コマンド外れ値の扱い
packs makeパックから外し、一覧に表示します。--keep-outliersを付けると、そのまま残します
packs normalize一覧に表示し、そのまま残します。--drop-outliersを付けるとpack.jsonから外し、画像も削除します
community pullそのまま残し、警告を出力します(Packsワークフローのログに表示されます)。誰かが共有したスキンが、人の判断なしに外されることはありません
ターミナルウィンドウ
cargo run -p folderskin-tools -- packs normalize --dir ../folderskin-community
cargo run -p folderskin-tools -- packs normalize --dir ../folderskin-community classic-art-5rxas2 --tolerance 0.3
cargo run -p folderskin-tools -- packs normalize --dir ../folderskin-community dreamscapes-ppfia6 --drop-outliers

packs normalizeは、すべてのパック、または指定したパックを順に処理します。パックごとに形と描き直したものを表示し、外れ値はどれだけずれているかとともにすべて挙げます。packs checkに通らないパックは、通るようになるまで手を付けません。--toleranceは8%の値を変更します。Classic Artのモナ・リザのように、外れ値でもパックの形に合わせたい場合に使います。--drop-outliersはメンテナ向けです。これ以外にスキンを削除するものはありません。packs check --require-one-shapeは、フォルダの形が1%を超えて異なるパックを拒否します(パックを自分でチェックする)。ひとつの形に描き直したフォルダが拒否されることはありません。

共有するスキンには、クリエイティブ・コモンズかMITのライセンスを使います。

  • CC0-1.0:誰でも、どんな目的にも使えます。ほとんどのスキンはAIで作られていて、CC0は権利の主張がいちばん少ないため、これが既定値です。
  • CC-BY-4.0:誰でも使え、使う人はあなたの名前をクレジットに表示します。
  • MIT:誰でも使え、あなたの名前も一緒に残ります。

共有するのは、自分で作った画像か、共有を許可されている画像だけにしてください。

packs makeは、画像生成モデルから保存したレンダリング画像などが入ったフォルダを、folderskin-communityのチェックアウト内のpacks/の下に、そのままチェックに通るパックとして作ります。以下のコマンドは、このリポジトリで、隣にfolderskin-communityをチェックアウトした状態で実行します。

ターミナルウィンドウ
cargo run -p folderskin-tools -- packs make ~/Downloads/3d-renders --dir ../folderskin-community \
--name "3D" --tags 3d,glossy --author your-github-name --preview /tmp/3d.png

パックには、名前とランダムな6文字からなる3d-k7q2mxのような固有のIDが付き、それがフォルダ名になります。IDはレポートに表示されます。packs/にあるフォルダの名前や、moved.jsonにある古いIDと重なることはありません。

各画像は、アプリで画像を追加するときと同じように振り分けられます。PROMPTS.mdのチャット用プロンプトの指示どおりマゼンタの上に描かれた完成したフォルダや、本当に透明な背景の完成したフォルダは、切り抜かれてそのままアイコンになります。それ以外は、FolderSkinのフォルダに使うアートワークになります。どの画像も1024pxに縮小され、ロスレスWebPで保存されます。アプリがパックの共有に使うエンコーダが組み込まれているので、何もインストールする必要はありません。それでも1.5MBを超える画像は896px、さらに768pxにして、そのことをレポートに表示します。--max-kbを使えば、1.5MBより小さく抑えられます。画像の合計が64MBを超える場合は受け付けず、2つのパックに分けるよう提案します。libwebpのもっとも丁寧な設定では1枚に数秒かかるので、すべてのコアで同時に処理します。形式について詳しくはSKINS.mdにあります。各画像がどちらに振り分けられたかはレポートに表示されます。スキンの名前はファイル名から付けられるので、先にファイル名を整えておくか、あとでpack.jsonの名前を直してください。--previewを付けると、すべてのスキンをフォルダの形で1枚のPNGに描き出すので、まとめて確認できます。

完成したフォルダが2つ以上あれば形をそろえ(パックのフォルダの形をそろえる)、どれを描き直したかをレポートに表示します。ほかのフォルダの形から8%を超えてずれているフォルダはパックから外し、どれだけずれているかをレポートに表示します。--keep-outliersを付けると、外さずにそのまま残します。外れ値を残さずに作ったパックは、packs check --require-one-shapeに通ります。

--idを使うと、既存のパックを新しい画像から作り直せます。--id 3d-k7q2mxはpacks/3d-k7q2mx/の中身をすべて置き換え、パックのIDはそのまま残るので、このパックを追加した人全員に、新しいバージョンがアップデートとして届きます。新しいフォルダはまず別の場所で作ってチェックし、通ったときだけ古いフォルダと入れ替えます。--idを付けなければ、packs makeは常に新しいパックを作ります。

画像生成モデルに#FF00FFを指定しても、代わりにラズベリー色やホットピンクで一様に塗ってしまうことがよくあります(Classic Artパックを作ったときのGrokもそうでした)。--flat-backdropは、どんな色でも単色の背景なら切り取ります。画像ごとに背景の色を測り、ふちまでつながっている部分だけを取り除き(そのため、フォルダの中の赤いマントは残ります)、やわらかいドロップシャドウも一緒に取り除いて、ふちにピンクの縁取りが残らないよう絵の色でなじませます。無地のグレーや黒の背景では、その背景自体のノイズの範囲にとどまり、上へ広がることもないので、フォルダのふちに接する暗いコートやインクの線が背景と間違われることはありません。あとで--previewのシートを確認してください(明るいグレーの上に描かれるので、穴があればわかります)。単色の背景がない画像は、これまでどおりアートワークとして扱われます。

1枚の画像がアプリでどう表示されるかを見るには、renderでフォルダとして描き出します。

ターミナルウィンドウ
cargo run -p folderskin-tools -- render ../folderskin-community/packs/3d-k7q2mx/glass.webp --out /tmp/glass.png --size 512

このリポジトリで、隣にfolderskin-communityをチェックアウトした状態で実行します。

cargo run -p folderskin-tools -- packs check --dir ../folderskin-community

packs/のすべてのフォルダをアプリと同じルールでチェックし、問題があればそれぞれ文章で表示します。folderskin-communityのチェックアウト内で実行する場合は、--dirを省略できます。ツールは既定で現在のフォルダを見るからです。画像は1枚2MBまで(0.1.7より前に公開されたパックの基準)、パックの画像は合計64MBまでであることをチェックします。--require-losslessを付けると、新しいパックが従うルール、つまりPNGまたはロスレスWebPで最大1.5MBというルールで、すべての画像をチェックします。これはコミュニティサービスが受け付け、packs makeが書き出す形式です。以前のパックの作り直しが済むまでは、指定しない限りオフです。--max-kbを使うと、さらに小さいサイズに制限できます。

IDどうしの関係もチェックします。大文字と小文字しか違わない2つのフォルダ名は、macOSとWindowsでは同じフォルダになってしまいます。また、パックはmoved.jsonにある古いIDを使えず、moved.json自体も独自のルールに従う必要があります(moved.json)。名前は重複してよいので、比較しません。--require-generated-idsは、IDが生成されたものではないパックをすべて拒否します。指定しない限りオフで、folderskin-communityのワークフローでは、変数REQUIRE_GENERATED_IDSがtrueのときに指定されます。

--require-one-shapeは、完成したフォルダの形がそろっていないパック、つまり幅÷高さが1%を超えて異なるフォルダが2つあるパックを拒否します。ひとつの形に描き直したフォルダは必ずこの範囲に収まるので、一度も形をそろえていないパックや、誰かが残した外れ値を見つけられます。エラーには、最も離れた2つのフォルダの名前と、実行すべきコマンドが表示されます(パックのフォルダの形をそろえる)。指定しない限りオフで、folderskin-communityのワークフロー向けです。

アプリがパックを読み込むしくみ

Section titled “アプリがパックを読み込むしくみ”

コミュニティにはリスト表示とギャラリー表示があり、パックの表示を押すとそのパックが開きます。何かを追加する前に、すべてのスキンがフォルダになった姿で、名前とともに表示されます。再読み込みで一覧を読み直します。追加したあとに変更されたパックにはアップデートが表示され、押すとスキンが新しいバージョンに入れ替わります。フォルダのアイコンはそのまま残り、両方のバージョンに共通する画像のお気に入りも、お気に入りのまま残ります。

  • folderskin-communityのindex.jsonには、すべてのパックが載っています。ID、名前、作者、ライセンス、タグ、スキンの数、そして中身(pack.jsonとすべての画像)を正確に表すハッシュです。アプリは追加したスキンと一緒にこのハッシュを保存し、それによってパックにアップデートがあることを知ります。各項目には、パックが最初に公開された日時("added"。Unix秒で、最初のIDでpack.jsonを追加したコミットの時刻)と、official.jsonに載っているパックなら"official": trueも入ります。パックの一覧と並んでいる"moved"はmoved.jsonの内容です。index.jsonはfolderskin-tools packs indexが書き出し、同時にpreviews/<id>.png(パックの最初の4つのスキンをフォルダとして並べた画像)も作ります。どちらもfolderskin-communityのmain上で生成されるので、手で編集しないでください。
  • packs catalogが書き出すv2/は、同じパックを、アプリがコンピュータ上で検索できるカタログの形にしたものです。そのhead.jsonは、現在のカタログを示し、featuredとofficialのパックを挙げ、movedを含み、https://packs.folderskin.appのように同じツリーを配信するミラーを列挙します(ミラー)。アプリは各ファイルをまずミラーから取得し、失敗したときはGitHubから取得します。どちらの場合も、すべてのファイルをハッシュで検証します。0.1.7以降は、head.json自体もまずhttps://packs.folderskin.appから読み込みます。
  • アプリがパックの画像をダウンロードするのは、パックを追加したときだけです。4枚ずつダウンロードし、届いた枚数を表示します。すべての画像を上の制限に照らしてチェックし、ひとつでも通らなければ何も保存しません。すべて通ったらまとめて保存するので、パックが中途半端に追加されることはありません。
  • FOLDERSKIN_COMMUNITY_URLを設定すると、アプリは別のfolderskin-communityのコピーを参照します。たとえば、チェックアウトのルートでpython3 -m http.serverを実行して配信し、この変数をhttp://localhost:8000にすれば、パックを最初から最後まで試せます。

index.jsonとhead.jsonには時とともにフィールドが増えていきますが、どのバージョンのアプリも知っているフィールドだけを読み、残りは読み飛ばします。pack.jsonはその逆で、仕様にないフィールドを受け付けないため、今後も何かを追加することはできません。パックについての新しい情報は、インデックスのほうに入れます。

folderskin-communityのルートには、packs/と並んで2つのリストがあり、編集するのはメンテナだけです。どちらも["classic-art-k7q2mx", "colours-a2b3c4"]のような、パックIDのJSONリストです。

ファイル役割
featured.json初回起動時に提案され、コミュニティで最初に表示されるパック(この順番で表示)
official.jsonコミュニティ、パックのビューア、Webサイトで公式の印が付くパック

どちらも省略できます。IDはすべてpacks/にあるパックでなければならず、2回載っているIDは1回として数えます。どちらかのリストに存在しないパックが載っていると、packs indexとpacks catalogは処理を止めて何も書き出しません。そのため、リネームや削除をしたパックが抜けたまま残ることはありません。プルリクエストのチェックではpacks catalogを実行するので、マージ前に見つかります。packs renameは両方のリストを自分で書き換えます。folderskin-communityのPacksワークフローは、pathsに含まれるファイルが変わるとインデックスを作り直します。そのため、両方のリストはpacks/**と並んでpathsに含めておく必要があり、moved.jsonも同様です。

folderskin://install?pack=<id>を開くと、FolderSkinがコミュニティでパック<id>を表示して追加します。パックの追加ボタンとまったく同じ動作で、進行状況の表示も最後のメッセージも同じです。まずウィンドウが最前面に出ます。GitHubにもう一度問い合わせても、そのIDのパックがコミュニティにない場合は、FolderSkinがそのことを伝え、検索するよう提案します。すでにライブラリにあるパックは、開いたうえで追加済みであることを伝えます。0.1.7以降は、古いIDのリンクを開くと、移動先のパックが開きます(moved.json)。

FolderSkinがリンクを受け付けるのは、厳密に次の形のときだけです。スキームがfolderskinで、installがホスト(folderskin://install?…)またはパス全体(folderskin:install?…)であること。ユーザ名、パスワード、ポートを含まないこと。packがちょうど1つあり、それがパックID(小文字の英字と数字でできた単語を1つのハイフンでつないだ、最大40文字の文字列)であること。ほかのパラメータは読み飛ばし、それ以外の形のリンクは無視します。

スキームはインストーラが登録します。macOSではアプリのInfo.plist、Windowsではインストーラ、Linuxでは.debと.rpmのデスクトップエントリです。AppImageはインストールされるわけではないので、起動時に自分で登録します。WindowsとLinuxでは、リンクを開くと2つ目のFolderSkinが起動し、すでに動いているFolderSkinにリンクを渡して終了するので、同時に動くのは常に1つだけです。

試すには:

macOSアプリをビルドし(pnpm tauri build --bundles app)、target/release/bundle/macos/FolderSkin.appを一度開いて、macOSにスキームを登録します(/Applicationsにコピーしたものがいちばん確実です)。そのあとopen 'folderskin://install?pack=classic-art'を実行します。macOSはバンドルされたアプリにしかリンクを送らないので、pnpm tauri devがリンクを受け取ることはありません
Windowsビルドをインストールするか、pnpm tauri devを実行します(開発ビルドは自分でスキームを登録します)。そのあと、コマンドプロンプトでstart "" "folderskin://install?pack=classic-art"を実行するか、「ファイル名を指定して実行」(Windows+R)に同じリンクを入力します
Linux.debか.rpmをインストールするか、AppImageを一度起動するか、pnpm tauri devを実行します。そのあとxdg-open 'folderskin://install?pack=classic-art'を実行します
ブラウザでのプレビューpnpm devを実行し、http://localhost:14200/?install=classic-artを開きます

WindowsやLinuxでpnpm tauri devを実行する前に、インストール済みのFolderSkinを終了してください。すでに動いているものがあると、新しく起動したほうはそちらにリンクを渡して終了してしまいます。スキームを登録した開発ビルドは、インストーラや別のビルドが登録し直すまで、その登録を持ち続けます。

コミュニティのパックが追加されると、FolderSkinはそのパックのIDをコミュニティサービスに伝えます。POST https://community.folderskin.app/v1/packs/<id>/installsを、本文なしで送るだけです。送るのはこれだけで、アカウントも、デバイスIDも、ライブラリやフォルダに関する情報も送りません(FolderSkinのほかのリクエストと同じく、User-Agentにはアプリのバージョンが入ります)。送信はパックを保存したあとに行い、5秒で打ち切ります。送信を待つ処理はなく、失敗しても報告されません。開発ビルドと、別のコピーからパックを読み込んでいるビルド(FOLDERSKIN_COMMUNITY_URL)は、FOLDERSKIN_COMMUNITY_APIで送信先のサービスを指定しない限り何も送りません。

サービスは、ネットワークとパックの組み合わせごとに1日1回だけ追加を数え、対象は公開済みのindex.jsonにあるパックだけです。古いIDでの追加は移動先のパックの分として数えるので、0.1.7より前のアプリからの追加も数えられます。サービスが保存するのは、パックごとの回数と、その日(UTC)の終わりまでの、リクエスト元ネットワークのソルト付きハッシュです。これにより、同じ日に同じパックをもう一度追加しても二重には数えません。これらのハッシュは毎日のクリーンアップで削除されます。アドレスは保存しません。

folderskin.appは、GET https://community.folderskin.app/v1/packs/installsから回数を読み込みます。レスポンスは{"version": 1, "installs": {"classic-art-k7q2mx": 42}}の形で、5分間キャッシュされます。詳しくはservices/community/README.mdをご覧ください。