angularaicursortailwindcssdesign-systemcli

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.

7 min read Ply team
Design skill
0:00 / 0:32

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.

Plays once. Use the chapters or the bar to move. Replay starts it again. Arrow keys work when this frame is focused. Reduced motion holds each frame still. This is a teaching walkthrough of the published skill, not a recorded agent session.

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-mcp or npx 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.