Loading...
Loading...
Design production-grade screens in Penpot from a brief, as a senior visual designer — reusing the existing design system (tokens + components) and assembling section by section, never one-shot. Use to create a screen/page/landing/dashboard from a description. NOT for translating existing code (use penpot-build-from-code). Triggers: 'design a dashboard', 'create a landing page', 'design this app screen', 'build a UI from this brief', 'design a settings page', 'mock up a screen in Penpot'.
npx skill4agent add penpot/penpot-ai-kit penpot-build-screenpenpot-build-screenexecute_codeexport_shapepenpotUtils.shapeStructureshared/penpot-mcp-tool-reference.mdpenpot-foundationsexport_shapepenpot-foundationsshared/penpot-mcp-tool-reference.mdpenpot.createBoard()addFlexLayout()penpot.library.local.componentscomp.instance()shape.applyTokenexport_shape('selection'|'page')shared/plugin-api-gotchas.mdcomponent.instance()growTypeauto-widthauto-heightresize()fixedlayoutChildcreateBoard()fills = [{ fillColor: "#FFFFFF", fillOpacity: 1 }]board.fills = []color.bg.*shared/modes-and-policies.mdpenpot.fonts.all.find(f => f.name === "…")findByNamelayoutChild.*appendChildopenPagecurrentPage.idcreateBoardclearFlipflipX = trueshared/visual-effects.mdawait board.waitForLayoutUpdate()const img = await penpot.uploadMediaUrl(name, url); shape.fills = [{ fillOpacity: 1, fillImage: img }]shared/visual-effects.mdpenpot_api_infoshared/design-quality.mdshared/anti-slop.mdshared/design-quality.mdpenpot-anti-slopVisual self-review (mandatory): before every ✋ checkpoint that shows visual work, run the export → look → fix loop from— export the unit you just built, inspect the image yourself against the checklist, fix visible defects (max 2 iterations), and present that same export with any remaining defects named.shared/visual-self-review.md
high_level_overviewscripts/setupOrReuseSystem.jsreferences/01-brief-analysis.mdreferences/02-style-profiles.mdshared/design-quality.mdpenpot-anti-slopscripts/antiSlopPrefs.jsshared/anti-slop.mdonpenpot-anti-slopreferences/02-direction-playbook.mdscripts/createScreenFrame.jsscripts/buildSection.jsexecute_codeexport_shapescripts/assembleScreen.jsscripts/auditScreenQuality.jsboardsWithoutLayoutreferences/05-critique-framework.mdshared/design-quality.mdshared/report-schemas/design-quality-report.schema.jsonpenpot-anti-slopdistinctivenessaddFlexLayout()addGridLayout()xyboardsWithoutLayoutexport_shapepenpot-foundationsshared/modes-and-policies.mdRUN_IDphasescreenBoardIdsections:[{name,id,done}]styleProfileskeletondesignQualityantiSlopprefdirectionreports[]penpot-aiprefs.antiSlop| After phase | Artifacts | Ask |
|---|---|---|
| 0 (pref unset) | the anti-slop opt-in question ( | Avoid the generic-AI look? |
| 0 | brief + style + skeleton + sections (+ direction block if strict) | Approve direction? |
| 1 | empty frame | Approve frame/viewport? |
| each section | section | Approve section? |
| assemble | full screen | Approve / iterate? |
shared/naming-conventions.mdheadermainsectionnavbuttonDashboard| Excuse | Why it's wrong | Countermeasure (halt) |
|---|---|---|
| "I'll draw a quick button instead of using the component." | Raw shapes drift from the system. | Instantiate the existing component; reuse beats reinvention. |
| "Hardcode this spacing/color, faster." | Breaks rhythm/theming/governance. | Bind to semantic tokens; snap spacing to 4px. |
| "Generate the whole screen in one go." | One-shot output is generic and unauditable. | Build section by section with checkpoints. |
| "Centered cards + generic gradient looks fine." | Distributive convergence → bland, off-brand UI. | Apply a deliberate style profile; justify aesthetic choices. |
| "I'll skip the anti-slop question, the user is busy." | Strict mode is the user's choice; guessing either way is wrong. | Read |
| "I'll set up tokens here real quick." | Foundations belong in their skill. | Hand off to |
| "I'll just position these with x/y, it's faster." | Absolute coords don't resize, reflow, or theme; off-system. | Wrap them in a flex/grid Board; order by append + gaps/align. |
| "A plain Group is enough to bunch these together." | Groups don't lay out — they only bound. | Use a Board with |
| "This little container doesn't need a layout." | Every UI container needs one for rhythm + responsiveness. | Add flex/grid before appending children — no exceptions. |
// Screen frame (Phase 1)
const screen = penpot.createBoard();
screen.name = "Dashboard";
screen.resize(1440, 1024);
const flex = screen.addFlexLayout();
flex.dir = "column";
flex.horizontalSizing = "fix"; flex.verticalSizing = "auto";
penpot.currentPage.root.appendChild(screen); // append first (#7); layoutChild only after append (#15)
// SPACING: bind tokens, never literals (#8: padding tokens bind on ≥ 2.17; numeric mirror + ledger exception otherwise)
const gap = penpotUtils.findTokenByName("spacing.24");
if (gap) screen.applyToken(gap, ["rowGap"]); else flex.rowGap = 24;
const pad = penpotUtils.findTokenByName("spacing.32");
const FLEX_PROP = { paddingTop: "topPadding", paddingBottom: "bottomPadding", paddingLeft: "leftPadding", paddingRight: "rightPadding" };
for (const side of Object.keys(FLEX_PROP)) {
try { if (!pad) throw new Error("no token"); screen.applyToken(pad, [side]); }
catch (e) { flex[FLEX_PROP[side]] = pad ? Number(pad.resolvedValue) : 32; } // record { kind: "padding-mirrors-token" } in the ledger
}
// FILL POLICY (gotchas #11): the screen root is THE one surface — bind its bg to a token so it flips in
// dark mode. Every section nested inside stays transparent (buildSection.js clears their default white).
screen.fills = []; // drop Penpot's default opaque #FFFFFF
const bg = penpotUtils.findTokenByName("color.bg.default");
if (bg) screen.applyToken(bg, ["fill"]); // bound surface, not a literal
storage.bs = { screenBoardId: screen.id };
return { screen: screen.id, bgBound: !!bg, gapBound: !!gap, padBound: !!pad };penpot_api_info('Board')penpot_api_info('LibraryComponent')penpot_api_info('Text')01-brief-analysis.md02-style-profiles.md03-layout-composition.md04-component-recipes.md05-critique-framework.md06-anti-rationalization.md07-error-recovery.mdshared/visual-effects.mdsetupOrReuseSystem.jscreateScreenFrame.jsbuildSection.jsassembleScreen.jsauditScreenQuality.jsshared/…policies/…${CLAUDE_PLUGIN_ROOT}/shared/…