mcpField
E
Easel

Easel

ローカル
github.comメディア・デザイン11 週間前に更新

Easel について

Easelは、AIエージェント向けのヘッドレスなペイントエンジンで、Python、コマンドライン、MCPから利用できます。有限の絵の具を使う筆跡、湿った顔料の混色、キャンバスの質感を扱うAPIであり、画像生成器ではありません。

主な機能

  1. 01絵の具の残量を伴う筆跡
  2. 02湿った顔料の混色
  3. 03キャンバス質感のシミュレーション
  4. 04Python APIとコマンドライン
  5. 05描画パスごとの画像確認

活用シーン

  1. 01筆跡を重ねて絵を制作
  2. 02描画パス後に画像を確認
  3. 03ブラシやキャンバスの質感を試行
  4. 04MCP経由でペイントエンジンを操作

MCP 対応

オプションのMCPサーバーが、ペイントエンジンをMCPクライアントに公開します。READMEには個々のツールの説明はありません。

設定

ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。

mcp.json · 共通設定
{
"mcpServers": {
"gemberkoekje-easel": {
"command": "uvx",
"args": [
"easel-paint"
]
}
}
}
起動コマンドuvx easel-paint

ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。

パッケージ
pypieasel-paint0.8.0

ツール

21

掲載時のツール一覧 · 2 週間前に更新

パラメーター型必須説明
seedintegerいいえ
sizestringいいえ
forcebooleanいいえ
budgetanyいいえ
groundstringいいえ
out_dirstringいいえ
sessionstringはい
texturestringいいえ
timelapseanyいいえ

詳細

イーゼル

LLM は、ピクセルで描くのではなく、本物の筆致で絵を描けるのでしょうか? はい、そのための API です。

Easel は、AI エージェント向けのヘッドレスなペイントエンジンです。ブラシ、絵の具の量、ウェット ブレンド、キャンバスのテクスチャを、Python、シェル、または MCP 経由で操作できます。ブラシは 有限量の絵の具を含み、ひと筆の途中で絵の具がなくなります。絵の具は濡れた状態で乗り、すでに ある絵の具と混ざります。顔料モデルでは、青と黄色を混ぜると灰色ではなく緑になります。キャン バスには凹凸があり、絵の具が少ないブラシは高い部分だけを拾います。そのため、ドライブラシは 特別な効果ではなく、粗いキャンバスの上で絵の具がなくなったときに起こることです。ひと筆ごと に自分の作品を見ます。それが肝心な点です。このエンジンは、描いたばかりのものを見られるエー ジェント向けに作られています。

これは描画ライブラリでも、ラスタライザーでも、画像生成ツールでもありません。プロンプトから 画像を作る機能はありません。すべての筆跡を選び、自分で描きます。レイヤーはなく、コストなし の取り消し機能もありません。工程を重ねて作業し、間違いがあればその上から塗り重ねます。

画像を見られる必要があります。 この手法では、各工程の最後に、その結果を確認します。 s.look()、リハーサル、工程後の確認などは、画像を受け取れない画家にはできません。画像入力 に対応していないモデルでも API 全体を操作して、最終的に絵を出力することはできますが、その どれがうまく描けたかは判断できません。0.5.0 コホートのある画家は、自分の完成した絵について まさにそう述べていました。ここでは視覚機能は必須であり、機能のひとつではありません。

描く前にガイドを読んでください。 エンジンはブラシにすぎません。 PAINTER.md が手法を説明しており、6 回の実測で、重要なのは その手法だとわかっています。ガイドはパッケージに含まれているため、探しに行く必要はありませ ん。easel guide を実行すると、最初のページ、つまりワークフロー全体をまとめた約 1,400 語 の内容が表示されます。easel guide --full を実行すると、残りも表示されます。

from easel import Session, blob, cell

s = Session(1024, 768, texture="linen", ground="toned_grey", seed=7)
s.palette["shadow"] = s.palette.mix("ultramarine", "burnt_umber", 0.4)

s.block_in(blob(cell("D5")), brush="bristle", color="shadow", density=0.8)
s.look(values=True)                       # check the value structure
s.stroke([(0.2, 0.6), (0.6, 0.55), (0.9, 0.62)], "bristle", "yellow_ochre")
s.export("painting.png")

この方法で描かれた絵

運転席から見た洗車機の内部。頭上にはマゼンタ色の泡のアーチがあり、トンネルの奥には白い光が広がり、赤い停止灯が点灯している。泡に覆われたサイドブラシが右から揺れながら入り込み、手前にはハンドルとバックミラーが見える

運転席から見た洗車機の内部 — 300ストロークの予算のうち206ストロークを使用。1152×720のリネンに、参考写真なしで描かれています。描画に使った19本のパススクリプトが隣にあります。

向かい側の歩道から見た夜のコインランドリー。暗い建物に、幅広く明るい店頭の窓があり、その中には丸い扉の洗濯機が並んでいる。右端には一人の人が座り、手前の濡れた道路には窓の明かりが筋状に伸びている

通りの向かい側から見た夜のコインランドリー — 300ストロークの予算のうち286ストロークを使用。1024×768のリネンに、参考写真なしで描かれています。描画に使った14本のパススクリプトが隣にあります。

夜明けの冠水した駐車場を高い位置から見下ろしたアオサギ。水面が画面のほぼ全体を占め、上端にはほぼ黒い木々の帯、その下には暖かな黄色の反射がある。鳥は画面の高い位置に大きく立ち、白い頭と長い黄土色のくちばしが見える。その真下には鳥自身の淡い反射があり、手前の水面には駐車区画の線が奥へと伸びている

夜明けの冠水した駐車場のアオサギ — 320ストロークの予算のうち253ストロークを使用。1024×768の粗いキャンバスに、参考写真なしで描かれています。同じ画家が同じ題材を二度描き、二種類の失敗を切り分けました。両方の試みはPAINTINGS.mdで並べて見られます。

これらはすべて、言語モデルがPAINTER.mdをもとに、このAPIを一度に一回呼び出して描いたものです。キャンバスに人の手は加わっておらず、トレースもありません。すべてのストロークがログに記録され、すべてのタイムラプスがそのログから再構築されています。また、それぞれの絵に添えられたノートには、うまくいったことだけでなく、うまくいかなかったことも記されています。PAINTINGS.mdに記録をまとめています。以下の制作例では、それぞれの絵が何でできているかを説明しています。

これから自分でガイドを見ながら描く方へ。何を描くか決めましたか? 決めているなら、これらの絵を参考にしてください。隣にあるスクリプトが、ここで最も役に立つものです。まだ決めていないなら、見ないでください。制作例には題材が示されており、その名のある題材があなたの代わりに選んでしまいます。かつて新たに始めた6つのセッションすべてで、ガイドが通りすがりに挙げただけの名詞を描いてしまったことが、それを示しています。まず決めてから、見てください。

ブラシそのもの

ブラシサンプラー:各ブラシを3つのサイズと3つの筆圧プロファイルで、滑らかなキャンバス、リネンキャンバス、粗いキャンバスに描いたもの

各キャンバステクスチャでの、すべてのブラシ、サイズ、筆圧プロファイルです。python scripts/make_brush_sampler.py で再生成できます。このシートはプロジェクトの主要なテスト成果物であり、テストスイートでは検出できない問題も、見ればわかります。

形状サンプラー:領域を作る5つの方法、それぞれを4方向に塗り広げたもの、最後の列には境界ボックスを表示

領域は長方形である必要はありません。各行は形状を作る方法、各列は塗り広げる方法を示しています。最後の列は、その領域が長方形だった場合の形です。python scripts/make_shape_sampler.py で再生成できます。

インストール

Python 3.12 以降が必要です。依存するのは numpy と Pillow のみで、Windows でのビルドに苦労するものはありません。

pip install easel-paint          # the engine, the CLI and the Python API
pip install "easel-paint[mcp]"   # and the MCP server
from easel import Session, blob, cell      # the import the documents teach
import easel_paint                         # the same engine under the installed name

ディストリビューション名は easel-paint であり、easel ではありません。 PyPI には無関係な easel というパッケージがあるため、pip install easel を実行すると別のパッケージがインストールされます。ここではどちらのインポート名も使えます。easel_paint は easel を再エクスポートしており、すべてのサンプルでは短い方を使っています。

チェックアウトした状態から、pip install -e . と pip install -e ".[mcp]" を実行すると、同じ2つの処理が行われます。

どちらの方法でも easel コマンドがインストールされます。Pip はこれをインタープリターのスクリプトディレクトリに配置しますが、このディレクトリは PATH に含まれていないことがよくあります(含まれていない場合は警告が表示されます)。そのため、同じコマンドを別名で実行できる python -m easel ... は常に利用できます。

MCP サーバーは、エンジン内のほかの部分からはインポートされないため、オプトインの追加機能です。以下のMCP サーバーを参照してください。

LLM エージェントの場合は、PAINTER.md をお読みください

PAINTER.md は、あなたのために書かれたガイドです。関数を列挙するのではなく、ワークフローを説明しています。地面をならし、奥から手前へ塗り、明暗を確認し、細部を整え、最後に輪郭とハイライトを仕上げます。また、最初の1時間から始まり、10個のウォームアップ練習を最初に行えるよう、メソッド全体を1ページにまとめています。

すでにパッケージをインストールしている場合は、そのリンクを開く必要はありません。 6つのドキュメントはすべてホイールに同梱されています。python -m easel guide で最初の1時間の内容を表示し、--full で残りを表示できます。また、easel.docs.read() を使えば、どのドキュメントもテキストとして取得できます。6つ目のドキュメントは DIAGNOSIS.md です。これは読むための文書ではなく、症状の索引です。パスを試してみたものの結果が違うときは、easel diagnose concentric rings を実行すると、その症状を計測した箇所が表示されます。

これは5つあるファイルのうちの1つです。5つのファイルにある各ルールは、それぞれ該当するファイルに一度だけ記載され、ほかのすべての場所からリンクされています。PAINTER.md はテストスイートで語数が制限されているため、画家が頭に入れておける内容に保たれています。そこに引用されている数値は CALIBRATION.md で計測されたもので、画家が自身のセッションについて報告した内容も、ルールの隣ではなく同じファイルに記載されています。

PAINTER.mdメソッド:作業のサイクル、順序、間違い、練習、チェックリスト。頭に入れておく内容です
RECIPES.md状況ごとの手順:順番に実行する呼び出し、失敗したときの見え方、その裏付けとなる数値です
PAINTING.md絵の具、ブラシ、計画ツールの動作について説明します。最終章では写真の模写を扱います。根拠を確認したり、注意書きが示す根拠を easel explain <code> で表示したりできます
REFERENCE.md仕様:単位、デフォルト値、各引数の役割です
CALIBRATION.mdほかの4つのファイルが引用するすべての数値の計測結果と、それぞれの計測対象です

このエンジンは、次の習慣を中心に設計されています。

5〜15回筆を動かすごとに確認してください。確認しなかった筆の動きは、あてずっぽうです。

llms.txt は、このリポジトリを取得するモデルが参照するよう求められることが増えている形式で、同じ案内をまとめたものです。概要、続きを読む前に知っておくべきこと、各ドキュメントの場所を、約1,500語で説明しています。

パッケージの内容

要素説明
Session手元に保持する唯一のオブジェクトです。キャンバス、パレット、シード、履歴、look() が含まれます。
Canvasリニアライト RGB に加え、wetness、thickness、sketch(グラファイト)、キャンバスの height(目の粗さ)を持ちます。
ブラシround_soft、round_hard、liner、flat、bristle、knife、smudge です。先端はプロシージャルに生成され、tip_wobble を使うと、丸いブラシにも独自のシルエットが生まれ、マークごとに描き直されます。
Palette黒を含まない、限られた顔料セットです。混色、色味の調整、陰影付けを行い、作った色に名前を付けられます。
領域region("top-left")、cell("D6")、horizon(0.4)、below(...)、between(...) です。
形状矩形ではない塊です。blob、ellipse、hull、union、ribbon、polygon のほか、どのキャンバスでもピクセル上で丸くなる s.circle() があります。smooth() は輪郭の角を落とし、roughen() は輪郭線から外れるように形を崩します。規則的でないものなら何にでも使えます。どれも領域と同じ場所に配置でき、group() で複数をまとめて動かせます。rotated() は形状やグループをピクセル上で回転させます。s.px(x, y) はピクセル単位で描画し、s.frame() は対象に独自の座標系を与え、ピクセル上で傾けます。
塊block_in(place, ...) は矩形または 形状 を重なり合うストロークで塗りつぶし、シルエットで止まります。または edge="clean" で輪郭を描きます。塗料を完全に不透明にする必要がある場合は solid=True を指定します。密度はストローク間隔を決めるもので、塗りつぶしを行うものではありません。sweep(edge, ...) は塊を輪郭に沿ってストロークで置き、内側へ段階的に進めます。どちらも通常のストロークを生成します。
通過部分と修正scumble(band, a, b, n) は、2つの値の間を進む n 本の重なり合うストロークで、柔らかな通過部分を作ります。絵の具でグラデーションツールを使うようなものです。direction="inward" にすると、パッチを横切るのではなく、その周囲に沿ってストロークを進め、中心から値が落ちていくようにします。cover(place, color) は修正レシピの条件がすべて設定済みの状態で、間違いを覆い隠します。smudge(edge, ...) は独自の形状に沿ってエッジをぼかします。点にも、輪郭に沿ってぼかす塊にも使えます。
look()グリッドのオーバーレイ、グレースケール値、領域の切り抜き、並べた表示、差分、ランドマーク、切り抜き内を細かく区切ったラベル付きの 10 分の 1 グリッドを表示します。
描画pencil() は塗料の下にグラファイトを描き、実際に乗った塗料の量に応じて覆われます。ストローク数には数えません。
計画thumbnail() は配置を平面的かつ小さく描きます。それぞれの場所を指定された値で描くか、値が与えられていない場合は、計画にある場所と、これまでに置かれたすべての塊を描きます。ここでシルエットが読み取れるかどうかが分かります。easel run pass.py --thumbnail は、パスのマークに費用が発生する前に、そのパスのサムネイルを描きます。preview() は、両方のパネルにマークを重ねて、どこに描かれるかを表示します。rehearse() はコピーに描いて、仕上がりを表示します。cost() は費用を示し、cost_line() は 理由 を示します。paint() はその同じ計画を描画するため、どの線も二度書きされません。キャンバスに触れるのは、この5つのうち最後のものだけです。
測定compare(reference) は、各セルの両方の値と差を、表とヒートマップで示します。compare({place: value}) は、代わりに自分で記述した値の計画と比較します。参照画像なしで描画する場合に使えます。また、計画自体が互いに 0.10 以内と見なしている値の組み合わせに名前を付けます。prepare(reference) は写真を番号付きの塊に分割します。palette.chroma_of は 色の鮮やかさ を示し、明るさを示す value_of と並んでいます。
チェックreport() はガイドに記載された継続中の警告をログから読み取ります。パス全体で1種類・1サイズのブラシしか使っていない、同じ角度でパスを重ねている、ブラシとして小さすぎる毛筆を使っている、塊より先に細部を描いている、幅を指定する圧力リストでチゼルを使っている、マークのうち題材が占める割合、といった警告です。さらに、ログだけでは把握できない4項目についてキャンバスを測定します。値の配置と絵の明暗が明確かどうか、エッジが硬いものと柔らかいものにどう分かれているか、地の部分がどれだけ残っているか、グラファイトがどれだけ見えているかです。run は各パスの後、予算の行の横に結果を出力します。まず検出事項を示し、続いて変化した各測定値を表示します。検出事項には、それを数えたマークと、そのマークを描いたスクリプトの行が記載されます。
呼び出し時それぞれコードと測定結果を伴う33種類の通知です。塗料が指定された場所の外に付着しそう、方向が塊の軸と比べてはるかに大きなコストを要する、パスの端が傾斜を下りそう、塗膜が本来の範囲を超えている、スマッジが境界に沿わず境界を横切りそう、閉じられないコームで塊を不透明に塗ろうとしている、といった内容です。ライブラリ、シェル、MCP の結果のいずれにも通知が届き、easel explain <code> は、その通知を測定した箇所を出力します。
締めくくりのチェックリストchecklist() — easel check — は、数値で評価できるガイドの締めくくりのチェックリストの各項目に回答します。その後、測定できない3項目を質問として出力し、あなた自身の why を引用して返します。
予算Session(budget=300) は、画家が記録するよう求められる予算の内訳を保持します。run は使用済みと残りの額を報告し、その下に、パスの中で最もコストの高い呼び出しを、それを発生させた行とともに表示します。cost は、計画が残額の大きな割合を使う場合に警告します。処理が拒否されることはありません。
計画s.plan(why=, values=, lightest=, subject_share=, bands=, ground=, key=, habits=, shares=) は、画家が最初のマークを付ける前に決めておくよう求められる、その他の内容を保持します。各部分の予算に占める割合も含まれます。チェックでは一般的な助言ではなく、この計画に照らしてキャンバスを測定します。さらに、画家だけが知っていることについて、ルールが例外を認める4項目を絵の側から申告できます。題材が格子である、地の部分が覆われている、明暗の基調が低いまたは高い、場所を意図して小さな丸いマークを使っている(顔のパーツなど)、といった項目です。セッションファイルに保存されます。シェルからは easel plan を使います。
履歴すべてのストロークがデータとして記録されます。元に戻す、再生する、GIF のタイムラプス、コンタクトシートに対応しています。
座標は常に原点を左上とする 0.0–1.0 の正規化値です。生のピクセル値は一切公開しません。絶対ピクセル座標は、言語モデルが最も苦手とするものだからです。

コマンドライン

セッションの状態は単一の .easel ファイルに保存されるため、Python プロセスを起動したままにせず、シェルから少しずつ作業できます。

easel new painting.easel --size 1024x768 --texture linen --ground toned_grey --seed 7 --budget 300
easel run painting.easel first_pass.py
easel run painting.easel first_pass.py --thumbnail  # its masses, flat and small, unpainted
easel run painting.easel first_pass.py --rehearse   # against a copy, committing nothing
easel run painting.easel p2_sea.py p3_rocks.py --rehearse   # ...both passes, one copy
easel run painting.easel sky_a.py sky_b.py --alternatives   # ...two versions, side by side
easel run painting.easel p4_tower.py --check         # the post-pass check over the whole painting
easel look painting.easel --grid
easel look painting.easel --values
easel look painting.easel --region D4 --fine --reference ref.jpg
easel mark painting.easel top_l 0.335 0.315
easel compare painting.easel ref.jpg
easel prepare painting.easel ref.jpg --level coarse
easel undo painting.easel 3
easel export painting.easel painting.png
easel timelapse painting.easel painting.gif --every 3 --scale 240
easel brushes
easel guide                                          # the method, in about 1,400 words
easel guide --full                                   # all of PAINTER.md
easel guide --painting                               # the reasons under the rules
easel guide --recipes                                # the calls, in order, for a thing
easel guide --reference                              # units, defaults, every argument
easel diagnose concentric rings                      # it is wrong: the passage that says why
easel explain chisel-blank                           # it warned you: the measurement behind it
easel demo crosses a boundary                        # a recipe, painted beside its failure

easel 実行ファイルが PATH にない場合は、どのコマンドも python -m easel ... として実行できます。

easel run で実行するスクリプトでは、セッションがあらかじめ s にバインドされ、公開 API 全体がすでにスコープ内にあるため、インポートは不要です。セッションファイルと同じ場所にある prelude.py は同じスコープで先に実行されるため、ヘルパーや混色の設定をパス間で引き継げます。別のファイルを指定するには --prelude other.py を使い、無効にするには --no-prelude を指定します。

MCP サーバー

MCP を話すクライアント向けに、同じ動詞がそろっています。違いとして便利なのは、画像を確認するツールが画像へのパスではなく、画像そのものを返す点です。look、thumbnail、preview、rehearse、compare、prepare は PNG をインラインで返します。これはパスをリハーサルするときに run が行うのと同じなので、ガイドが推奨するループ(5〜15 ストロークごとに確認する)を 1 回の呼び出しで実行できます。

pip install "easel-paint[mcp]"
easel-mcp --dir ~/paintings          # or: python -m easel.mcp_server

インストールせずに使う場合は、クライアントで設定する次の形式を使います。

uvx --from "easel-paint[mcp]" easel-mcp --dir ~/paintings

どちらも必要なので、この 2 つを明記しています。サーバーはオプションの追加機能であり、そのコンソールスクリプトは easel-paint ではなく easel-mcp です。サーバーは公式 MCP レジストリに io.github.Gemberkoekje/easel として登録されています。リポジトリのルートにある server.json が公開されているファイルです。

ツールは 21 個です。CLI の 17 個の動詞に、まだ描かれていないストロークについて確認する 4 つのツール、preview、rehearse、cost、thumbnail を加えたものです。ストロークを描くのは run で、スクリプトをテキストとして受け取ります。run(rehearse=true) はコピーに対してパス全体を試し、何も確定しません。run(alternatives=[...]) は、それぞれ専用のコピーで 1 つのパスの複数バージョンを試し、並べて返します。run(thumbnail=true) はパスを試して、その質量をフラットかつ小さな形式で返すため、実際に描く前に内容を確認できます。場所は名前、セル、範囲、矩形、輪郭、または {"blob": "D5", "radius": 0.12} のような形状ビルダーで指定します。

run はクライアントから送られた Python を、easel run とまったく同じように実行します。シェルを渡せる相手にだけ実行してください。

決定性

各セッションにはシードがあり、同じシードで同じスクリプトを実行すれば、同じ PNG が生成されます。同じマシンではピクセル単位で一致し、別のマシンでは 255 段階のうち 1 段階以内で一致します。numpy のビルドによって、数ピクセルで丸め方が異なる場合があるためです。Linux で描いた 9 点の作品は、Linux で再ビルドするとピクセル単位で一致し、Windows では各作品 12〜2,508 ピクセルの範囲で 1 段階以内に一致しました。各ストロークの乱数は、ひとつの連続した乱数列ではなく、(seed, stroke index) から導出した生成器から取得されます。そのため、ストロークの揺らぎはそのストロークの番号だけに依存し、それより前の呼び出しで乱数がどれだけ消費されたかには左右されません。

これにより、正確な再生が可能になります。

s.replay()          # rebuilds the whole painting from its log; identical export
s.replay(upto=40)   # the state after the first 40 records

これが、別々のシェル呼び出しをまたいで easel undo が機能する仕組みでもあります。セッションファイルにはログが保存され、元に戻すためのスナップショットは保存されません。再構築にはインストール済みのエンジンが使われます。同様に easel timelapse も、ファイルにはフレームが保存されていないため、ログを再生して動画を作成します。フレームごとに、絵を記録したときと同じ動画になります。以前のリリースで保存したファイルを開くと、以降の修正によって一部のストロークの描画方法が変わる場合は、その旨が表示されます。

ゴールデン画像テストにより、この動作が維持されます。tests/golden/ には、各テクスチャに対する固定されたストロークスクリプトと、ブラシサンプラー全体のハッシュおよび PNG が保存されています。ストロークの見た目を変更するとテストスイートが失敗し、失敗時には比較用の 2 枚の画像が表示されます。最初の実行で実際の不具合が見つかりました。チップマスクのキャッシュキーには丸めた半径を使う一方、マスクの作成には正確な半径を使っていたため、同じプロセス内で先に実行された処理によって、スクリプトの描画結果が変わっていたのです。

設計上の注意点

出力が生成物ではなく、描かれたものに見える理由となる、知っておく価値のある決定事項をいくつか紹介します。

  • RGB の平均ではなく、顔料を混ぜます。 色は Kubelka-Munk の K/S 空間で、べき平均(p = 0.35)を使って混ざります。単純に RGB を平均すると、どの混色も灰色がかった茶色になります。また、反射率に下限を設ける必要もあります。そうしないと、あるチャンネルがゼロの色が混色を支配し、赤と青を混ぜると緑になります。この下限がクリップするのは算術演算だけで、混色からは下限の値を差し引くため、それより暗い色も指定どおりに塗られます。src/easel/color.py を参照してください。
  • 間隔は移動方向に沿って測ります。 平筆やナイフの先端は、移動方向に薄くなっています。丸い先端と同じ間隔にすると、離散した線が柵のように並びます。
  • ブレは、スタンプごとではなく滑らかにします。 スタンプごとに独立した揺らぎを加えると、隣り合うスタンプが密集したり離れたりして、スタンプの頻度に沿った縞模様に見えます。ストロークに沿ってゆっくりと揺らすと、波打たずに本物の筆の不揃いな縁を再現できます。
  • 歯のゲートには、周期性のない粒子で粗さを加えます。 ほぼ周期的な織り目に滑らかな閾値を適用すると、絵の具が切れるにつれてハーフトーンの網点が現れ、ドライブラシではなく印刷物のように見えます。
  • 絵の具が切れた筆は引きずります。 ピクセルごとにゲートを適用すると、絵の具が不足した筆でも織り目のスケールの点が残り、紙吹雪のように見えて汚れと区別がつきません。そこで、絵の具の残量が減ると、ゲートはストロークの移動方向に沿って歯を読み取り、毛の櫛の毛先は一本ずつ絵の具が切れていきます。どちらも歯そのものの分布に合わせてあるため、絵の具の残量が変わっても塗られる量は変わらず、形だけが変わって、筆に沿って伸びる筋になります。
  • 毛の櫛はストロークごとに描画され、毛にはそれぞれ幅があります。 筆ごとに櫛を固定すると、幅広の跡を描くたびに同じ筋が印刷され、重ね塗りした面はコーデュロイのようになります。先端全体に一定の本数の毛を並べると、筋は筆の大きさに合わせて拡大され、大きな面には絵全体のどの要素よりも幅広の縞が印刷され、小さな跡にはモチーフではなく筆の特徴が現れます。そのため、毛の間隔、位相、抜けている毛はストロークごとに描き直し、本数は筆のサイズに合わせます。同じ考え方は、デフォルトでは無効の tip_wobble を通じて丸い先端にも当てはまります。円盤はほとんどの跡には適切なシルエットですが、小さな跡を15個連続して描く場合には不適切です。その場合、同じ形が15回印刷されてしまいます。
  • 丸い先端では、幅が筆圧に応じて変わります。 絵の具が付く量だけを変える筆圧は、不透明な色が飽和すると見えなくなります。また、先細りになる跡――まぶた、眉、まつげ、小枝など――を、サイズの異なる2本のストロークで描くことになります。方向性のある先端は、平筆の幅が塗り重ねる面そのものなので、先端の角張った形を保ちます。

ステータス

初期段階ですが、想定されていた機能はすべて実装されています。エンジン、パレット、構図ヘルパー、look()、履歴、CLI、精密ツール(描画、ランドマーク、プレビュー、リハーサル、比較、準備)、形状のある面、MCP サーバーはすべて動作します。API を変更するものは、それを公開するものより先に実装するという原則に従い、サーバーは最後に追加されました。それ以降、サーバーはすべての変更に対応し続けています。

これらの機能はどれも、画家が実際にガイドを使ってエンジンを試し、何が問題だったかを書き留めた結果、追加または修正されました。エンジンの変更にはテストと測定結果が伴い、ガイドの変更は、次のセッションで実際に描いて確かめられるまでは仮説のままです。

制作例

paintings/には、これらのセッションで制作された絵画が収められています。それぞれは単なるギャラリーではなく、最初から最後までの制作例です。絵画を作り上げた番号付きの工程スクリプト、それらに添えられたヘルパーと混色処理をまとめたprelude.py、画家自身の言葉で書かれたNOTES.md、完成したPNGとタイムラプスが含まれています。そのため、制作の順序を後から推測するのではなく、そのまま読み取れます。順序は抽象的な説明では教えられないことであり、初めて描く人が最も確信を持てないことです。

ここには異なる主張が二つあります。このページは以前、すべての絵画について、より強いほうの主張をしていました。 どの絵画にも当てはまるのは、ログをストローク単位で再生できることです。ストロークの乱数は(seed, stroke index)から生成されるため、保存された絵画のログを使えば、すべてのマークが描かれたときと同じ場所に再び描かれ、ゴールデンイメージテストでも確認されています。バイト単位で一致するのは、同じマシン上の場合です。numpyのビルドが異なると、混色の丸め方が小数点以下7桁目で異なることがあり、その結果、ある絵画の786,432ピクセルのうち729ピクセルが1段階ずれました。描画結果はインストールされているエンジンによって決まるため、以前のバージョンが誤って描いたストロークは、修正された状態で再現されます。そのような修正は、各バージョンのCHANGELOG.mdに記載されています。コミットされたスクリプトでキャンバスを再構築できるかどうかは別の問題で、答えは絵画ごとに異なります。34点のうち7点は、PAINTINGS.mdの各自の表で再現性:主張なしと記しています。多くの場合、描画工程が書き換えられて再実行されたか、絵画の工程の合間にlookスクリプトが工程として実行されたためです。マークのテクスチャはログ内の位置をもとにシードされます。各絵画の表には、二つの主張のどちらを掲げているかが記されています。より強い主張をしている古い絵画はsha256で検証済みで、最も新しい7点は画家自身の主張を記していますが、ここではまだ再実行していません。

PAINTER.mdでは条件付きでここを案内しています。その条件が、この取り決めのすべてです。このリポジトリを開く前に題材を決めているなら、これらの例は自由に見てかまいません。まだ題材を決めていないなら、題材は例に選ばれてしまいます。 制作例には題材が明記されており、題材を名指しすると、その題材に引きずられてしまいます。しかし、先に決めておいた画家なら、名詞に誘導されることはありません。そのため、これらを非公開にすることで最も恩恵を受ける画家に、その代償を負わせる必要はなくなりました。LESSONS.mdの測定プロトコルを実行するところなら、このルールは提案ではなく、プロトコルそのものです。

PAINTINGS.mdでは、同じ絵画を画家の立場ではなく、外側から見ています。制作にかかったコスト、失敗したこと、そして実際の出来栄えが記されています。

その他の記録の場所

ガイド自体を構成する5つのファイルは、上の表にあります。プロジェクトに取り組む人向けに、絵を描く人向けではないファイルが、さらに2つあります。 LESSONS.mdには、6回の測定済みの絵画制作と敵対的レビューから得られた内容がまとめられています。手法、エンジンを支える重要な判断、落とし穴、そして未解決の課題です。エンジンまたはガイドを変更する前に読んでください。ガイドをどのように変更できるかというルールも、ここに記されているためです。 SUGGESTIONS.mdは、ガイドを使った25人の画家から寄せられた要望の一覧です。何が問題で、どう対処したかが、それぞれ2行で記されています。最上部のラウンドを除き、すべて対応済みです。修正すべき点がないと測定によって判明した10件も含め、その旨が記されています。最上部のラウンドは未対応であり、各行にその旨が記されています。 CHANGELOG.mdには、同じ履歴が画家別ではなくリリース別にまとめられています。各バージョンでの変更点、変更されたデフォルト値、引数を省略するスクリプトがアップグレード後にどのように違う絵を描くかが記されています。

ライセンス

MIT — LICENSEを参照してください。

オプションのMixbox顔料モデルは、組み込みのモデルよりも優れた混色を実現しますが、参照実装はCC BY-NCです。そのため、依存関係ではなく、オプトインで追加できます(pip install "easel-paint[mixbox]")。有効にする前に、ライセンスが用途に適していることをご確認ください。

コメント

MCP は初めてですか?

プロトコルの概要から最初のサーバーの導入まで、よくある疑問にまとめて答えます。

AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。