Install
$ agentstack add skill-monikazapisek-design-engineering-playbook-vertical-spacing ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Vertical Spacing
Purpose
Compute vertical spacing (margin, padding, Auto Layout gap) as clean multiples of a grid base, applying the proximity rule (elements that relate should sit closer together than elements that don't), and correcting for vertical-trim state so the optical gap matches the set gap.
When To Use
- Reviewing or defining spacing for a card, section, article, or form.
- Fixing an Auto Layout frame in Figma where gap/padding look inconsistent or off-grid.
- Not for spacing within a single line of text (that's
text-typesetting) or column width (line-length-optimizer).
Inputs
grid-base: default8px(or4pxfor denser UI); confirm which the project uses rather than assuming.component-type: card / page section / article / form.hierarchy-level: compact / standard / spacious.base-line-height(LH): the resolvedline-heightof the body text in the flow — required for Workflow step 5 (paragraph/list rhythm), since those gaps are defined as a fraction of it, not as fixed pixel values.- If available: Figma Auto Layout properties (see Figma Node Integration) and the
textLeadingTrimstate of any text layers inside the frame.
Outputs
- Spacing values, all multiples of
grid-base(e.g. 8, 16, 24, 32, 48, 64, 96). - CSS (flex/grid
gap, margin) or Tailwind utility classes, matching whichever convention the project already uses. - A note on any vertical-trim-driven adjustment (see Workflow step 3).
- For paragraph/list flow:
paragraphSpacing, list-to-paragraph gap, and list-item gap, each shown as both theLH-fraction formula and the resulting pixel value (see Workflow step 5).
Workflow
- Snap every value to
grid-base. Reject or round any spacing value that isn't a clean multiple — flag existing off-grid values found in input CSS rather than silently leaving them.
- Apply the proximity rule. Spacing above a heading (separating it from the previous, unrelated block) should be noticeably larger — roughly 2–3× — than the spacing below it (to the body text it introduces). E.g.
margin-top: 48px/margin-bottom: 16pxon a heading, not symmetric values on both sides.
- Vertical-trim correction (critical when text is involved):
- If the text layers in this spacing context have vertical-trim off (default), the visually perceived gap is smaller than the set
gap/marginvalue, because the font's built-in leading eats into it — e.g. a setgap: 16pxoptically reads as ~11px. Either compensate by increasing the set value, or (preferred) recommend turning vertical-trim on for those text layers so the set value and the optical value match exactly. - If vertical-trim is on, the set spacing value is the true optical distance from baseline/cap-height to the next element — no compensation needed; this is the state to prefer for new work.
- Always state which assumption is in effect — don't emit a spacing recommendation without saying whether it assumes trim on or off, since the correct pixel value differs between the two.
- Report, don't silently rewrite a stylesheet or Figma frame unless asked to apply directly.
- Paragraph and list rhythm — all derived from
LH(body text line-height), not fixed pixel guesses:
| Relationship | Formula | Example (LH = 24px) | |---|---|---| | Between paragraphs (paragraphSpacing) | 0.50–0.75 × LH | 12–16px | | Between a list block and the surrounding paragraph (before and after) | same as paragraphSpacing — treat the whole list as one paragraph-equivalent unit | 12–16px | | Between items inside one list (List_Item_To_Item_Gap) | 0.25–0.33 × LH — deliberately tighter than paragraphSpacing, so the list reads as one cohesive block (Gestalt proximity) rather than a series of unrelated paragraphs | 6–8px | | Bullet/number to item text (horizontal indent) | fixed optical distance, not an LH fraction — one grid-base step or 1ch (the width of a "0" in the running font), whichever the project's existing spacing convention prefers | 8px |
- Don't apply
paragraphSpacingand first-line paragraph indent (1emtext-indent) together — pick one convention per project. If the input already shows one in use, match it rather than introducing the other. - Snap the computed
LH-fraction results togrid-base(step 1) where the two don't conflict; ifgrid-baseand theLH-fraction range don't intersect cleanly (e.g.LH = 22px→ 0.5–0.75× = 11–16.5px, andgrid-base = 8only offers 8 or 16), prefer the value inside theLH-fraction range over forcing a grid-base multiple — state which constraint won when they conflict, rather than silently picking one. - This step depends on
text-typesetting'sline-heightoutput — ifbase-line-heightisn't given, ask for it or compute it via that skill first rather than guessing a round number.
- Figma margin-collapse guard (a real Figma-specific gotcha, not a CSS concept): Figma's
TextNode.paragraphSpacingonly adds space below a paragraph, not above the next one — there's no browser-style margin-collapse behavior reconciling two adjacent blocks' spacing. If a heading node (H2, say) directly follows a paragraph node, the paragraph'sparagraphSpacingalone is usually too small a gap above a heading (it was sized for paragraph-to-paragraph rhythm, not paragraph-to-heading), and the heading will visually "stick" to the text above it.
- Fix: don't rely on the paragraph's trailing
paragraphSpacingfor this transition. Explicitly override the space above the heading — either via the parent Auto Layout frame'sitemSpacingfor that specific gap (if using per-item spacing /itemReverseZIndexgap overrides), or by giving the heading node its own leading space, sized to:
`` Margin_top_heading = 1.5 × LH_body ``
- This is larger than the standard heading proximity ratio in step 2 specifically to counteract the missing collapse behavior — don't also apply step 2's 2–3× ratio on top of this value; they solve the same problem, use the larger of the two, not both stacked.
Figma Node Integration
When running with Figma access, work against the selected FrameNode:
- Read:
layoutMode(must beVERTICALorHORIZONTAL— ifNONE, this isn't an Auto Layout frame and gap/padding don't apply the same way; report that first),itemSpacing(=gap),paddingTop/paddingBottom/paddingLeft/paddingRight. - Also read
textLeadingTrimon any childTextNodes — this is the input to Workflow step 3. Don't compute a spacing verdict for a frame containing text without checking it. - Paragraph/list frames: read
TextNode.paragraphSpacingandTextNode.paragraphIndentdirectly when the node is a body-copy text node with multiple paragraphs — Figma exposes these as native text-node properties, not just Auto LayoutitemSpacing, so check which one the content actually uses before recommending a fix. - Verdict: if
itemSpacing/padding aren't multiples of the confirmedgrid-base, flag each offending value with the nearest clean multiple. - Alert pattern for missing trim: "Wykryłem brak vertical trimu w warstwach tekstowych w tej ramce. Przy
gap: {itemSpacing}pxrzeczywisty odstęp optyczny to ok. {estimate}px. Rekomenduję włączenie Vertical Trim: Cap height dla precyzyjnej siatki {grid-base}px." — give this as the concrete alert text when trim is off and the frame is otherwise on-grid. - Action back to Figma: set
itemSpacing/padding, orparagraphSpacing/paragraphIndentfor text-node-native rhythm, ortextLeadingTrimon child text nodes, only on explicit request — never silently.
Quality Checklist
- [ ] Every emitted spacing value is a stated multiple of
grid-base. - [ ] Proximity rule applied asymmetrically around headings (top ≫ bottom), not symmetric padding by default.
- [ ] Vertical-trim state checked for any text-containing frame before giving a final gap value; assumption stated explicitly if unknown.
- [ ] Off-grid values found in existing input are flagged, not silently left or silently "fixed" without saying so.
- [ ] Paragraph/list rhythm values (step 5) shown as both the
LH-fraction formula and the resulting px — never a bare pixel number with no derivation. - [ ] List-item gap is visibly tighter than
paragraphSpacing(0.25–0.33×LH vs. 0.5–0.75×LH) — never emitted equal or reversed. - [ ]
paragraphSpacingand first-line indent not both recommended together; matches whichever convention the input already shows. - [ ] Figma writes (if any) only happen on explicit request.
- [ ] Cross-reference to
text-typesettingnoted when the fix is really "turn on vertical-trim" rather than a spacing-value change.
References
- Latin, M. (2017). Better Web Typography for a Better Web. — mathematical treatment of vertical rhythm and grid-base spacing.
- Butterick, M. Practical Typography. — critique of rigid baseline-grid enforcement in favor of flexible, grid-base-multiple padding/gap.
- Wertheimer, M. (1923). Gestalt principle of proximity — elements spaced closer together are perceived as grouped/related; the basis for list items sitting tighter than paragraphs.
- Bringhurst, R. (2012). The Elements of Typographic Style (4th ed.). Hartley & Marks — paragraph spacing and first-line indent as alternative (not combined) conventions, both derived from line-height rather than arbitrary pixel values.
- Figma Plugin API Docs:
FrameNode.layoutMode,FrameNode.itemSpacing,FrameNode.paddingTop/Right/Bottom/Left,TextNode.textLeadingTrim,TextNode.paragraphSpacing,TextNode.paragraphIndent. - Related skills: [
text-typesetting](../text-typesetting/README.md) (vertical-trim and line-height source of truth), [line-length-optimizer](../line-length-optimizer/README.md) (horizontal measure — different axis, same text blocks).
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: monikazapisek
- Source: monikazapisek/design-engineering-playbook
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.