Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Add, integrate, or build Preline UI components and blocks into HTML files via the Preline MCP server. Use when the user mentions "preline", says "/preline", asks to add a UI component, or requests a Preline block (a ready-made page section) using Preline UI.
.claude/skills/htmlstreamofficial-preline-mcp/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-10 | ✗→✓ | ▲ Improved | 65% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 94% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 193% | 0% |
| case-17 | ✗→✓ | ▲ Improved | 84% | 0% |
| case-19 | ✗→✓ | ▲ Improved | 97% | 0% |
Use this skill to integrate Preline UI components and blocks into HTML files via the Preline MCP server. The server exposes 6 tools that return integration-ready HTML, CSS, and JS.
Activate when:
components_list or blocks_categories first.components_list({ section: "<inferred-slug>" }) when the component type is known - this keeps the response small. Omit section only when unsure.| User says | Use | |---|---| | "component" / "components" | Component workflow | | "block" / "blocks" (or "example" / "examples") | Block workflow | | Ambiguous | Use judgment; blocks give more complete results |
Ask the user to pick instead of guessing in either of these cases:
blocks_in_category / components_list({ section }) still leaves 2+ candidates whose titles + descriptions satisfy every criterion the request named about equally well (same layout/feature/style class), with nothing in the request to break the tie. Skip straight to step 3 below with just the tied candidates.If exactly one candidate matches everything the request names ("a basic accordion", "the SaaS hero with tabs"), skip straight to the normal workflow - don't interrogate the user for things you can already resolve, and don't ask just to be safe when one option is clearly the best fit.
All clarifying questions and lists are in English by default - switch to the user's language only once they write to you in it.
Blocks:
blocks_categories() and present the relevant mainSection / subSection / category paths with their titles and descriptions - the catalog carries a one-line description for every category, so present it directly rather than inventing your own summary.blocks_in_category to confirm the exact ID and go straight to single_block - skip step 3 entirely.blocks_in_category({ mainSection, subSection, category }), list the block titles + descriptions - or just the tied candidates, for the case above - and ask the user to pick the one closest to their needs.single_block.Components - same shape, sections instead of categories:
components_list() for the full list, or components_list({ section }) once you can infer one).single_component (lean on relative metadata - see Smart Component Selection - to land on the right default/variant).relative.category groupings where present - or just the tied candidates, for the case above) and ask which fits best.single_component.Keep each round to one focused question with a short, scannable list - that beats an open "what do you want?" and beats guessing a slug just to avoid asking.
When a request describes more than a single component - several pieces, a region, a full page, or an app shell - don't fetch ad-hoc. Plan the whole result first, then fetch and integrate one node at a time. The same steps apply to any shape: a dashboard, a settings page, a product page, a multi-step form, "a card/section/layout with X, Y and Z", etc.
isUtilityBased / theme), shared surfaces/colors, spacing/density, repeated element states - decide once, up front. Keep it identical across every later fetch and edit.blocks_categories branch (reuse a ready-made block as the skeleton when one fits); each named element → the right components_list({ section }). The map only tells you where to look - always confirm the exact slug against the tool output before inserting.See references/composite-layouts.md for the expanded method and worked illustrations.
1. components_list({ section: "<slug>" }) → get valid component IDs
2. single_component({ section, component }) → get HTML/CSS/JS
3. Read target file
4. Integrate HTML, CSS, scripts, init (see Integration Rules)
5. Repeat from step 1 only after integration is complete1. blocks_categories() → get hierarchy
2. blocks_in_category({ mainSection, subSection, category }) → get block IDs
3. single_block({ mainSection, subSection, category, block }) → get HTML/CSS/JS
4. Read target file
5. Integrate HTML, CSS, scripts, init (see Integration Rules)
6. Repeat from step 1 only after integration is completeHTML - insert where the user needs it.
CSS (<!-- CSS --> section):
<head>, immediately before </head><body> or near </body>External scripts (<!-- Scripts --> section):
<!-- Scripts --> label is a response section marker - NOT a location in the target file</body>, skipping blank lines, comments, and non-structural tags (</script>, </style>, etc.)</main>, </section>, </div>, </footer>, </article>) is the anchor<script src> tags after that anchor, ordered around the existing Preline core script - the loaded <script src> whose src contains preline (e.g. …/preline/dist/index.js; exact path varies by install):src does not contain preline (third-party libs: lodash, apexcharts, …) → before the Preline core scriptsrc does contain preline (Preline helpers, e.g. hs-*-helpers.js) → after the Preline core scriptpreline, then scripts with preline<script> always comes last, immediately before </body>Init (<!-- Init --> section):
</body>window.addEventListener('load', () => { ... }) unless the block already contains <script> tagsLarge responses (artifacts): when a response is written to a temp scratch file, read it once with the Read tool (use offset/limit for big files), copy the needed blocks into the target, then delete the scratch file. Don't pull the whole artifact into context if you only need to place it.
Adapt before you write. When the request differs from the fetched markup - regions the user didn't ask for (breadcrumbs, demo menus, placeholder logos), different blocks or labels - produce the final markup in memory first, then write it into the target in ONE edit per region. Never insert fetched markup wholesale and refactor it with a chain of follow-up edits: every such edit re-transfers large markup, bloats context, and desyncs file state.
Same token = same color. Theme tokens (bg-navbar, bg-sidebar, bg-layer, …) are consistent across a theme - to give two surfaces the same color, give them the same token class. Never resolve tokens to raw colors by reading the project's CSS.
Trust the returned markup - do not re-verify it. The classes, structure, and data-hs-* attributes the MCP returns are valid Preline by construction. This is the single biggest time-sink to avoid. Do NOT:
main.css) to "confirm" a class exists or to resolve what color a design token produces - Preline classes resolve at the consumer's build step, so absence from any one stylesheet means nothing;HTMLParser, tag-balance checkers, etc.) - SVG and void elements trip naive parsers and produce false errors;Place the markup, change text only, move on. Verify against the request (is every element the user named present?), never by auditing the generated code or the project's CSS.
components_list may return a relative object per component:
isSectionDefault: true - recommended default for the section; prefer when the request is vaguecategory - logical group (e.g. "color-variants", "states")isCategoryDefault: true - recommended default for its category; prefer when the request implies a style groupdefault (blue) · harvest (amber) · retro (fuchsia) · moon (grayscale) · ocean (cyan) · bubblegum (pink) · cashmere (mauve) · autumn (orange) · olive (green)
Pass via isUtilityBased: true, theme: "<name>" on single_component or single_block.
section / blocks branch before any discovery call.| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 27,182 | 9,422 | -65% | 1 | 1 | 0% | 5,645 | 3,242 | -43% | 0 | 0 | — |
case-02 | fail→fail | 18,218 | 8,964 | -51% | 1 | 1 | 0% | 3,668 | 3,298 | -10% | 0 | 0 | — |
case-03 | fail→fail | 40,682 | 7,684 | -81% | 1 | 1 | 0% | 8,255 | 3,200 | -61% | 0 | 0 | — |
case-04 | fail→fail | 16,198 | 4,599 | -72% | 1 | 1 | 0% | 3,228 | 2,928 | -9% | 0 | 0 | — |
case-05 | fail→fail | 13,367 | 7,938 | -41% | 1 | 1 | 0% | 2,439 | 3,246 | +33% | 0 | 0 | — |
case-06 | pass→pass | 11,680 | 7,001 | -40% | 1 | 1 | 0% | 1,779 | 3,697 | +108% | 0 | 0 | — |
case-07 | pass→pass | 10,149 | 8,934 | -12% | 1 | 1 | 0% | 1,471 | 4,443 | +202% | 0 | 0 | — |
case-08 | pass→pass | 16,026 | 3,330 | -79% | 1 | 1 | 0% | 1,722 | 3,206 | +86% | 0 | 0 | — |
case-09 | pass→pass | 14,627 | 4,816 | -67% | 1 | 1 | 0% | 2,248 | 3,494 | +55% | 0 | 0 | — |
case-10 | fail→pass | 15,624 | 5,055 | -68% | 1 | 1 | 0% | 2,146 | 3,536 | +65% | 0 | 0 | — |
case-11 | fail→fail | 11,665 | 16,158 | +39% | 1 | 1 | 0% | 2,312 | 3,651 | +58% | 0 | 0 | — |
case-12 | fail→fail | 10,362 | 7,763 | -25% | 1 | 1 | 0% | 1,403 | 3,986 | +184% | 0 | 0 | — |
case-13 | pass→fail | 30,243 | 7,418 | -75% | 1 | 1 | 0% | 6,623 | 3,075 | -54% | 0 | 0 | — |
case-14 | fail→pass | 12,823 | 4,167 | -68% | 1 | 1 | 0% | 1,716 | 3,336 | +94% | 0 | 0 | — |
case-15 | fail→pass | 7,584 | 3,551 | -53% | 1 | 1 | 0% | 1,080 | 3,169 | +193% | 0 | 0 | — |
case-16 | pass→pass | 7,323 | 4,009 | -45% | 1 | 1 | 0% | 1,394 | 3,079 | +121% | 0 | 0 | — |
case-17 | fail→pass | 12,184 | 5,831 | -52% | 1 | 1 | 0% | 1,939 | 3,571 | +84% | 0 | 0 | — |
case-18 | pass→fail | 11,393 | 7,601 | -33% | 1 | 1 | 0% | 2,271 | 3,990 | +76% | 0 | 0 | — |
case-19 | fail→pass | 12,003 | 6,369 | -47% | 1 | 1 | 0% | 1,990 | 3,925 | +97% | 0 | 0 | — |
case-20 | fail→pass | 9,889 | 4,048 | -59% | 1 | 1 | 0% | 1,335 | 3,352 | +151% | 0 | 0 | — |
case-21 | pass→pass | 8,152 | 2,858 | -65% | 1 | 1 | 0% | 1,229 | 3,077 | +150% | 0 | 0 | — |
case-22 | pass→pass | 10,041 | 6,623 | -34% | 1 | 1 | 0% | 1,601 | 3,873 | +142% | 0 | 0 | — |
case-23 | pass→pass | 8,535 | 5,946 | -30% | 1 | 1 | 0% | 1,675 | 3,716 | +122% | 0 | 0 | — |
case-24 | pass→pass | 7,396 | 6,629 | -10% | 1 | 1 | 0% | 1,221 | 3,818 | +213% | 0 | 0 | — |
case-25 | pass→pass | 6,901 | 4,550 | -34% | 1 | 1 | 0% | 1,092 | 3,185 | +192% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 25 cases were attempted, and 18 counted toward the lift figure. The other 7 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +16 percentage points is the difference between those two pass rates over the 18 comparable cases. 3 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.