{
  "markdown": "# undraw\n\n**English** | [한국어](README.ko.md)\n\nSearch unDraw's [illustrations](https://undraw.co) and\n[handcrafts](https://handcrafts.undraw.co) from your coding agent and save an SVG\nstraight into your project, recolored to match your theme.\n\n```\n> find an illustration for the login page\n\n8 results for \"login\":\n 1. Biometric Login — https://undraw.co/illustration/biometric-login_v832\n 2. Secure login    — https://undraw.co/illustration/secure-login_m11a\n ...\n\n> the second one\n\nFound primary color #3b82f6 in tailwind.config.ts. Save to public/illustrations/?\n\n> yep\n\nSaved public/illustrations/undraw_secure-login_m11a.svg\nRecolored #6c63ff -> #3b82f6\n```\n\nHandcrafts are the small hand-drawn accents — arrows, underlines, circles. They\nare drawn in `currentColor`, so leaving the color alone is usually the point:\n\n```\n> add a hand-drawn underline under the pricing heading\n\n7 results for \"underline\":\n 1. Underline (id 950) — underline, stress, underscore, emphasis   [bold, thin]\n ...\n\n> the first one, thin\n\nSaved src/components/pricing/icons/undraw_underline_950_thin.svg\nKept currentColor — the artwork inherits the CSS `color` around it.\n```\n\n## Quick start\n\nOn Claude Code:\n\n```bash\n/plugin marketplace add CaesiumY/undraw-plugin\n```\n\nThen `/plugin install undraw@undraw-plugin` and ask for what you need in plain\nlanguage — *\"find an illustration for the empty cart state\"*, or *\"put a\nhand-drawn arrow next to the CTA\"*. The agent searches, shows you candidates,\nreads your theme color out of your stylesheet, and writes the file once you\nconfirm. Other hosts are covered under [Install](#install).\n\nTo see what it does before installing anything, run the bundled CLI from a\nclone. Node 18+ is the only prerequisite — there is nothing to build or fetch:\n\n```bash\ngit clone https://github.com/CaesiumY/undraw-plugin\nnode undraw-plugin/scripts/undraw.mjs search \"login\" --limit 5\nnode undraw-plugin/scripts/undraw.mjs handcrafts search \"arrow\" --limit 5\n```\n\n## Install\n\n### Claude Code\n\n```bash\n/plugin marketplace add CaesiumY/undraw-plugin\n```\n\nThen `/plugin install undraw@undraw-plugin`.\n\n### Codex, Cursor, Copilot, VS Code, Kiro\n\nShips an [Agent Plugins 1.0](https://agent-plugins.org) manifest\n(`plugin.json`), which these hosts consume. Install through your host's plugin\nmechanism pointing at this repository.\n\n### Gemini CLI\n\n```bash\ngemini extensions install https://github.com/CaesiumY/undraw-plugin\n```\n\n### Any host that reads SKILL.md — manual\n\nClone the repo and link the skills into wherever your agent scans for them\n(commonly `.agents/skills/`, `~/.claude/skills/`, `.gemini/skills/`):\n\n```bash\ngit clone https://github.com/CaesiumY/undraw-plugin\n```\n\n```bash\nln -s \"$PWD/undraw-plugin/skills/undraw-illustrations\" ~/.agents/skills/undraw-illustrations\n```\n\n```bash\nln -s \"$PWD/undraw-plugin/skills/undraw-handcrafts\" ~/.agents/skills/undraw-handcrafts\n```\n\nEither can be installed without the other — neither reads the other's files.\n\nCopying instead of linking also works — the skills detect a missing script and\nfall back to a no-Node path.\n\n## Requirements\n\nNode 18+ for the fast path. Without it the illustrations skill still works — it\nfalls back to `curl` (or PowerShell on Windows) and walks the same flow through\nthe agent, with the color conversion done by hand.\n\nHandcrafts degrades further without Node. That site has no API at all, so the\nno-Node path can list the catalog but hands the actual download back to the\nwebsite's own button. Install Node if you want handcrafts.\n\nThere are no npm dependencies and nothing to build.\n\n## What triggers the skills\n\nYou do not invoke anything by name. Asking for artwork is enough, and which of\nthe two skills answers is decided by what you ask for:\n\n| You say | What happens |\n|---|---|\n| \"find an illustration for the login page\" | searches `login` — the subject, not the page purpose |\n| \"we need art for the 404 page\" | searches `404` / `error` |\n| \"빈 상태에 넣을 그림 찾아줘\" | Korean requests trigger the same flow |\n| \"회원가입 페이지 일러스트\" | ditto — the skill's triggers are bilingual |\n| \"undraw에서 가져와줘\" | names the source directly |\n| \"add a hand-drawn arrow pointing at the CTA\" | handcrafts — an accent, not a scene |\n| \"제목 밑에 손그림 밑줄 넣어줘\" | handcrafts, in Korean |\n\nThe dividing line is scene versus mark. Hero images, empty states, error pages,\nonboarding art and placeholder vectors are **illustrations**. Arrows, underlines,\ncircles, checkmarks, stars and doodles that point at or emphasize something are\n**handcrafts**.\n\nBoth route through the same six steps: search → you pick → propose a directory →\npropose a color → save → report. Both confirm the path and the color before\nwriting, and neither picks the artwork for you unless you tell it to.\n\nThey are two separate skills rather than one with a branch, because the trigger\nis the `description` field: one description covering both intents fires on both\nand then has to guess. Handing back a 200-byte arrow when you asked for login\npage art is the failure that split avoids.\n\n## What's different\n\n**Your stylesheet's color format is the input format.** Whatever is already\ndeclared — shadcn's bare HSL channels (`214 92% 58%`), Tailwind v4's\n`oklch(0.514 0.222 16.935)`, `rgb(49 130 246)` — goes straight to `--color`.\nNothing gets converted by hand.\n\n**Handcrafts keep `currentColor` unless you ask otherwise.** Not converting is\nthe better default: the mark then inherits the CSS `color` around it and follows\ndark mode and hover states for free. The CLI says so on every save, including the\ncaveat that an `<img src>` or a CSS background cannot inherit and renders it\nblack.\n\n**CDN URLs are never assembled from slugs.** The catalog is inconsistent about\nits path segment, and a single search returns both spellings side by side:\n\n```\n1. Biometric Login   → https://cdn.undraw.co/illustration/biometric-login_v832.svg\n2. Fingerprint login → https://cdn.undraw.co/illustrations/fingerprint-login_19qv.svg\n```\n\nA URL guessed from a slug 404s on much of the library, so the `media` field from\n`search` is passed through verbatim.\n\n**Handcraft filenames carry the id, because titles are not unique.** Two catalog\nentries are both called `Circled Arrow`. Under the site's own naming both are\n`undraw_circled-arrow.svg`, so saving the second into a directory that already\nholds the first destroys it silently. Files are `undraw_<title-slug>_<id>.svg`\ninstead, with `_thin` appended for the thin variant.\n\n**It refuses to overwrite what it cannot replace.** `--out` is a file only when\nit ends in `.svg`. Pointed at an existing `hero.png`, it exits 1 instead of\nwriting SVG text over a raster asset.\n\n**No dependencies, no build, no lock file.** One `.mjs` file on Node 18+.\nWithout Node the illustrations skill falls back to a `curl`-only path that walks\nthe same flow — though there you convert the color yourself, and the script's\nresponse and filename checks do not apply.\n\n**It fetches one file at a time, by design.** No bulk download, no local mirror,\nno cache on disk, and every saved file carries the same attribution attributes\nthat unDraw's own downloaders write. [Licensing](#licensing) explains why that\nmatters.\n\n**Every test pins a real defect.** No runner, no dependencies, no network — each\nassertion guards a bug that actually occurred or an oddity that is actually in\nthe catalog, so a failure is a regression rather than a style disagreement.\n\n## Using the CLI directly\n\nThe bundled script is usable on its own:\n\n```bash\nnode scripts/undraw.mjs search \"empty cart\" --limit 5\nnode scripts/undraw.mjs search \"empty cart\" --json\n\nnode scripts/undraw.mjs get \"https://cdn.undraw.co/illustration/foo_ab12.svg\" \\\n  --out public/illustrations --color \"#3b82f6\"\n```\n\nExit codes: `0` success, `1` usage error — including a handcraft name matching\nmore than one entry, `2` network/HTTP error, or handcrafts.undraw.co's page\nbundle changed shape, `3` no results, the asset 404'd, the requested style does\nnot exist, or the response was not an SVG, `4` could not write the output file.\n\n`--color` takes whatever form your stylesheet already uses — you should not have\nto convert anything by hand:\n\n| Input | Result |\n|---|---|\n| `#3b82f6` | used as-is |\n| `214 92% 58%` | shadcn/ui bare HSL channels → converted to hex |\n| `hsl(214 92% 58%)` | converted to hex |\n| `rgb(49 130 246)` / `rgb(50% 20% 90%)` | converted to hex |\n| `oklch(0.514 0.222 16.935)` | written through unchanged (needs a CSS Color 4 renderer) |\n\nAlpha is dropped when an `hsl()` or `rgb()` value is converted to hex — an SVG\n`fill` takes the color only — and the output says so. Hex and CSS Color 4 values\nare written through as given, alpha included.\n\n`--out` is treated as a file only when it ends in `.svg`; anything else is a\ndirectory and is created if missing. Pointing it at an existing file that is not\na `.svg` is refused rather than silently overwritten — writing SVG text over\n`hero.png` is never what was meant.\n\n`--limit` may not exceed 50 — a larger value is rejected rather than clamped —\nand a search stops after 20 pages or as soon as a page returns nothing new, so\nthe loop cannot run away if the API changes shape.\n\n**Pass the `media` URL from `search` verbatim.** CDN paths are not derivable\nfrom slugs — newer illustrations live under `/illustration/` and older ones\nunder `/illustrations/`, so assembling a URL from a slug 404s on much of the\ncatalog. `get` accepts `cdn.undraw.co` URLs only; the `preview` URL printed\nbeside it is a web page, not the asset, and is rejected.\n\n### Handcrafts\n\n```bash\nnode scripts/undraw.mjs handcrafts search \"underline\" --limit 5\nnode scripts/undraw.mjs handcrafts get 950 --out src/components/pricing/icons --style thin\n```\n\n**Pass the id, not the title.** Titles are not unique, so a name matching more\nthan one entry is rejected with exit 1 and a list of the ids rather than resolved\nto a guess. A name matching exactly one (`arrow` → `Arrow`) does work.\n\n**`--color` is optional here, and usually best left off** — see *What's\ndifferent* above. Pass one only when the file will be used somewhere that cannot\ninherit.\n\n`--style` is `bold` (the site's default) or `thin`. Not every entry ships both:\n`Sneaker` has only a thin variant. Omitting `--style` falls back to whichever\nexists and says so; naming a missing one explicitly is exit 3, because then you\nasked for it.\n\nThere are no preview URLs — handcrafts.undraw.co is a single page with a modal,\nso no per-item link exists. Browse them at <https://handcrafts.undraw.co/app>.\n\n## Tests\n\n```bash\nnode scripts/undraw.test.mjs\n```\n\nNo runner, no dependencies, no network. Every assertion pins a defect that was\nreal at some point, so a failure is a regression rather than a style opinion —\nread the case before changing the code it guards.\n\n## Scope\n\nCovered: the [illustration library](https://undraw.co) and\n[Handcrafts](https://handcrafts.undraw.co).\n\nunDraw's other two open tools are out of scope because neither has a catalog to\nwrap — not merely because neither has an API:\n\n- [Code Videos](https://videos.undraw.co) turns *your own* pasted code snippet\n  into an MP4. There are no assets in it at all.\n- [Banner cards](https://cards.undraw.co) composes a card around an image *you*\n  supply (\"click on the card or drag a new image inside\"). Its editor bundle\n  carries no preset or template list, and its sitemap is two URLs.\n\n**Handcrafts is the fragile one, and worth knowing why before relying on it.**\nIt has no API; its catalog is a JavaScript array literal inlined into a page\nchunk whose filename hash changes on every deploy. That is mitigated rather than\nsolved:\n\n- the chunk path is discovered at runtime from `/app`, so a new hash costs\n  nothing;\n- the parser reads fields by key and skips entries it cannot follow, so an extra\n  field or a reordering is not fatal;\n- if fewer than 20 usable entries come back it stops with exit 2 and a pointer to\n  the issue tracker, instead of silently returning a short list;\n- the parser is pinned by fixture tests covering the catalog's real oddities — an\n  artwork-less placeholder entry, an entry with only one style variant, and two\n  entries sharing a title.\n\nA redesign upstream still breaks it. It fails loudly when that happens.\n\n## Licensing\n\nThe plugin code in this repository is MIT (see `LICENSE`). **The artwork is\nnot.** The two libraries have separate licenses and they are not identical —\nread both before using this tool: <https://undraw.co/license> and\n<https://handcrafts.undraw.co/license>\n\n### Illustrations\n\nunDraw is generous about *using* assets:\n\n> \"You can use them for noncommercial and commercial purposes. You do not need\n> to ask permission from or provide credit to the creator or unDraw.\"\n\nIts own plain-language summary of the limits is blunter, and names this kind of\ntool directly:\n\n> \"Just don't try to replicate unDraw, use for machine learning, redistribute in\n> packs the illustrations or create integrations for it.\"\n\nThe license body restricts how assets are *acquired*:\n\n> \"This license does not include the right to compile assets, vectors or images\n> from unDraw to replicate a similar or competing service, in any form or\n> distribute the assets in packs or otherwise. This extends to automated and\n> non-automated ways to link, embed, scrape, search or download the assets\n> included on the website without our consent.\"\n\nand prohibits AI training use outright:\n\n> \"This license explicitly prohibits the use of unDraw assets, vectors, and\n> images for training, fine-tuning, or developing artificial intelligence,\n> machine learning models, or similar technologies.\"\n\nAdditionally, `undraw.co/robots.txt` names several AI user agents — including\n`anthropic-ai` — and disallows `/*.svg$` and `/download/*` for them, under the\nheading `# AI Training Protection - only for artwork`.\n\nThis tool automates acquisition, and it is an integration — both of which the\nlicense asks people not to build. It is published on the understanding that\nusers fetch individual illustrations for their own projects, the same thing the\nwebsite's download button does, and not to build a mirror or a competing\ncatalog. It does not bulk-download, does not redistribute assets, and writes\ninto each SVG the same `artist` and `copyright` attributes that unDraw's own\ndownloader does.\n\nIf you need a use beyond that, contact unDraw for consent. If you want\nillustrations under an unambiguous open license, look at\n[Open Peeps](https://openpeeps.com) (CC0) or\n[Humaaans](https://humaaans.com) (CC BY 4.0) instead.\n\n### Handcrafts\n\nThe Handcrafts license carries the same two asks — do not replicate it, do not\ncreate integrations for it — and extends the restriction one step further than\nthe illustration license does. Its restriction clause reads:\n\n> \"automated and non-automated ways to link, embed, scrape, search, use for\n> generative AI training purposes or download the assets included on the website\n> and integration without our consent.\"\n\nThe phrase **\"and integration\"** does not appear in the illustration license,\nnor does \"generative AI training purposes\" inside this clause. So the restricted\nsurface here explicitly includes assets reached through an integration, not only\nassets on the website.\n\n**By either license's wording this plugin is an integration.** That is true for\nillustrations too — see above — and is stated in both places rather than glossed\nover, because you may reasonably decide it rules the whole tool out for you.\n\nIt is published on the same understanding as the rest of the tool: a user\nfetching one mark for their own project, which is what the site's own Download\nbutton does. Concretely, the handcrafts path\n\n- fetches on demand and writes exactly one file per `get`;\n- **never caches or writes the catalog to disk**, deliberately — persisting it\n  would be the \"compile assets\" the license forbids, and the reason is pinned as\n  rule 3 in `scripts/undraw.mjs` so it does not get \"optimized\" back in later;\n- writes the same `creator` and `origin` attributes the site's own downloader\n  writes (the artwork in the page bundle carries neither);\n- is removable on request.\n\nOne fact cuts the other way and belongs here too, since the illustrations section\ncites `robots.txt` against this tool: `handcrafts.undraw.co/robots.txt` is fully\npermissive — `User-agent: *` with an empty `Disallow:` — and unlike `undraw.co`\nit does not single out AI agents at all.\n\nIllustrations and handcrafts by\n[Katerina Limpitsouni](https://twitter.com/ninaLimpi).\n",
  "bytes": 16490,
  "sha": "397adceb8c5ce83e2e9db5a2e06e7b52f6fd22371cdfd488bf5d63d17165ead0",
  "repo_slug": "caesiumy/undraw-plugin",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/plg_caesiumy_undraw_plugin_839768e8/readme"
}