Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
msw-git avatar

Msw Painter

  • 4.2k installs
  • 33 repo stars
  • Updated July 29, 2026
  • msw-git/msw-ai-coding-plugins-official

msw-painter is an agent skill that draws pixel art sprites, renders PNGs, and uploads them to MapleStory Worlds resource storage when catalog search fails.

About

MSW Painter is an agent skill for creating hand-drawn pixel art sprites and registering them as MapleStory Worlds sprite resources when msw-search cannot find a suitable RUID. It supports chunky pixel style for icons and tiles and maple cartoon style for characters, NPCs, and mascots with selout outlines and selective anti-aliasing rules. The workflow chooses SVG, Canvas, or HTML medium, picks size from the guide defaulting to 128 by 128, writes code following style references, renders PNG via render.cjs with puppeteer, and uploads through a two-step presigned URL pattern on asset_create_resource_storage_item. Security rules keep presigned URLs out of user-facing output and pass them via environment variables during PUT. The skill forbids curve and gradient APIs, requires reading the output PNG before upload, and reports only the final RUID with style and description. Developers invoke it when users need custom sprites, pixel art icons, maple-style characters, or NPC images that are not available in the MSW asset catalog.

  • Two styles: chunky pixel for icons and maple cartoon for characters and NPCs.
  • Renders SVG, Canvas, or HTML to PNG via sandboxed render.cjs with puppeteer.
  • Two-step presigned upload registers sprites without exposing signed URLs in chat.
  • Calls msw-search first and only paints when no suitable RUID exists.
  • Size guide defaults to 128x128 with style-specific logical grid requirements.

Msw Painter by the numbers

  • 4,191 all-time installs (skills.sh)
  • +540 installs in the week ending Aug 2, 2026 (Skillselion tracking)
  • Ranked #118 of 1,337 Generative Media skills by installs in the Skillselion catalog
  • Security screen: HIGH risk (skills.sh audit)
  • Data as of Aug 2, 2026 (Skillselion catalog sync)
At a glance

msw-painter capabilities & compatibility

Capabilities
pixel art drawing · style selection · png rendering · asset upload · catalog fallback · presigned upload · sprite registration
Use cases
image generation · ui design
From the docs

What msw-painter says it does

Call `msw-search` first, and only invoke this skill when no suitable RUID is found.
SKILL.md
npx skills add https://github.com/msw-git/msw-ai-coding-plugins-official --skill msw-painter

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs4.2k
repo stars33
Security audit1 / 3 scanners passed
Last updatedJuly 29, 2026
Repositorymsw-git/msw-ai-coding-plugins-official

How do I get a custom sprite RUID when msw-search has no matching asset for this icon or character?

Draw pixel art sprites in chunky or maple cartoon style, render PNGs, and upload them to MSW resource storage when search finds no RUID.

Who is it for?

MSW developers needing custom icons, tiles, or maple-style characters after catalog search returns no match.

Skip if: Animation, audio, avatar, or atlas assets, or cases where msw-search already returns a suitable RUID.

When should I use this skill?

Invoke after msw-search fails or when the user explicitly wants hand-drawn pixel art, custom graphics, maple style characters, or direct sprite creation.

What you get

A registered sprite RUID with chunky or maple style art at the requested size ready for entity placement elsewhere.

  • PNG sprite file
  • MSW storage resource with sprite RUID

By the numbers

  • Supports 2 sprite style modes: chunky pixel and maple cartoon
  • Outputs PNG sprites uploaded via msw-mcp asset_create_resource_storage_item

Files

SKILL.mdMarkdownGitHub ↗

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

SituationAction
User wants a specific spriteFirst use msw-search (Resource search section, sprite category)
msw-search returns an RUID that matches the intentUse that RUID directly. Do not invoke painter.
No search results, or all results are unsuitableInvoke 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 stylechunky or maple. See "Choosing the style" below. 3. Decide the size — See references/size-guide.md. Default is 128×128. 4. Write the code — Follow the rules for the chosen style:

  • chunkyreferences/style-chunky-pixel.md
  • maplereferences/style-maple-cartoon.md

5. Render to PNG — Run <SKILL_PATH>/scripts/render.cjs. 6. Upload the resourcemcp__msw-mcp__asset_create_resource_storage_item two-step pattern. 7. 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

MediumRecommended useStrengths
SVGIcons, logos, simple characters, shape-based pixel artIntuitive code, easy to drop 1px <rect> dots
CanvasProcedural patterns, iterative logic (loop-drawn textures / noise)Generate complex patterns via JS programming logic
HTMLComposite layouts that can be styled quickly with CSSRarely used — SVG/Canvas is usually a better fit for pixel art

Minimal SVG template

<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"/>
  <!-- Place dots one by one with 1px rects -->
</svg>
⚠️ 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

// `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

<!doctype html>
<html><body style="margin:0; image-rendering: pixelated;">
  <!-- Anything you like -->
</body></html>

---

2. Choosing the style

StyleRecommended useLook & feelLogical gridOutlineShading
`chunky`Icons, buttons, tiles, blocks, simple propsRetro / 8-bit / NES-SNESSmall (16×16, 32×32)Black or white, 1px2–4 stepped levels, NO AA
`maple`Characters, NPCs, monsters, cute mascotsMapleStory / storybook / cartoonLarger (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-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)

UseRecommended size
Icon / button48×48 ~ 64×64
Character / item / NPC / monster96×96 ~ 128×128
Tile / floor / block64×64 ~ 128×128
Background / large object256×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.

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

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@<version> 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 <script>, <foreignObject>, inline on* handlers, and non-data: URLs. You do not need to do anything to opt in — these protections are always on.

If you are in a constrained environment where Chromium cannot start its sandbox (some CI containers, certain WSL setups), set PAINTER_DISABLE_SANDBOX=1 before invoking render.cjs. Do not set this on a developer workstation.

Invocation

node <SKILL_PATH>/scripts/render.cjs --type <svg|canvas|html> --in <code-file> --out <out.png> --width <W> --height <H>

Or pass the code via stdin:

echo "<svg ...>" | node <SKILL_PATH>/scripts/render.cjs --type svg --out out.png --width 128 --height 128

Options:

  • --type: One of svg / canvas / html. Required.
  • --in: Path to the code file. Omit or use - for stdin.
  • --out: Output PNG path. Required.
  • --width / --height: Output pixel size. Default 128.

On success, the absolute path of the output PNG is printed to stdout on a single line and exit code is 0. On failure, the error is printed to stderr and exit code is 1.

The PNG defaults to a transparent background. If you need a background color, draw it explicitly inside the SVG/Canvas/HTML.

---

5. Resource upload — two-step pattern

mcp__msw-mcp__asset_create_resource_storage_item is called twice.

🔒 Security — handling the presigned URL (W007). The presignedUrl returned in step 1 is a short-lived signed credential (anyone holding it can PUT to that storage slot until it expires). Treat it as a secret:

>

- Never echo, quote, paraphrase, or include the URL or any of its query parameters (X-Amz-Signature, X-Amz-Credential, etc.) in the assistant's user-facing response, in commit messages, in logs, or in any subsequent prompt — including when reporting "what you did".
- When invoking the shell, pass the URL via the PAINTER_PRESIGNED_URL environment variable as shown below, not as a command-line argument. Command-line arguments are visible to other processes via /proc/*/cmdline (Linux/macOS) and Get-Process (Windows), and they are recorded in shell history.
- When invoking step 3, pass the URL directly as the fileUrl tool argument — do not copy it into a code block or markdown for the user to see first.
- If the PUT step fails (typically 401/403 → URL expired), discard the URL and restart from step 1. Do not reuse it elsewhere.

Step 1 — request a presigned URL

mcp__msw-mcp__asset_create_resource_storage_item({
  category: "sprite",
  subcategory: "<appropriate subcategory>",   // e.g. "monster", "npc", "object", "icon"
  name: "<resource name>",
  description: "<1–2 sentence description>",
  makerOwnerType: 0,                          // 0 = Account
  makerOwnerId: "<account id>",               // look up in advance with mcp__msw-mcp__account_get_my_user_id
  // omit fileUrl in this step
})

The response contains a presignedUrl. Keep it inside the agent's reasoning context only — do not surface it in chat output.

Step 2 — PUT the PNG binary (URL passed via env var)

PowerShell:

$env:PAINTER_PRESIGNED_URL = "<presignedUrl from step 1>"
try {
  Invoke-WebRequest -Method PUT -InFile out.png -Uri $env:PAINTER_PRESIGNED_URL -ContentType "image/png"
} finally {
  Remove-Item Env:\PAINTER_PRESIGNED_URL -ErrorAction SilentlyContinue
}

bash (Git for Windows / WSL):

PAINTER_PRESIGNED_URL="<presignedUrl from step 1>" \
  curl -X PUT -T out.png "$PAINTER_PRESIGNED_URL" && \
  unset PAINTER_PRESIGNED_URL

The PUT itself is a plain binary upload — no auth headers are needed (the signature is embedded in the presigned URL). The env-var pattern keeps the URL out of Get-Process / ps-visible argument lists and out of shell history.

Step 3 — report upload completion

mcp__msw-mcp__asset_create_resource_storage_item({
  ...same arguments,
  fileUrl: "<presignedUrl from step 1>"   // pass directly as tool arg, do not echo
})

The response contains the sprite RUID. That is the final deliverable. After this call returns, treat the URL as fully consumed — do not retain it.

Choosing a subcategory

First inspect the subcategory distribution of existing sprites with asset_search_resources or asset_list_account_resources and match it. When in doubt, fall back to a generic value such as object / etc.

---

6. Report format

When the painter task is done, hand the user only this:

RUID: <received RUID>
Style: <chunky | maple>
<1–2 sentence description: what you drew, at what size, and what sprite it was registered as>

Entity creation/movement/spawn, script authoring, and UI editing are outside the painter's scope. Handle those in another skill or a follow-up step.

---

Common pitfalls

  • Not running `npm ci` before `render.cjs`Cannot find module 'puppeteer'. Only needed the first time. Use npm ci (not npm install) so the lockfile-pinned puppeteer version is installed.
  • Omitting `--width` / `--height` → It falls back to 128×128, and if the user wanted a different size you have to redraw. Always specify it.
  • SVG/Canvas content drawn only in the top-left corner of the PNG → The drawing code declared its own dimensions (e.g. SVG width="128" height="128" or Canvas scale = 8) but render.cjs was invoked with a larger --width/--height. The content fills only its declared size and the rest of the PNG stays transparent. Fix: SVG uses width="100%" height="100%"; Canvas derives scale from c.width. The Minimal templates above already follow this.
  • Always Read the output PNG before uploading → A misconfigured SVG/Canvas can silently produce a blank or off-canvas PNG. One Read on the output catches the size-mismatch and blank-canvas bugs in seconds; uploading first means re-doing the 2-step upload.
  • Background comes out black → You drew a background inside the SVG/Canvas/HTML. To keep it transparent, remove the background shape itself.
  • Curves look smooth → If using chunky, this is a rule violation; remove arc()/bezierCurveTo()/gradients and redraw with dots. If using maple, smoothness should come from selective AA pixels at the silhouette, NOT from gradient/curve APIs — the API ban still applies.
  • Maple sprite looks like chunky with extra colors → You probably forgot the selout (1-pixel darker-color outline around each surface) and/or the selective AA at silhouette edges. Re-check style-maple-cartoon.md Selout and Selective AA sections.
  • Chunky sprite looks mushy / blurry → You added intermediate-color pixels on edges. Chunky forbids ALL anti-aliasing — remove transition pixels and keep edges sharp. If a softer look is desired, switch to maple instead.
  • Maple sprite at small size (32×32 output) looks bad → Maple style needs ≥ 64×64 output to fit selout + AA + features. Either increase size or switch to chunky.
  • PUT step fails with 401/403 → The presigned URL expired or is wrong. Restart from step 1.
  • Changing other metadata in the step-2 completion call → Pass the exact same category/subcategory/name/description/makerOwnerType/makerOwnerId as in step 1. Only add fileUrl.

Related skills

How it compares

Pick msw-painter over generic image generators when you need MSW-compatible pixel sprites with a registered RUID after catalog search misses.

FAQ

When should painter run instead of msw-search?

Only when msw-search returns no suitable RUID or the user explicitly requests hand-drawn art.

What are the two supported art styles?

Chunky pixel for icons and tiles, and maple cartoon for characters, NPCs, and cute mascots.

How are presigned upload URLs handled securely?

Pass URLs via PAINTER_PRESIGNED_URL env vars during PUT and never echo them in user-facing responses.

Is Msw Painter safe to install?

skills.sh reports 1 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.