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.mdllm-wiki/glossary.mdllm-wiki/playbook/semantic-html.mdI 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-componentskill.- 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 aredata-{category}modifiers (data-surface,data-effect,data-behavior), checked against the component's row inmodifiers/applicability.json. Don't cross the two.- Every value via
var(--token-name). No raw hex, no pixels (except0and a hairline1px), 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:
- One paragraph identifying the chosen component (existing or new) and its layer.
- The HTML markup.
- The CSS, scoped to
@layer malevich.components.- (If runtime is needed) the
initXfunction — idempotent, setsdata-malevich-ready="true"; no custom-element class. For behavior modifiers, note that the runtimeinit()discovers them — no custom initializer.- A short list of tokens consumed.
- 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:
- What it is — "a notification banner," "a stat card," "a date picker."
- Where it lives — "top of the page," "inside a sidebar," "in a dashboard grid."
- What variants — info / warning / success, primary / secondary.
- What interactions — dismissible, expandable, sortable.
- What it must NOT do — "doesn't auto-dismiss," "doesn't take focus on mount."
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:
--stat-card-gap,--stat-card-padding(tier-3, would be added tocore/tokens/component-specific.json)--color-surface-raised,--color-ink-strong,--color-ink-subtle,--color-success,--color-danger(tier-2)--font-display-title-*,--font-body-support-*(tier-2, five properties each)--radius-block,--space-inset-block-s,--space-gap-elements-s(tier-2)
Decisions / open questions:
- I made
stat-carda new block. If you'd rather constrain it to the existingcard(which accepts the full visual modifier stack), I can rewrite — but the slot contract would be looser. - I introduced two tier-3 spacing tokens for the default density. Adding
them is a small PR to
@malevich/core; let me know if you'd prefer to reuse--space-inset-block-muntil they exist. - The compact density uses the
rhythmmodifier rather than a variant, matching the system's density model. If you'd expected a-compactvariant, that's the wrong mechanism here.
Pairs with
- Skill:
malevich-component-usage— read this if the output uses an existing component. - Skill:
malevich-new-component— read this if the output proposes a new component. - Prompt:
screen-from-brief— for larger briefs that span multiple components.