Malevich

AI-Things / Prompts / Prompt/

Component from brief

Generate a Malevich component (HTML + CSS, optionally with an init function) from a short natural-language brief.

generation · brief → component · updated 2026-05-21

Use case: When you have a one-paragraph description of a UI piece and want a Malevich-conformant implementation to start from.

When to use

You have a short brief like:

"I need a notification banner that sticks to the top of the screen, dismissible, with an icon, a title, and a body. Three variants: info, warning, success."

…and you want a Malevich-conformant starting point you can paste, review, and refine. Use this prompt when the brief is specific enough to act on but not large enough to need its own design review — typically a single component, screen region, or small block.

If the brief is bigger (a full screen, a multi-step flow), use the screen-from-brief prompt instead.

The prompt

Fill in the placeholders and send the text below.

You are working in the Malevich design system. Read these files before answering:

  • llm-wiki/architecture.md
  • llm-wiki/glossary.md
  • llm-wiki/playbook/semantic-html.md

I need a Malevich-conformant implementation of the following:

Brief: {{brief}}

Constraints:

  • Pick the correct component layer (primitive / element / block / section / overlay) from the brief, using the ADR-0006 functional test.
  • If the brief maps to an existing Malevich component, use it directly. Don't invent new components when existing ones suffice.
  • If a genuinely new component is needed, follow the malevich-new-component skill.
  • Standard HTML elements with BEM classes. No custom elements, no <m-*> tags, no Shadow DOM (ADR-0004). A component is a semantic element plus a block class.
  • Identity is a BEM short modifier (.block.-variant); presentation and behavior are data-{category} modifiers (data-surface, data-effect, data-behavior), checked against the component's row in modifiers/applicability.json. Don't cross the two.
  • Every value via var(--token-name). No raw hex, no pixels (except 0 and a hairline 1px), no tier-1 --palette-* / --scale-* references. Font tokens expand into five --font-<role>-* properties — set them individually.
  • Accessibility: real semantic HTML; ARIA only where no native equivalent exists.

Target framework: {{framework}}

Output format:

  1. One paragraph identifying the chosen component (existing or new) and its layer.
  2. The HTML markup.
  3. The CSS, scoped to @layer malevich.components.
  4. (If runtime is needed) the initX function — idempotent, sets data-malevich-ready="true"; no custom-element class. For behavior modifiers, note that the runtime init() discovers them — no custom initializer.
  5. A short list of tokens consumed.
  6. A short list of decisions you made and any open questions for me.

If you genuinely cannot decide between two interpretations of the brief, ask before writing code.

Variables

Placeholder What to fill in
{{brief}} The natural-language description of the component. One paragraph is ideal.
{{framework}} vanilla HTML/CSS, React, Vue, Astro, etc. Vanilla is the default — use it unless the project requires a framework.

Tips for writing the brief

The output quality tracks the brief quality. A good brief includes:

You don't need to specify colors, sizes, or spacing — those are inferred from the design system.

Example input

A stat card for a dashboard grid. Shows a large number, a label below, a small trend indicator (up/down with percentage), and an optional icon in the corner. Three variants: positive, negative, neutral. Default density; also a compact density for tighter dashboards.

Example output

Component identified. This maps to a new block called stat-card. Not an element (it has internal structure / slots), not a section (not full-width), not an overlay (in-flow). The closest existing component is card, but a stat card has a fixed structural contract that warrants its own block.

HTML:

<article class="stat-card -positive" data-rhythm="regular">
  <header class="stat-card__header">
    <i class="stat-card__icon icon" data-icon="users" aria-hidden="true"></i>
  </header>
  <div class="stat-card__value">2,481</div>
  <div class="stat-card__label">Active users</div>
  <div class="stat-card__trend">
    <i class="stat-card__trend-arrow icon" data-icon="arrow-up" aria-hidden="true"></i>
    <span class="stat-card__trend-value">12.4%</span>
  </div>
</article>

Status variants apply as .stat-card.-positive, .stat-card.-negative, .stat-card.-neutral. Density is the rhythm modifier (data-rhythm="compact"), not a -compact variant. The trend color follows the status variant on the root, so the trend block needs no separate modifier.

CSS:

@layer malevich.components {
  .stat-card {
    display: grid;
    grid-template-areas:
      "header header"
      "value value"
      "label trend";
    gap: var(--stat-card-gap);
    padding: var(--stat-card-padding);
    background: var(--color-surface-raised);
    border-radius: var(--radius-block);
  }

  .stat-card__header { grid-area: header; }

  .stat-card__value {
    grid-area: value;
    font-family: var(--font-display-title-family);
    font-size: var(--font-display-title-size);
    font-weight: var(--font-display-title-weight);
    line-height: var(--font-display-title-line-height);
    letter-spacing: var(--font-display-title-letter-spacing);
    color: var(--color-ink-strong);
  }

  .stat-card__label {
    grid-area: label;
    font-family: var(--font-body-support-family);
    font-size: var(--font-body-support-size);
    color: var(--color-ink-subtle);
  }

  .stat-card__trend {
    grid-area: trend;
    font-family: var(--font-body-support-family);
    font-size: var(--font-body-support-size);
  }

  .stat-card.-positive .stat-card__trend { color: var(--color-success); }
  .stat-card.-negative .stat-card__trend { color: var(--color-danger); }
  .stat-card.-neutral  .stat-card__trend { color: var(--color-ink-subtle); }

  .stat-card[data-rhythm="compact"] {
    padding: var(--space-inset-block-s);
    gap: var(--space-gap-elements-s);
  }
}

Tokens consumed:

Decisions / open questions:

Pairs with