--- name: msw-painter description: "When msw-search cannot find a suitable sprite RUID, draw a pixel art sprite directly with SVG / HTML5 Canvas / HTML code, render it to PNG, and upload it via the msw-mcp asset upload tool to obtain a sprite RUID (if no upload tool is connected, guide the user to register it through Maker). Two style modes are supported: chunky pixel (retro / icon / tile feel) and maple cartoon (MapleStory-inspired character / NPC feel). Triggers: draw sprite directly, create sprite, image generation, custom graphic, pixel art, cartoon sprite, maple style, chibi character, painter, draw a sprite, make an icon, create NPC image directly, draw a slime, custom sprite." --- # MSW Painter A workflow for registering a hand-drawn pixel art sprite as a sprite resource. **Call `msw-search` first, and only invoke this skill when no suitable RUID is found.** This skill is dedicated to the sprite category. It does not handle animation / audio / avatar / atlas. The painter supports two pixel art **styles**: **chunky pixel** (retro, icon/tile feel) and **maple cartoon** (MapleStory-inspired, character/NPC feel). Pick one before writing code — see step 2 below. --- ## When to invoke | Situation | Action | |-----------|--------| | User wants a specific sprite | First use `msw-search` (Resource search section, sprite category) | | `msw-search` returns an RUID that matches the intent | Use that RUID directly. **Do not invoke painter.** | | No search results, or all results are unsuitable | Invoke painter → create directly | | User explicitly says "I need a hand-drawn looking character/icon" | Invoke painter directly | --- ## Workflow 1. **Choose the medium** — One of SVG / Canvas / HTML. See "Choosing the medium" below. 2. **Choose the style** — `chunky` or `maple`. See "Choosing the style" below. 3. **Decide the size** — See [references/size-guide.md](references/size-guide.md). Default is 128×128. 4. **Write the code** — Follow the rules for the chosen style: - `chunky` → [references/style-chunky-pixel.md](references/style-chunky-pixel.md) - `maple` → [references/style-maple-cartoon.md](references/style-maple-cartoon.md) 5. **Render to PNG** — Run `scripts/render.cjs`. 6. **Upload the resource** — the msw-mcp asset upload tool, two-step presigned pattern (§5). If the connected MCP has no upload tool, ask the user to register the PNG through Maker. 7. **Register sprite properties** — `asset_update_resource_storage_info` right after upload: `filter_mode` / `wrap_mode` / pivot, plus 9-slice borders for UI frame sprites. See "Step 4" below. 8. **Report the result** — RUID + a 1–2 sentence description (include which style was used). Entity placement / script application is outside the painter's scope. --- ## 1. Choosing the medium | Medium | Recommended use | Strengths | |--------|-----------------|-----------| | **SVG** | Icons, logos, simple characters, shape-based pixel art | Intuitive code, easy to drop 1px `` dots | | **Canvas** | Procedural patterns, iterative logic (loop-drawn textures / noise) | Generate complex patterns via JS programming logic | | **HTML** | Composite layouts that can be styled quickly with CSS | Rarely used — SVG/Canvas is usually a better fit for pixel art | ### Minimal SVG template ```xml ``` > ⚠️ Use `width="100%" height="100%"` (NOT a fixed pixel count). The SVG element draws at its **own** declared size inside the render.cjs viewport — if you hard-code 128 but render at `--width 1024`, the SVG fills only the top-left 128px and the rest of the PNG is transparent. `100%` makes the SVG fill whatever canvas `--width`/`--height` specifies. ### Minimal Canvas template ```javascript // `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); ``` ### Minimal HTML template ```html ``` --- ## 2. Choosing the style | Style | Recommended use | Look & feel | Logical grid | Outline | Shading | |-------|-----------------|-------------|--------------|---------|---------| | **`chunky`** | Icons, buttons, tiles, blocks, simple props | Retro / 8-bit / NES-SNES | Small (16×16, 32×32) | Black or white, 1px | 2–4 stepped levels, NO AA | | **`maple`** | Characters, NPCs, monsters, cute mascots | MapleStory / storybook / cartoon | Larger (32×32 ~ 128×128) | **Selout** (darker version of fill color) | 4–6 stepped levels + **selective AA** on silhouette + optional 2×2 dithering | ### Defaults when in doubt - Icon / button / tile / block → **`chunky`** - Character / NPC / monster / mascot / "cute" requests / "draw a slime" → **`maple`** - User says "retro" / "8-bit" / "NES" / "minimal" → **`chunky`** - User says "MapleStory" / "cute" / "cartoon" / "chibi" / "illustrated" → **`maple`** Full per-style rules: - [references/style-chunky-pixel.md](references/style-chunky-pixel.md) - [references/style-maple-cartoon.md](references/style-maple-cartoon.md) Both styles share the same forbidden APIs (no curve APIs, no gradient APIs, no fractional coordinates, no `filter: blur`/`drop-shadow`). They differ in palette richness, outline color, AA, and working grid. --- ## 3. Size guide (summary) | Use | Recommended size | |-----|------------------| | Icon / button | 48×48 ~ 64×64 | | Character / item / NPC / monster | 96×96 ~ 128×128 | | Tile / floor / block | 64×64 ~ 128×128 | | Background / large object | 256×256 or larger (only on explicit request) | The default is **128×128**. For style-specific working-grid tables (chunky uses a small logical grid like 16×16; maple uses a larger one like 64×64) and SD character proportions, see [references/size-guide.md](references/size-guide.md). > If the requested output is **below 64×64**, the `maple` style does not have enough pixels for selout + AA + facial features — either bump the output size to 64+ or fall back to `chunky`. --- ## 4. PNG render — `render.cjs` ### One-time dependency install ```bash cd scripts && npm ci ``` This installs `puppeteer` (~200MB including headless Chromium) from the committed `package-lock.json`. It is separate from other base skill dependencies, so run this only the first time you use painter. > 🔒 Use `npm ci`, **not** `npm install`. `npm ci` installs exactly the versions pinned in `package-lock.json` and fails if the lockfile and `package.json` disagree — this is the supply-chain integrity guarantee for W012. Never edit `package-lock.json` by hand; if you need to bump puppeteer, run `npm install puppeteer@` locally and commit the regenerated lockfile. ### Sandboxing & network isolation `render.cjs` runs the headless Chromium with the OS sandbox **enabled** by default and blocks **all** network requests from the rendered page. The page is also served via a `data:` URL with a strict `Content-Security-Policy` (`default-src 'none'`), and the SVG / HTML input is sanitized to strip `