aiforui logo

How to build with aiforui skills

There are a lot of skills in the aiforui skills library. It can feel overwhelming at first, so this guide will help you understand how to use them effectively.

Each skill belongs to a moment in the work, and they’re meant to be run in an order. In this lesson I’ll take one screen through that order. From the first attempt of an agent to the final polished version.

Let’s start by learning when to invoke a skill.

Invoke skills by name

A skill gets loaded in one of two ways. The agent can read your prompt, match it to a skill’s description, and load it on its own. “Add an enter animation to this dropdown” will usually pull in /emil-animations without you asking for it explicitly.

That’s actually the first tip: use keywords. When you want to animate something, use the word “animate” in your prompt. It helps the agent pick the right skill. And skills can save you a lot of time, they can pick a semi-translucent border for you or pick the right easing so you don’t have to write another prompt to fix it.

Currently, there are five skills you need to invoke manually: /emil-ask-emil, /emil-product-thinking, /emil-build-a-tool, /emil-get-creative, and /emil-borrow-a-brain. Those are quite specific either to my thinking or a specific process, so you wouldn’t want them to be invoked automatically.

A skill can’t do everything for you, so you need to steer it in the right direction. If you are not happy with how a screen looks, describe what’s wrong with it, instead of asking the agent to just make it better.

Bad

make this page better

Good

/emil-design-foundations the domains settings page feels flat, everything blends together. Fix the hierarchy and spacing.

One or two skills at a time

With an abundance of skills, you might be tempted to use them all, all the time.

Every skill is a bar the agent has to hold the work to. If you use five for one task, your output can become quite messy, since it tries to satisfy tons of different requirements. That’s why each skill covers one aspect of the interface instead of all of it.

So run one or two in sequence, and look at the screen between runs. It helps you decide whether what the agent is doing is working, and if not, you can adjust your prompt and run the skills again. You are the one behind the wheel.

The loop for your work

Here’s one of the loops you could use for your work. It’s important to know that you can adapt it to your own needs. Maybe you want to run /emil-product-thinking first, to get a better understanding of the product and the user needs. This lesson aims to inspire you and give you a good starting point for your work.

When every screen has been through the loop, /emil-prep-for-prod runs on the whole app. We’ll talk about it at the end of the lesson.

Let’s go through it with a real screen. Here’s my prompt, with no skill loaded:

Build a settings page where I can see my project’s custom domains and add a new one.

Domains ✨
Seamlessly manage your custom domains
acme.com
128,480 requests
Verified
staging-preview-7f3a2c.acme-internal-tools.dev
9,204 requests
Verified
docs.acme.com
96 requests
Pending

It technically works, you can add a domain and submit, that’s what AI is good at, making the technical requirements work. It also has a gradient icon, a sparkle, pill badges, a card inside a card, and every line of text at the same size. It also has a few UX quirks, like Enter not submitting the form.

Decide, if you haven’t

The example above obviously has many issues, but the biggest one is trying to one-shot the whole screen. A good first step is to prototype the screen, increase the number of variants to test it with your eyes.

/emil-prototype builds three to five different versions behind a switcher so you can interact with all of them and pick the best one. Reach for it when you can’t describe what you want yet. The prototyping lesson covers it in more detail.

This is optional. If you know exactly what you want, you can be more precise with the initial prompt and skip this step.

Build on the foundation first

/emil-design-foundations goes first on almost every UI feature I build. It owns hierarchy, spacing, and alignment, and everything else that is design related.

/emil-design-foundations the domains page looks generated. Fix the hierarchy and spacing, and drop anything that isn’t adding value.

acme-web/Settings/Domains

Domains

Point a domain you own at this project.
Domain
Requests
Status
acme.com
128,480
Verified
staging-preview-7f3a2c.acme-internal-tools.dev
9,204
Verified
docs.acme.com
96
Pending

Same screen, before and after /emil-design-foundations.

The card, the gradient, and the sparkle are gone. The title is now the biggest thing on the page, the status is a dot with quiet text, and there’s one primary button. The page finally looks like it belongs to a product.

Generic UI is intentional

You might still think it doesn’t look amazing, kinda generic. We’ll improve it, but being generic in product UI is partially intentional. The goal here is not to invent new patterns, we want our UI to be predictable and consistent, which means that we have to follow existing patterns and conventions. We are going for correctness over creativity here.

The form is still broken though. There’s no validation, you can type asdf and it will still be added to the list. That’s fine, because foundations doesn’t own forms.

Next comes one skill for whatever the screen is made of. I call these the material skills:

  • /emil-forms-and-inputs for anything a person types into or presses
  • /emil-surfaces for cards, modals, dropdowns, shadows, and borders
  • /emil-typography when you want to change the font, size, weight, or line height
  • /emil-component-design for the props of a component other people will reuse
  • /emil-marketing-pages for a landing page, which pulls the others in by itself

This screen is a form, so:

/emil-forms-and-inputs the add domain form accepts anything and Enter doesn’t submit. Fix the validation and the submit states.

acme-web/Settings/Domains

Domains

Point a domain you own at this project.
Domain
Requests
Status
acme.com
128,480
Verified
staging-preview-7f3a2c.acme-internal-tools.dev
9,204
Verified
docs.acme.com
96
Pending

Try asdf again, then a real domain, and press Enter this time.

The input has a label now. It’s visually hidden, because the button next to it already says what the field is for, but a screen reader still announces it. It also sits inside a <form>, so Enter submits.

asdf gets an error next to the field, with an icon, so the message doesn’t rely on red alone. The line for that error is always reserved, which means the page doesn’t jump when it shows up. While the request runs, the button is disabled and says what’s happening, so it can’t fire twice.

Refine

The screen works now. This step is about making it feel built.

/emil-ui-polish do a polish pass on the domains page.

acme-web/Settings/Domains

Domains

Point a domain you own at this project.
Domain
Requests
Status
acme.com
128,480
Verified
staging-preview-7f3a2c.acme-internal-tools.dev
9,204
Verified
docs.acme.com
96
Pending

Add a domain in both, and watch the long one in the second row.

Here’s the list of what got fixed with the polish skill:

  • The long domain truncates instead of wrapping.
  • The request counts use tabular numbers and align to the right, so the digits line up.
  • The button moved inside the field, so the two read as one control, and it keeps its width when it says “Adding…”, so the text next to it doesn’t shift.
  • And the button has a focus ring and a pressed state.

/emil-ui-polish is the main polish skill that usually fixes the cheap feeling you might be getting from the UI. The rest of this group each solve a different problem:

  • /emil-animations for bad motion
  • /emil-performance when it feels laggy or sluggish
  • /emil-mobile-native when you want to improve the mobile experience
  • /emil-touch-and-accessibility for tap targets, focus, and screen readers

You could even make an argument that you should run all of them every time, but that might be overkill some of the time.

Review

Now to review it you can use /emil-ui-review.

/emil-ui-review review the domains page before I merge it.

It starts with a verdict, which is blocked, approve with changes, or ship it. Then you get a ranked list of findings:

**Approve with changes**
 
Should fix
- `domains.tsx:64` Add a bottom fade to the list of domains so users know there's more to scroll. See /emil-surfaces.
 
Nits
- `domains.tsx:96` The new row animates `height`. Fine for one row on
  submit. Don’t reuse it on anything that fires often.

You can then simply tell it to fix the issues. Some of the reported findings have a skill name attached to them, so the agent will know which skill to run.

When you don’t know which skill

Here’s a cheatsheet for the most commonly used skills:

For everything else, there’s a router. It answers with one or two skills and the order to run them in:

/emil-ask-emil the pricing page looks fine on desktop but something’s off on my phone, which skill?

And if you feel like you are missing the right word, /emil-design-vocabulary and /emil-engineering-vocabulary turn “the space between two specific letters” into “kerning”. A vague prompt gets you a vague interface, so being more precise helps you get better results.

Before you ship

Everything so far was built on a fast laptop, in light mode, with a seeded account and a mouse. That’s the ideal scenario, but there are lots of variables that can break your UI.

/emil-prep-for-prod checks for those variables. Here’s the polished Domains page in four situations we never checked while we were building it. You can use the switch at the bottom to see the before and after for each.

acme-web/Settings/Domains

Domains

Point a domain you own at this project.
Domain
Requests
Status
acme.com
128,480
Verified
staging-preview-7f3a2c.acme-internal-tools.dev
9,204
Verified
docs.acme.com
96
Pending
Blocker
The light theme’s colors were typed in by hand. Nobody opened dark mode after the redesign.

Three of the four got fixed, but the empty state didn’t, that’s on purpose. The skill never adds a value, and the copy in your empty state is a value. So it flags the blank page as a blocker, says what’s missing, and leaves the writing to you.

That’s the difference from /emil-ui-review. Review judges one diff and tells you what’s wrong. Prep for prod checks the whole app or your branch and fixes it in one go.

It’s also the one exception to “one or two skills at a time”. It crosses every other skill on purpose, and it runs all of them even if you only asked about speed:

What comes back

Here’s an example of what comes back from /emil-prep-for-prod:

**Not yet.** One blocker is open: a new account opens to a blank
Domains page.
 
A. Accessibility
  BLOCKER · Fixed
  `outline: none` on every button at `globals.css:41`
  → `:focus-visible` outline with a 2px offset
  Keyboard users can’t see where they are.
 
E. Stability and states
  BLOCKER · Open (needs copy)
  `domains.length === 0` renders `null` at `domains.tsx:88`
  Every new account opens to a blank page.
 
  BLOCKER · Fixed
  Nothing renders while loading at `domains.tsx:80`
  → skeleton rows at the loaded height
  1.5s of blank, then the form jumps.
 
G. Theming
  BLOCKER · Fixed
  14 hardcoded hex colors in `domains.tsx`
  → theme tokens
  The title and the button are unreadable in dark mode.
 
B, C, D, F, H: clean. I: skipped, no marketing routes.
 
Needs a device
- Open Domains on an iPhone, tap the input, and confirm the page
  doesn’t zoom.
- Tab through the page with VoiceOver on and confirm the error is
  read out when it appears.
 
Needs a human
- The empty state needs a headline and one line of copy.
  Owning skill: /emil-design-foundations.
 
Verification
- `pnpm tsc --noEmit` passed
- `pnpm build` passed

The “Needs a device” list is the most useful part of the report as it tells you to review those parts yourself, on an actual device. Probably soon the agents will be able to do this for you, but this is a manual step for now unfortunately.

Summary

  • Invoke skills by name when the result matters, and be precise about what’s wrong with the thing you’re pointing at.
  • One or two skills per run. Look at the screen in between.
  • Follow the order. Decide, build on /emil-design-foundations plus one material skill, refine, then review.
  • When you don’t know which skill, say what you are looking for, or ask /emil-ask-emil.
  • Before shipping, run /emil-prep-for-prod.

If you’re building something right now, start with the audit. It changes nothing and takes a few minutes, and you’ll learn a lot about your app.

/emil-prep-for-prod audit

If you installed the skills using the general install command, you already have it. Otherwise:

npx @aiforui/install emil-prep-for-prod --token=…