dotharness/dotcraft/generative-ui
Claude Code and agent skill by dotharness/dotcraft
- community
Checking that the SKILL.md file is still in the repository.
Answer with a small interactive tool built from Desktop's own components: calculators, forms, quizzes, choices, comparisons, and cards the user can adjust or act on. Use only when interaction materially helps the answer; use visualize for free-form graphics, simulations, maps, or games, and plain Markdown for static facts and tables.
Install
npx vskill@latest install dotharness/dotcraft/generative-uiSKILL.md
Generative UI
- Use Generative UI only when the system context has a
# Generative UIsection. Otherwise, answer in Markdown and never emit adotcraft-uiblock. - Use it when the user benefits from acting on the answer: adjusting inputs (calculators, estimators), choosing between options, answering a quiz, filling a short form, or acting on a comparison (copy a command, open a link, ask a follow-up).
- Use the
visualizeskill instead for dynamics, simulations, maps, custom graphics, games, and anything that needs free-form HTML, SVG, or canvas. - Use plain Markdown for static facts, lists, and tables, and for every plain answer. Never add a block merely because the answer contains numbers or options.
- Use at most one surface per piece of content. Never render the same content as both a block and a visualization.
- Work silently: the final reply is your first user-facing message. Never announce this skill, widgets, components, JSX, programs, or code.
- In prose, describe only what the block helps the user see or decide. Keep it concise and never repeat what the block already shows.
- Read this file in full before authoring.
Authoring contract
Block
- Write one top-level fenced block with the info string
dotcraft-uiand three backticks. Never indent it or put it inside a list, quote, or another fence. Never put three backticks in a row inside the program. - Each block holds one JSX program that ends with
DotCraft.render(<App />). A program that never callsrenderfails. - A message may contain several blocks; each renders in place between the surrounding Markdown. Usually one block is right. Place it where it belongs in the answer.
- Close each fence as soon as the program is complete.
Program
- Built-in components are capitalized globals (
Card,Row,Slider, ...). Use noimportorexport. - Define your own components as named functions at the top level of the program, with distinct names.
- Props are JSON values (strings, finite numbers, booleans, null, arrays, plain objects) or functions. A function prop is an event handler. Elements are valid only as children, never as props.
undefinedprops are omitted. - Give every element rendered from an array a stable
key. - Network, storage, workers, and imports are unavailable. Timers (
setTimeout,setInterval) are available; start them inuseEffectand clear them in its cleanup. - Keep the program deterministic: the first render must be the same every time. Never use
Math.random(),Date.now(), ornew Date()for initial values. Put verified data from the conversation directly in the program. - Images must be base64
data:image/png,jpeg,gif, orwebpURLs.
Hooks
All hooks live on DotCraft and follow React semantics. Call them at the top of a component, in the same order on every render, never inside conditions, loops, or handlers.
| Hook | Meaning | |
|---|---|---|
useState(initial) | State and setter; the setter accepts a value or an updater function. | |
useEffect(effect, deps?) | Runs after a committed render; may return a cleanup. | |
useMemo(compute, deps?) | Cached derived value. | |
useRef(initial) | Mutable { current } that survives renders. | |
useId() | Stable unique string. | |
useTheme() | 'light' or 'dark'. | |
useBreakpoint() | 'compact' below 480px of block width, 'regular' below 900px, otherwise 'wide'. |
Never set state unconditionally during render; a state update on every render fails the block.
Saved state
- Every
useStatevalue is saved per block after the user interacts and restored when the conversation is reopened. Keep component names, tree shape, and hook order stable, and initial values deterministic, so saved values still apply. - Only JSON values are saved; others are skipped. Keep the whole state of a block under 16 KiB or none of it is saved.
useRef,useMemo, and uncontrolled fields (defaultValue,defaultChecked) are not saved. Use controlled fields (value/checkedplusonChangebacked byuseState) for anything that should survive a reload.- You never see saved state or what the user did in a block. Ask the user, or have the block send a self-contained message.
Actions
Call actions only from event handlers, at most one per user interaction, with arguments within the sizes in the table.
| Action | Effect | |
|---|---|---|
DotCraft.sendMessage(prompt) | Sends prompt as the user's next message in this thread. Up to 16 KiB. | |
DotCraft.prefillComposer(text) | Puts text in the composer without sending. Up to 64 KiB. | |
DotCraft.copy(text) | Copies text to the clipboard. Up to 64 KiB. | |
DotCraft.openUrl(url) | Opens an http or https link. |
- Make every
sendMessageprompt self-contained: include the selected values and the request, because you will not see the block's state. Write it as the user would, such asExplain why merge sort is stable. I answered quicksort. - Label the triggering
Buttonwith what happens, such asExplain,Copy command, orOpen docs.
Limits
Source 64 KB, rendered tree 256 KB of JSON, 1,500 components, depth 32, first render within 5 seconds. Aggregate or trim data that would exceed them; tables take up to 200 rows and charts up to 500 points.
Components
Use only the components and props below. Text props take at most 2,000 characters unless noted. space is a number from 0 to 64 (pixels).
Layout
Card—title?,subtitle?,padding?(none|sm|md|lg, defaultmd),gap?space (default 12). One quiet surface.Row—gap?space (default 8),align?(start|center|end|stretch|baseline, defaultcenter),justify?(start|center|end|between|around),wrap?,flex?0–12.Col—gap?(default 8),align?,justify?,flex?. Children stretch to its width, except buttons, badges, icons, and images.Box—padding?space,gap?(default 8),surface?(none|subtle|muted),radius?(none|sm|md),flex?0–12,minWidth?/maxWidth?0–1200. A column.Spacer—size?space. Withoutsize, it fills the remaining room in aRowand pushes the following items to the end.Divider—spacing?space (default 4).
Text
Title—value?or text children,level?1|2|3 (default 2).Text—value?(up to 8,000 characters) or text children,tone?,size?(sm|md|lg|xl|2xl),weight?(regular|medium|semibold),align?(start|center|end),mono?,tabular?,truncate?.Caption—value?or text children,tone?. Secondary meta text.Markdown—content(required, up to 32,000 characters). Takes no children. Conversation Markdown without Mermaid.Badge—label?(up to 80 characters) or text children,tone?(neutral|success|warning|error|info).
tone for Text, Caption, and Icon is primary|secondary|dimmed|success|warning|error|info.
Media
Icon—name(a Lucide icon name in kebab case, such ascircle-check),size?integer 10–48 (default 16),tone?,label?. Withoutlabelthe icon is decorative.Image—src(base64data:image/...URL),alt(required),width?/height?16–1200,fit?(cover|contain),radius?(none|sm|md, defaultmd).
Controls
Every field takes name?, label?, and disabled?. A field is controlled with value (or checked) plus onChange, or uncontrolled with defaultValue (or defaultChecked).
Button—label?or text children,variant?(primary|secondary|ghost|danger, defaultsecondary),size?(sm|md),icon?Lucide name,submit?,disabled?,fullWidth?,onClick(). Withsubmit, it submits the enclosingFormand still callsonClick.Input—value?/defaultValue?string or number,placeholder?,type?(text|number|email|search|url|tel),hint?,error?,required?,onChange(value),onSubmit(value)on Enter. Withtype="number",valueis a number when the text parses, otherwise the raw string (such as'').Textarea—value?/defaultValue?string,placeholder?,rows?2–16 (default 3),hint?,error?,onChange(text).Select—options,value?/defaultValue?,placeholder?,onChange(value). Withplaceholderthe initial value is''; without it, the first option.Checkbox—checked?/defaultChecked?,label?or text children,onChange(checked).RadioGroup—options,value?/defaultValue?,direction?(row|column, defaultcolumn),onChange(value). Use''for no selection.SegmentedControl—options(2–6),value?/defaultValue?,onChange(value). Defaults to the first option.Slider—minandmax(required,maxgreater thanmin),step?(positive),value?/defaultValue?,valueText?(up to 80 characters, shown at the trailing edge; defaults to the raw number),onChange(number).Form—gap?(default 12),onSubmit(values).valuesmaps each named field inside the form to its current value (string, number, or boolean). Validation is the program's job.
options is an array of 1–100 { value, label, disabled? } objects with string value and label up to 200 characters. Only Input and Textarea show hint and error; show a validation message for other fields with a Caption tone="error" below them.
Data
Table—columns(1–12{ key, label, align?, format?, currency? }),rows(up to 200 objects mapping column keys to string, number, boolean, or null),caption?,rowKey?(the column whose value identifies a row). Numbers align right; booleans render as a check or a dash.List—items(up to 200{ title, description?, icon?, trailing? }),ordered?,divided?.Chart—type(line|bar|area),data(1–500 objects of string, number, or null),xKey,series(1–5{ key, label?, color? }),height?120–480 (default 200),stacked?,format?,currency?,showLegend?(default: shown with more than one series).PieChart—data(1–12{ label, value, color? }withvalue≥ 0),height?120–480,donut?,format?,currency?,showLegend?(default shown, with values).
format is number|compact|percent|currency. percent expects fractions (0.25 shows 25%). currency is a three-letter ISO 4217 code used with format: "currency" (default USD); on Table it is set per column. Chart color is series-1–series-4 or other; series take colors in order by default.
Layout and style
- Use one
Cardper answer, titled concisely. Never nest cards. Inside the card, rely on the default gaps; changegaponly to group or separate content. - Use
Box surfacesparingly, for at most one highlighted result or a grouped region. Never add surfaces for decoration. - Put related controls in a
Col(the card already is one). Use aRowfor inline actions or side-by-side figures; give columns in a rowflex={1}to share the width, andflex={0}to keep one at its natural width. A row of buttons or badges wraps by itself; addwrapwhen other items may not fit. - Read
useBreakpoint()and stack side-by-side content when it is'compact'. - Show key figures with
Text size="xl"or"2xl",weight="semibold", andtabular, labeled with aCaption. Usetabularon every changing number. - Use tones and badge tones only for meaning (success, warning, error, info), never for decoration. Keep text in the default tone otherwise.
- Use one primary
Buttonper group. Prefersecondaryorghostfor supporting actions. - Show only the controls the task needs. Never invent filters, resets, or metrics the user did not ask for.
Accessibility
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 90 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingsrc/DotCraft.Core/Skills/BuiltIn/generative-ui/SKILL.md
Popularity
- 7-day trend score
- 0
Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/dotharness/dotcraft/generative-ui)