msw-painter について
msw-painter は、MSW プロジェクト向けの手描き風ピクセルアートのスプライトを作成・登録するワークフローです。スタイル選択から PNG のレンダリング、アップロードまでを案内します。
主な機能
- 01SVG、Canvas、HTMLで描画
- 02ChunkyとMapleのスタイル
- 03スプライト種別ごとのサイズ指針
- 04作品をPNGにレンダリング
- 05スプライトリソースの登録
- 06シードから一貫した差分を作成
活用シーン
- 01アイコン、タイル、簡単な小物の作成
- 02キャラクター、NPC、モンスターの描画
- 03関連するスプライト差分の作成
MCP 対応
接続された msw-mcp のアップロードツールでスプライトリソースを作成し、ストレージ属性を更新します。アップロードツールがない場合は、Maker で PNG を登録するよう案内します。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ msw-git/ msw-ai-coding-plugins-official --skill msw-painterインストール後、Claude Code で/msw-painterを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/size-guide.mdstyle-chunky-pixel.mdstyle-maple-cartoon.mdscripts/package.jsonrender.cjs詳細
MSW Painter
手描きのピクセルアートスプライトをスプライトリソースとして登録するワークフローです。まず msw-search を呼び出し、適切な RUID が見つからなかった場合にのみ、このスキルを呼び出してください。
このスキルはスプライトカテゴリー専用です。アニメーション/オーディオ/アバター/アトラスには対応していません。
Painter は、2 種類のピクセルアートスタイルに対応しています。chunky pixel(レトロで、アイコンやタイルのような雰囲気)と maple cartoon(MapleStory をイメージした、キャラクターや NPC のような雰囲気)です。コードを書く前に、どちらかを選んでください。下記のステップ 2 を参照してください。
呼び出すタイミング
| 状況 | アクション |
|---|---|
| ユーザーが特定のスプライトを希望している | まず msw-search を使用します(リソース検索セクションのスプライトカテゴリー) |
msw-search で意図に合う RUID が見つかった | その RUID を直接使用します。Painter は呼び出さないでください。 |
| 検索結果がない、またはすべての結果が適切でない | Painter を呼び出す → 直接作成します |
| ユーザーが「手描き風のキャラクター/アイコンが必要」と明示している | Painter を直接呼び出します |
ワークフロー
- メディアを選択する — SVG/Canvas/HTML のいずれかを選びます。下記の「メディアの選択」を参照してください。
- スタイルを選択する —
chunkyまたはmapleを選びます。下記の「スタイルの選択」を参照してください。 - サイズを決める — references/size-guide.md を参照してください。デフォルトは 128×128 です。
- コードを書く — 選んだスタイルのルールに従います。
chunky→ references/style-chunky-pixel.mdmaple→ references/style-maple-cartoon.md
- PNG にレンダリングする —
scripts/render.cjsを実行します。 - リソースをアップロードする — msw-mcp のアセットアップロードツールを使用し、2 段階の事前署名パターンを使います(§5)。接続中の MCP にアップロードツールがない場合は、Maker を通じて PNG を登録するようユーザーに依頼してください。
- スプライトのプロパティを登録する — アップロード直後に
asset_update_resource_storage_infoを実行し、filter_mode/wrap_mode/ピボットを設定します。UI フレームスプライトには 9 スライスの境界も設定します。下記の「ステップ 4」を参照してください。 - 結果を報告する — RUID と 1~2 文の説明を伝えます(使用したスタイルを含めてください)。エンティティの配置/スクリプトの適用は Painter の対象外です。
1. メディアの選択
| メディア | 推奨用途 | 長所 |
|---|---|---|
| SVG | アイコン、ロゴ、シンプルなキャラクター、図形ベースのピクセルアート | 直感的なコードで、1px の <rect> ドットを簡単に配置できます |
| Canvas | 手続き型パターン、反復処理によるロジック(ループで描画するテクスチャ/ノイズ) | JS のプログラミングロジックで複雑なパターンを生成できます |
| HTML | CSS で手早くスタイルを設定できる複合レイアウト | 使用頻度は低く、ピクセルアートには通常 SVG/Canvas のほうが適しています |
SVG の最小テンプレート
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"
width="100%" height="100%" preserveAspectRatio="xMidYMid meet"
style="image-rendering: pixelated;">
<rect x="6" y="2" width="1" height="1" fill="#4A90D9"/>
</svg>
⚠️
width="100%" height="100%"を使用してください(固定のピクセル数は使用しないでください)。SVG 要素は render.cjs のビューポート内で、SVG 自身に指定されたサイズで描画されます。128 をハードコードして--width 1024でレンダリングすると、SVG は左上の 128px の範囲にしか表示されず、PNG の残りは透明になります。100%を指定すると、SVG は--width/--heightで指定されたキャンバス全体に広がります。
Canvas の最小テンプレート
// `c` (canvas element) and `ctx` (2D context) are auto-exposed by render.cjs.
// ctx.imageSmoothingEnabled = false is applied automatically as well.
// IMPORTANT: derive scale from c.width, not a hard-coded constant — otherwise
// a different --width leaves the bottom-right of the canvas blank.
const GRID = 16;
const scale = c.width / GRID; // 16×16 logical grid → canvas-sized output
ctx.fillStyle = '#4A90D9';
ctx.fillRect(6 * scale, 2 * scale, scale, scale);
HTML の最小テンプレート
<!doctype html>
<html><body style="margin:0; image-rendering: pixelated;">
</body></html>
2. スタイルの選択
| スタイル | 推奨用途 | 見た目と雰囲気 | 論理グリッド | アウトライン | 陰影 |
|---|---|---|---|---|---|
chunky | アイコン、ボタン、タイル、ブロック、シンプルな小物 | レトロ/8-bit/NES-SNES | 小さめ(16×16、32×32) | 黒または白、1px | 2~4 段階の階調、アンチエイリアスなし |
maple | キャラクター、NPC、モンスター、かわいいマスコット | MapleStory/絵本/カートゥーン | 大きめ(32×32~128×128) | Selout(塗り色を暗くした色) | 4~6 段階の階調+シルエット上の選択的アンチエイリアス+任意で 2×2 ディザリング |
迷ったときのデフォルト
- アイコン/ボタン/タイル/ブロック →
chunky - キャラクター/NPC/モンスター/マスコット/「かわいい」というリクエスト/「スライムを描いて」 →
maple - ユーザーが「レトロ」/「8ビット」/「NES」/「ミニマル」と指定した場合 →
chunky - ユーザーが「MapleStory」/「かわいい」/「カートゥーン」/「ちびキャラ」/「イラスト風」と指定した場合 →
maple
スタイルごとのルール全文:
どちらのスタイルも、同じ禁止 API(曲線 API、グラデーション API、小数座標、filter: blur/drop-shadow は使用不可)を共有します。パレットの豊かさ、輪郭の色、AA、作業グリッドは異なります。
3. サイズガイド(概要)
| 用途 | 推奨サイズ |
|---|---|
| アイコン/ボタン | 48×48 ~ 64×64 |
| キャラクター/アイテム/NPC/モンスター | 96×96 ~ 128×128 |
| タイル/床/ブロック | 64×64 ~ 128×128 |
| 背景/大きなオブジェクト | 256×256 以上(明示的にリクエストされた場合のみ) |
デフォルトは 128×128 です。スタイルごとの作業グリッドの表(chunky は 16×16 などの小さな論理グリッド、maple は 64×64 などの大きなグリッドを使用)と SD キャラクターのプロポーションについては、references/size-guide.md を参照してください。
リクエストされた出力が 64×64 未満 の場合、
mapleスタイルでは selout + AA + 顔のパーツに十分なピクセルがありません。出力サイズを 64 以上にするか、chunkyに切り替えてください。
3.5 複数スプライトのセット — すべてのバリエーションを1つのシードから作成する
1つのリクエストで複数の関連スプライト(歩行 1/2/3 や攻撃ポーズなどのフレーム風シーケンス、アイコンのファミリー、1体のキャラクターの状態違い)が必要な場合、各スプライトを最初から個別に描いてはいけません。プロンプトで同じ説明を繰り返しても、個別に描いたスプライトはサイズ、パレット、ベースラインにずれが生じます。
- 最初にシードスプライトを1つ描画し、レンダリングして確認してから(PNG を読み取ってから)、セットの残りに取りかかります。
- ほかのスプライトはすべて、シードのコードのコピーを編集して作成します。論理グリッド、パレット定数、輪郭処理、シルエット/プロポーション、アンカーは同一に保ち、ポーズ/内容のみを変更します。キャラクターは下中央をアンカーにし、セット内で足が同じベースラインに揃うようにします。
- PNG をすべてレンダリングし、アップロードする前に横に並べて読み取ります。バリエーションの1つにずれ(サイズ/パレット/ベースライン)があれば、ずれた出力を修正せず、シードのコードから作り直します。
- 各 PNG を個別のスプライトとしてアップロードし(§5)、共通の名前プレフィックス(
Slime_Walk_01、Slime_Walk_02、…)を付け、すべての RUID をまとめて報告します(§6)。
フレームシーケンスの場合は、最初にユーザーへ制約を伝えてください。アップロードツールでは animationclip を作成できないため、各フレームは独立したスプライト RUID として N 個アップロードされます。再生するには、タイマーで SpriteRendererComponent.SpriteRUID を切り替えるスクリプトが必要です(スクリプトなしで再生できる)ネイティブクリップを使うには、ユーザー自身が Maker からフレームをインポートする必要があります。
4. PNG レンダリング — render.cjs
初回の依存関係のインストール
cd scripts && npm ci
コミット済みの package-lock.json から puppeteer(ヘッドレス Chromium を含めて約 200MB)をインストールします。これはほかの基本スキルの依存関係とは別のため、painter を初めて使用するときだけ実行してください。
🔒
npm installではなくnpm ciを使用してください。npm ciはpackage-lock.jsonに固定されたバージョンを正確にインストールし、ロックファイルとpackage.jsonが一致しない場合は失敗します。これは W012 のサプライチェーン完全性を保証するための仕組みです。package-lock.jsonを手動で編集しないでください。puppeteer のバージョンを上げる必要がある場合は、ローカルでnpm install puppeteer@<version>を実行し、再生成されたロックファイルをコミットしてください。
サンドボックス化とネットワーク分離
render.cjs は OS のサンドボックスをデフォルトで有効にしてヘッドレス Chromium を実行し、レンダリングされたページからのすべてのネットワークリクエストをブロックします。また、ページは厳格な Content-Security-Policy(default-src 'none')を設定した data: URL で配信され、SVG/HTML 入力は <script>、<foreignObject>、インラインの on* ハンドラー、data: 以外の URL を除去するためにサニタイズされます。これらの保護を有効にするために、何かを設定する必要はありません。常に有効です。
Chromium がサンドボックスを起動できない制約のある環境(CI コンテナーの一部や、特定の WSL 構成など)では、render.cjs の実行前に PAINTER_DISABLE_SANDBOX=1 を設定してください。開発者のワークステーションでは設定しないでください。
呼び出し方法
node scripts/render.cjs --type <svg|canvas|html> --in <code-file> --out <out.png> --width <W> --height <H>
または、コードを stdin 経由で渡します。
echo "<svg ...>" | node scripts/render.cjs --type svg --out out.png --width 128 --height 128
オプション:
--type:svg/canvas/htmlのいずれかです。必須です。--in:コードファイルのパスです。省略するか、stdin を使う場合は-を指定します。--out:出力 PNG のパスです。必須です。--width/--height:出力ピクセルサイズです。デフォルトは 128 です。
成功すると、出力 PNG の絶対パスが stdout に 1 行で出力され、終了コードは 0 になります。失敗すると、エラーが stderr に出力され、終了コードは 1 になります。
PNG の背景はデフォルトで透明です。背景色が必要な場合は、SVG/Canvas/HTML 内で明示的に描画してください。
5. リソースのアップロード — 2 段階のパターン
接続された msw-mcp が公開するアセットアップロード(作成)ツールを使ってアップロードします。サーバーのツール一覧を確認し、実際に提供されているスプライト対応の作成ツールを使用してください。正確な呼び出し形式はツール自身のスキーマが基準です。ツール名を推測したり、作成と asset_update_resource_storage_data(既存アセットのバイナリを置き換えるツール)を混同したりしないでください。
接続された MCP にアップロードツールがない場合は、アップロード手順を中止し、代わりに Maker から PNG を登録するようユーザーに依頼してください。その後、ユーザーから提供された RUID を使うか、msw-search で見つけてください。
ツールの種類にかかわらず、手順は同じ 2 段階のパターンで、同じツールを 2 回呼び出します。
🔒 セキュリティ — 署名付き URL の取り扱い(W007)。 手順 1 で返される
presignedUrlは、有効期間の短い署名付き認証情報です(保持している人は誰でも、有効期限までそのストレージ領域に PUT できます)。秘密情報として扱ってください。
- アシスタントからユーザーへの応答、コミットメッセージ、ログ、その後のプロンプトでは、「何をしたか」の報告を含め、URL やそのクエリパラメーター(
X-Amz-Signature、X-Amz-Credentialなど)を決してそのまま出力、引用、言い換え、記載しないでください。- シェルを呼び出す際は、以下に示すように URL をコマンドライン引数ではなく、
PAINTER_PRESIGNED_URL環境変数で渡してください。コマンドライン引数は他のプロセスから/proc/*/cmdline(Linux/macOS)やGet-Process(Windows)を通じて確認でき、シェル履歴にも記録されます。- 手順 3 を呼び出す際は、URL を
fileUrlツール引数に直接渡してください。先にコードブロックや Markdown に記載してユーザーに見せてはいけません。- PUT に失敗した場合(通常は URL の有効期限切れによる
401/403)、URL を破棄し、手順 1 からやり直してください。他の場所で再利用しないでください。
手順 1 — 署名付き URL をリクエストする
fileUrl を省略してアップロードツールを呼び出します。スキーマで必須のフィールドを入力してください。通常は category: "sprite"、既存アセットに合った subcategory(下記参照)、name、1~2 文の description、およびスキーマで求められる場合は fileName/contentLength などのファイルメタデータです。
応答には presignedUrl が含まれています。エージェントの推論コンテキスト内だけで保持し、チャットの出力には決して表示しないでください。
Step 2 — PNG バイナリを PUT する(URL は環境変数経由で渡します)
⚡
Invoke-WebRequestではなくcurl.exeを使用してください(P001 — 「アップロード後にフリーズする」バグ)。 Windows PowerShell 5.1 では、-UseBasicParsingを指定しない限り、Invoke-WebRequestは Internet Explorer エンジンを使って HTTP レスポンスを解析します。Windows 11 では IE が 削除または無効化されているため、呼び出しが IE の「初回起動時の設定」でブロックされ、バイト列のアップロードがすでに完了した後も長時間フリーズしたように見えます(MCP ツール自体の処理は約 45 ms で完了し、停止しているのはこの手順だけです)。curl.exe(Windows 10 1803 以降とすべての Windows 11 でSystem32に同梱されています)は IE に依存せず、PowerShell と Git Bash のどちらでも同じように動作するため、両方のシェルで優先して使用してください。
PowerShell(推奨 — curl.exe):
$env:PAINTER_PRESIGNED_URL = "<presignedUrl from step 1>"
try {
# Feed url/request/upload-file to curl via a stdin config (-K -) so the URL
# never lands in argv (visible via Get-Process) or shell history.
"url = `"$env:PAINTER_PRESIGNED_URL`"`nrequest = `"PUT`"`nupload-file = `"out.png`"" | curl.exe -K -
} finally {
Remove-Item Env:\PAINTER_PRESIGNED_URL -ErrorAction SilentlyContinue
}
bash(Git for Windows / WSL — curl):
# 1) Assign on its OWN statement (export), NOT as an inline prefix.
# `VAR=… curl … "$VAR"` does NOT work: the shell expands "$VAR" on the
# same command line BEFORE the assignment takes effect, so curl receives
# an empty URL and fails with "curl: option : blank argument…".
export PAINTER_PRESIGNED_URL="<presignedUrl from step 1>"
# 2) Feed the URL to curl via a config file read from stdin (-K -). Passing it
# as a normal argument (curl … "$PAINTER_PRESIGNED_URL") would expand the URL
# straight into argv, where it is visible via `ps` / /proc/<pid>/cmdline —
# -K - keeps it out of the argument list entirely.
printf 'url = "%s"\nrequest = "PUT"\nupload-file = "out.png"\n' "$PAINTER_PRESIGNED_URL" | curl -K -
unset PAINTER_PRESIGNED_URL
PUT は単純なバイナリアップロードです。署名は事前署名 URL に埋め込まれているため、認証ヘッダーは不要です。両方のシェルで -K -(標準入力から設定を読み込む)形式を使用すると、URL が ps / Get-Process の引数リストやシェル履歴に残りません。
フォールバックとしてのみ使用 — Invoke-WebRequest。 curl.exe が本当に利用できない場合は、-UseBasicParsing を必ず追加してください(IE エンジンをスキップするため、フリーズしません)。また、進行状況バーも無効にしてください(PowerShell 5.1 の別のバグにより、転送が 10~50 倍遅くなります):
$env:PAINTER_PRESIGNED_URL = "<presignedUrl from step 1>"
$ProgressPreference = 'SilentlyContinue'
try {
Invoke-WebRequest -Method PUT -InFile out.png -Uri $env:PAINTER_PRESIGNED_URL `
-ContentType "image/png" -UseBasicParsing
} finally {
Remove-Item Env:\PAINTER_PRESIGNED_URL -ErrorAction SilentlyContinue
}
Step 3 — アップロード完了を報告する
同じツールを同じ引数で再度呼び出し、fileUrl に手順 1 の事前署名 URL を設定します(ツールの引数として直接渡してください。チャットやコードブロックに出力しないでください)。
レスポンスにはスプライトの RUID が含まれます。これが最終成果物です。この呼び出しが返ったら、URL は使用済みとして扱い、保持しないでください。
Step 4 — スプライトのプロパティを登録する
作成ツールは properties を受け付けません。手順 3 で RUID が返ったら、アセットの guid を指定して、すぐに mcp__msw-mcp__asset_update_resource_storage_info を呼び出してください。プロパティ項目は、小文字の { "key": "...", "value": "..." } 形式で、値は 文字列にします(リソースの レスポンス では Properties: [{ "Key", "Value" }] と表示されますが、入力でこの大文字小文字の表記をまねないでください)。
| Key | Value | 意味 |
|---|---|---|
pivot_x / pivot_y | 数値文字列 | スプライトのピボット |
border_left / border_right / border_top / border_bottom | 数値文字列 | 9 スライスの境界線(px) |
filter_mode | Point / Bilinear / Trilinear | テクスチャフィルタリング |
wrap_mode | Repeat / Clamp / Mirror / MirrorOnce | テクスチャのラップ方式 |
Painter のデフォルト値:filter_mode=Point(Bilinear は粗いピクセルやメープルのピクセルのエッジをにじませます)、wrap_mode=Clamp、pivot_x=0.5。アイコン / UI パネルでは pivot_y=0.5、地面に立つキャラクターや小道具では pivot_y=0.0 にします(目視確認で足元のずれが見られた場合にのみ調整してください)。border_* を 0 以外に設定するのは、スプライトが 9 スライスの UI フレーム(ボタン / パネル / ゲージ)の場合に限ります。さらに .ui 側で SpriteGUIRendererComponent.Type = Sliced(1) が必要です(component-api.md §「SpriteGUIRenderer — ImageType Selection」を参照)。この表にないプロパティキーや列挙値を作らないでください。接続先 MCP のツール一覧に asset_update_resource_storage_info がない場合は、別のツールを呼び出さず、設定する予定のプロパティ値をユーザーに報告してください。
サブカテゴリの選び方
まず、asset_search_resources または asset_list_account_resources を使って既存スプライトのサブカテゴリの分布を確認し、それに合わせてください。判断に迷う場合は、object / etc などの汎用的な値を使用してください。
6. 報告形式
Painter タスクが完了したら、ユーザーに次の内容だけを渡してください:
RUID: <received RUID>
Style: <chunky | maple>
<1–2 sentence description: what you drew, at what size, and what sprite it was registered as>
§3.5 のセットの場合は、RUID: の行を、セット内の順序でスプライトごとに <sprite name>: <RUID> の行に置き換えてください。Style と説明はセット全体を対象として、それぞれ 1 つだけ記載します。
エンティティの作成 / 移動 / スポーン、スクリプトの作成、UI の編集は Painter の対象外です。別のスキルまたは後続の手順で対応してください。
よくある落とし穴
render.cjsの前にnpm ciを実行していない →Cannot find module 'puppeteer'が発生します。必要なのは初回のみです。ロックファイルで固定されたバージョンの puppeteer をインストールするため、npm installではなくnpm ciを使用してください。--width/--heightを省略する → 128×128 にフォールバックするため、ユーザーが別のサイズを希望していた場合は描き直す必要があります。必ず指定してください。- SVG/Canvas のコンテンツが PNG の左上にしか描画されない → 描画コードで独自のサイズ(例:SVG の
width="128" height="128"、または Canvas のscale = 8)を宣言している一方で、render.cjs がより大きい--width/--heightで呼び出されています。コンテンツは宣言されたサイズにしか収まらず、PNG の残りの部分は透明なままになります。修正方法:SVG ではwidth="100%" height="100%"を使用し、Canvas ではc.widthからスケールを算出します。上記の Minimal テンプレートはすでにこの方法に従っています。 - アップロード前に、必ず出力 PNG を読み込む → 設定ミスのある SVG/Canvas は、何も表示されない PNG やキャンバス外に描画された PNG を気付かれないまま生成することがあります。出力を 1 回
Readすれば、サイズの不一致やキャンバスが空になる問題を数秒で検出できます。先にアップロードすると、2 段階のアップロードをやり直すことになります。 - 背景が黒くなる → SVG/Canvas/HTML 内に背景を描画しています。透明にするには、背景の図形自体を削除してください。
- 曲線が滑らかに見える →
chunkyを使用している場合、これはルール違反です。arc()/bezierCurveTo()/グラデーションを削除し、ドットで描き直してください。mapleを使用している場合、滑らかさはグラデーション/曲線 API ではなく、シルエット部分に選択的に配置した AA ピクセルによって表現してください。API の使用禁止ルールは引き続き適用されます。 - Maple スプライトが、色を増やした chunky のように見える → 各面を囲む 1 ピクセル幅の暗い色の輪郭線である selout、および/またはシルエットの縁に配置する選択的な AA を忘れている可能性があります。
style-maple-cartoon.mdの Selout と Selective AA のセクションをもう一度確認してください。 - Chunky スプライトがぼやけて見える → 縁に中間色のピクセルを追加しています。Chunky ではアンチエイリアスがすべて禁止されています。遷移ピクセルを削除し、縁をくっきりさせてください。より柔らかな見た目にしたい場合は、代わりに
mapleに切り替えてください。 - 小さいサイズ(出力 32×32)の Maple スプライトの見た目が悪い → Maple スタイルで selout、AA、特徴を収めるには、出力サイズが 64×64 以上必要です。サイズを大きくするか、
chunkyに切り替えてください。 - セット内のスプライトにずれが生じる(バリエーション間でサイズ/パレット/ベースラインが変わる) → それぞれを独立して描画しています。共通のグリッド/パレット/アンカー定数(§3.5)を使用し、承認済みのシードコードから各バリエーションを再生成してください。アップロード前にセット全体を並べて再確認してください。
- PUT の手順で 401/403 が発生する → 署名付き URL の有効期限が切れているか、URL が正しくありません。手順 1 からやり直してください。
- 完了呼び出しの他の引数を変更する → 手順 1 とまったく同じ引数を渡してください。追加するのは
fileUrlだけです。