Why Ply installs a UI design skill when you run init
Ply at ply-ui.com writes a UI design skill on npx ply-ui-cli init so agents reuse ply-card and ply-button, with loading, empty, and error states.
Chapter 1 of 6
Init
$ npx ply-ui-cli init --yes
Writing editor rules, snippets, and the UI design skill...
- .cursor/rules/ply-ui.mdc
- .vscode/ply-ui.code-snippets
- .cursor/skills/ply-ui-design/SKILL.md
- .cursor/skills/ply-ui-design/reference.md
- .cursor/skills/ply-ui-design/examples.md
Specimen
Written when missing
.cursor/skills/ply-ui-design/
SKILL.md, reference.md, and examples.md. Existing files are left as they are.
npx ply-ui-cli init writes the skill folder when it is missing. In Cursor, run /ply-ui-design or attach @ply-ui-design.
Ply — ply-ui.com — writes a UI design skill the first time you run npx ply-ui-cli init, if .cursor/skills/ply-ui-design/ is not already there. The skill tells the agent to reuse ply-card, ply-button, and ply-input-group, keep one accent, and ship loading, error, empty, and data states. The player above walks that correction, chapter by chapter.
The published copy is SKILL.md, plus reference.md and examples.md. Together they are 882 lines. The player covers the four decisions that change the card, not every line.
What the player is
It is a teaching walkthrough, the same kind of reconstruction as the token session. It is not a screen recording of Cursor, and it is not a benchmark. Chapters are clickable. It plays once, then waits. Replay starts it again.
| Chapter | What you should see |
|---|---|
| Init | The three skill files, plus the Cursor rule and the snippet pack, land only when those paths are missing |
| Prompt | A billing card: plan name, Save, and the operational states |
| Without | A gradient header, a card shadow, a pill button, and no states |
| Tokens | One accent, no card shadow, --ply-radius, slate neutrals |
| Primitives | ply-card, ply-input-group, two buttons of one size |
| States | Loading, error, empty, then data — one branch, same card |
What init actually writes
npx ply-ui-cli init is project setup, not add. It writes ply-ui.json, ply-ui.css, the icon sprites, and — when the destination is missing — three editor files:
| Path | Role |
|---|---|
.cursor/rules/ply-ui.mdc |
Always-on rule: install with the CLI, do not invent a control that is already in the catalog |
.vscode/ply-ui.code-snippets |
Snippets for ply-card, dialog, and the other usual pieces |
.cursor/skills/ply-ui-design/ |
SKILL.md, reference.md, examples.md |
The skill write is skip-if-present. A folder you already edited stays yours. The command does not install a component. Components still arrive with npx ply-ui-cli add <name>.
Cursor’s own description of a skill is the reason this is a folder and not another paragraph in the rule: “Skills are reusable sets of instructions that teach Agent how to handle specific tasks. They're more detailed than rules and designed for multi-step workflows.” (Cursor Help). The rule says install, don’t invent. The skill says how the installed pieces should look, and which states the screen owes the user.
The always-on file is the rule. The skill is invoked. In Cursor, type /ply-ui-design or attach @ply-ui-design. The description in the front matter is what the agent uses to decide the skill is relevant; this one does not set disable-model-invocation, so a UI task can pull it in without the slash command. Do not expect it in every chat the way alwaysApply: true works on the rule.
If this project was initialized before the skill shipped, copy the three files from the links above into .cursor/skills/ply-ui-design/. Running init again also rewrites ply-ui.json and ply-ui.css, so copying is the safer way to add the skill to a project that already has those files.
Why the model needs the file
The 2025 Stack Overflow Developer Survey found that 84% of respondents are using or planning to use AI tools in their development process. The same release is blunt about quality: “46% of developers said they don't trust the accuracy of the output from AI tools” (Stack Overflow). A markdown skill does not move that percentage. It gives the editor a project-owned answer for the part agents get wrong on UI: which component, which token, which state.
Ply is copy-in Angular styled with Tailwind CSS. The agent can read the template after add. It still has to choose ply-card over a new div, and it still has to remember that a card in this system has no shadow. That choice is what SKILL.md is for. The longer argument for copy-in source, llms.txt, and MCP is Why LLMs write better code when the library is not in node_modules.
The four corrections
Tokens. Page, surface, and raised fills are tonal (bg-slate-50, bg-white, bg-slate-100, with dark pairs). The hairline is border-slate-200. The accent is --ply-primary. Neutrals stay slate — not gray, zinc, or indigo. rounded-full is for chips, avatars, and status dots. Buttons use rounded-[var(--ply-radius)].
Primitives. The reuse map in the skill is short on purpose. A modal is DialogService. A field is ply-input-group with ply-label, ply-input, and ply-error. A toast is ToastService, not a ply-toast-container you place yourself. Extend a primitive through its class input. Do not restyle it from the inside.
One button size per row. Cancel and Save in the player are both the default size. A large primary next to a tiny text button is the pattern the skill forbids.
States, in order. Render exactly one branch: loading, then error, then empty, then data. Keep them in the same card so the page does not jump. Loading is ply-skeleton sized like the final field. The field error is ply-error inside ply-input-group; after the control is touched and invalid, the group shows the message, sets aria-invalid, and paints border-red-500. Do not wrap ply-error in @if. Empty copy names the missing thing in a few words and ends on a verb. examples.md has a full four-state region if you want the template rather than the billing card.
<ply-card>
<ply-card-header>Billing</ply-card-header>
<ply-card-body>
<ply-input-group>
<ply-label>Plan name</ply-label>
<input ply-input />
<ply-error>Enter a plan name.</ply-error>
</ply-input-group>
</ply-card-body>
<ply-card-footer>
<button ply-stroked-button type="button">Cancel</button>
<button ply-button color="primary" type="button">Save</button>
</ply-card-footer>
</ply-card>
The error line stays in the template. The group decides when it is visible.
What the skill does not do
- It does not install components, and it does not replace
npx -y ply-ui-mcpornpx ply-ui-cli add. - It does not apply itself inside ChatGPT or Gemini. Those hosts use the catalog at
https://mcp.ply-ui.com/mcp. The skill is a Cursor folder (.cursor/skills/). Copy the markdown if another editor reads a skills directory. - It does not overwrite a skill you already have.
- It is not a measured accuracy lift. We have not run an eval that scores agents with and without the file.
npx ply-ui-cli doctor checks ply-ui.json, Tailwind’s @source paths, ply-ui.css, and the icon sprites. It does not grade whether the agent followed the skill. That part you can see: open the card it wrote and look for one accent, no card shadow, matched button sizes, and a state for loading, error, and empty.
Frequently asked questions
Same wording as the canonical FAQ.
npx ply-ui-cli init writes ply-ui.json, ply-ui.css, icon sprites, .cursor/rules/ply-ui.mdc, .vscode/ply-ui.code-snippets, and the UI design skill at .cursor/skills/ply-ui-design/ (SKILL.md, reference.md, examples.md) when those files are missing. The skill tells the agent to reuse ply-button, ply-card, and ply-input-group, keep one accent, and include loading, error, empty, and data states. It does not install components. Published copy: https://ply-ui.com/docs/ai/skills/ply-ui-design/SKILL.md. Walkthrough: https://ply-ui.com/learn/ply-ui-design-skill/.
npx ply-ui-cli init once per project, then npx ply-ui-cli add <name>. Omit the name in a terminal to pick from the catalog (filter, then type to select). --yes and CI need explicit names. Components land in src/app/components/<name>/ by default and are yours.
Yes. npx -y ply-ui-mcp runs over stdio in Cursor, VS Code, Claude Code, Claude Desktop, Codex, Antigravity, Grok Build, Kimi Code, Qwen Code, Windsurf, and other local hosts. ChatGPT and Gemini chat apps use the Streamable HTTP connector at https://mcp.ply-ui.com/mcp (catalog tools) or a local npx -y ply-ui-mcp --http without --read-only so add/init/update can see the project. Pro add uses PLY_LICENSE_KEY on the MCP process. Setup for each host: https://ply-ui.com/getting-started/#ai-agents-mcp. Editors that skip MCP can copy the Cursor rule and snippet pack from https://ply-ui.com/getting-started/#editor-rules.
Install Tailwind CSS 4 and @angular/cdk, run npx ply-ui-cli init, then npx ply-ui-cli add card (or add with no name to pick from the catalog). The steps, MCP setup for AI tools, and a StackBlitz starter are at /getting-started/. Brand color, translated strings, and right-to-left layouts are at /configuration/.
Start with the free tier
All primitives, all 19 form blocks, and 390 icons — no account, no licence key.