Files
pbakaus_impeccable/skill/reference/layout.md
T
3e38e595c7 Add platform axis (web / ios / android / adaptive) (#269)
* Add a platform axis (web / ios / android / adaptive) to the skill

Orthogonal to register: register decides whether design IS or SERVES the
product; platform decides the delivery target and which native conventions
apply. Set `## Platform` in PRODUCT.md; a missing field defaults to `web`,
so legacy projects are unaffected.

- extractPlatform() in skill/scripts/context.mjs (mirrors extractRegister);
  the CLI appends a NEXT STEP directive to read the native reference(s).
  `adaptive` (Flutter / RN / KMP shipping both iOS and Android) loads both
  ios.md and android.md.
- New reference/ios.md (Apple HIG distilled) and reference/android.md
  (Material 3 distilled); reference/web.md is a thin pointer. The native
  refs frame register's role as narrow: platform conformance is the bar,
  brand lives in the expressive layer the platform gives you, never by
  breaking the rails.
- Setup step 5 loads the native reference(s) when platform is native. Live
  mode and the detect CLI stay web-only, gated off ios/android/adaptive.
- init asks platform right after register; adapt/audit/animate/layout carry
  short platform divergence notes; all secondary spots thread `adaptive`.
- a11y stays in audit.md (loading it at design time makes output timid), so
  the native refs carry no Accessibility section; audit.md's Platform
  section owns native a11y.
- Tests: extractPlatform unit coverage + skill-behavior scenario 10
  (PRODUCT.md platform ios -> agent loads ios.md).

Source-first: only skill/, scripts/, tests/, CLAUDE.md, NOTICE.md, the
changelog and version are committed; the sync workflow regenerates the
provider trees and ./plugin on merge.

ios.md / android.md are distilled from the MIT-licensed
ehmo/platform-design-skills; attribution in NOTICE.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Address review: gate web tools on native platforms, drop version churn

Maintainer-review fixes applied with AI assistance (Claude Code), on top
of the rebased platform-axis commit:

- Design hook (post-edit and Cursor pre-edit) now resolves the project
  platform via loadContext + extractPlatform and skips its web rule scan
  for ios / android / adaptive projects, so React Native / Flutter code
  never draws web-shaped findings (new hook-lib resolveProjectPlatform /
  isNativePlatform helpers, covered by unit and subprocess tests).
- context.mjs CLI warns on an unrecognized ## Platform value (e.g. a
  toolchain name like `flutter`) instead of silently defaulting to web;
  extractRegister / extractPlatform now share extractSectionValue.
- Removed reference/web.md: nothing loaded it; CLAUDE.md carries the
  "web has no extra rulebook" explanation.
- init.md: skip live-mode config (Step 6) for native platforms; note the
  per-app PRODUCT.md pattern for repos shipping web + native.
- android.md: Material-everywhere apps that also ship on iPhone still
  owe iOS OS guarantees (safe areas, Reduce Motion, edge-swipe back).
- ios.md: reworded a design-time line that framed Dynamic Type as an
  accessibility check (a11y stays owned by audit.md).
- Renumbered the new skill-behavior scenario to 14 after main's 10-13;
  updated CLAUDE.md scenario list; added android + unrecognized-value
  CLI test cases.
- No version or changelog changes: versioning happens at release time.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Tighten platform reference prose

Editorial pass on the platform-axis text, applied with AI assistance
(Claude Code) under maintainer direction:

- ios.md / android.md rewritten to house style: single-line paragraphs
  (no hard wraps), one-sentence scope intro, deduplicated intro/slop-test,
  register-compression down to two sentences. In-file attribution
  paragraphs removed (NOTICE.md owns attribution); "read on top of the
  register reference" cruft removed (SKILL step 5 and the context.mjs
  directive already say it). Bans sections dropped: they restated the
  rules above them; the two additive items (tab-bar overload,
  hover-dependent affordances) folded into rules. ~40% smaller each.
- Sub-command Platform sections (adapt, audit, animate, layout), SKILL
  step 5, init.md platform prose, and the context.mjs directive trimmed
  the same way.

Build (prose validators, counts) and both test runners green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Treat an empty PRODUCT.md section as absent, not the next heading

Copilot review catch: extractSectionValue read the next `## ...` heading
as the section value when a field was left empty, which made the CLI
warn "value `## Product Purpose` is not recognized". Stop at the next
heading and return null instead. Regression tests for extractPlatform,
extractRegister, and the CLI warning path. Applied with AI assistance
(Claude Code) under maintainer direction.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Only read a token list of both native targets as adaptive

Bugbot catch: after the exact platform tokens failed, any Platform line
containing the words ios and android was classified adaptive, so
negated or explanatory prose ("web only, not ios or android") silently
loaded both native refs and skipped the hook, with no warning. The
combo parse now accepts only list separators and the two platform
words; anything else falls through to the CLI's unrecognized-value
WARNING. Regression tests added. Applied with AI assistance (Claude
Code) under maintainer direction.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Paul Bakaus <paul.bakaus@gmail.com>
2026-07-08 17:11:31 -07:00

8.8 KiB
Raw Blame History

Space is the most underused design tool. Find the layout's actual problem (monotone spacing, weak hierarchy, identical card grids) and fix the structure, not the surface.


Register

Brand: asymmetric compositions, fluid spacing with clamp(), intentional grid-breaking for emphasis. Rhythm through contrast: tight groupings paired with generous separations.

Product: predictable grids, consistent densities, familiar navigation patterns. Responsive behavior is structural (collapse sidebar, responsive table), not fluid typography. Consistency IS an affordance.

Platform

Native (ios / android / adaptive): structure follows platform navigation (iOS tab bar / navigation stack; Android navigation bar / rail / drawer), safe-area / window insets, and spec touch targets (44 pt iOS, 48 dp Android). See ios.md and android.md; adaptive lays out per OS.


Assess Current Layout

Analyze what's weak about the current spatial design:

  1. Spacing:

    • Is spacing consistent or arbitrary? (Random padding/margin values)
    • Is all spacing the same? (Equal padding everywhere = no rhythm)
    • Are related elements grouped tightly, with generous space between groups?
  2. Visual hierarchy:

    • Apply the squint test: blur your (metaphorical) eyes. Can you still identify the most important element, second most important, and clear groupings?
    • Is hierarchy achieved effectively? (Space and weight alone can be enough; is the current approach working?)
    • Does whitespace guide the eye to what matters?
  3. Grid & structure:

    • Is there a clear underlying structure, or does the layout feel random?
    • Are identical card grids used everywhere? (Icon + heading + text, repeated endlessly)
  4. Rhythm & variety:

    • Does the layout have visual rhythm? (Alternating tight/generous spacing)
    • Is every section structured the same way? (Monotonous repetition)
    • Are there intentional moments of surprise or emphasis?
  5. Density:

    • Is the layout too cramped? (Not enough breathing room)
    • Is the layout too sparse? (Excessive whitespace without purpose)
    • Does density match the content type? (Data-dense UIs need tighter spacing; marketing pages need more air)

CRITICAL: Layout problems are often the root cause of interfaces feeling "off" even when colors and fonts are fine. Space is a design material; use it with intention.

Plan Layout Improvements

Create a systematic plan:

  • Spacing system: Use a consistent scale (a framework's built-in scale like Tailwind's, rem-based tokens, or a custom system). The specific values matter less than consistency.
  • Hierarchy strategy: How will space communicate importance?
  • Layout approach: What structure fits the content? Flex for 1D, Grid for 2D, named areas for complex page layouts.
  • Rhythm: Where should spacing be tight vs generous?

Improve Layout Systematically

Establish a Spacing System

  • Use a consistent spacing scale (framework scales like Tailwind, rem-based tokens, or a custom scale all work). What matters is that values come from a defined set, not arbitrary numbers.
  • Prefer a 4pt base scale (4, 8, 12, 16, 24, 32, 48, 64, 96px) over 8pt; 8pt is too coarse and you'll frequently need 12px between 8 and 16.
  • Name tokens semantically if using custom properties: --space-xs through --space-xl, not --spacing-8
  • Use gap for sibling spacing instead of margins; eliminates margin collapse hacks
  • Apply clamp() for fluid spacing that breathes on larger screens

Create Visual Rhythm

  • Tight grouping for related elements (8-12px between siblings)
  • Generous separation between distinct sections (48-96px)
  • Varied spacing within sections (not every row needs the same gap)
  • Asymmetric compositions: a deliberate choice when the content invites it (not a default to chase).

Choose the Right Layout Tool

  • Use Flexbox for 1D layouts: Rows of items, nav bars, button groups, card contents, most component internals.
  • Use Grid for 2D layouts: Page-level structure, dashboards, data-dense interfaces, anything where rows AND columns need coordinated control.
  • Use named grid areas (grid-template-areas) for complex page layouts; redefine at breakpoints.
  • Use container queries for components, viewport queries for page layouts. A card in a narrow sidebar can stay compact while the same card in a main content area expands automatically:
.card-container { container-type: inline-size; }
.card { display: grid; gap: var(--space-md); }
@container (min-width: 400px) {
  .card { grid-template-columns: 120px 1fr; }
}

Break Card Grid Monotony

  • Don't default to card grids for everything; spacing and alignment create visual grouping naturally
  • Use cards only when content is truly distinct and actionable. Never nest cards inside cards
  • Vary card sizes, span columns, or mix cards with non-card content to break repetition

Strengthen Visual Hierarchy

  • Use the fewest dimensions needed for clear hierarchy. Space alone can be enough; generous whitespace around an element draws the eye. Some of the most polished designs achieve rhythm with just space and weight. Add color or size contrast only when simpler means aren't sufficient.
  • The best hierarchy combines 23 dimensions at once. A heading that's larger, bolder, AND has more space above it reads as primary without trying:
Tool Strong Hierarchy Weak Hierarchy
Size 3:1 ratio or more <2:1 ratio
Weight Bold vs Regular Medium vs Regular
Color High contrast Similar tones
Position Top/left (primary) Bottom/right
Space Surrounded by white space Crowded
  • Be aware of reading flow: in LTR languages, the eye naturally scans top-left to bottom-right, but primary action placement depends on context (e.g., bottom-right in dialogs, top in navigation).
  • Create clear content groupings through proximity and separation.

Manage Depth & Elevation

  • Build a consistent shadow scale (sm → md → lg → xl); shadows should be subtle
  • Use elevation to reinforce hierarchy, not as decoration

Optical Adjustments

  • If an icon looks visually off-center despite being geometrically centered, nudge it. But only if you're confident it actually looks wrong. Don't adjust speculatively.
  • Text at margin-left: 0 looks slightly indented because of letterform whitespace; a negative margin (-0.05em) optically aligns it. Geometrically centered glyphs often look off-center (play icons need to shift right, arrows shift toward their direction).
  • Touch targets must be 44×44px minimum even when the visual element is smaller. Expand the hit area with padding or a pseudo-element:
.icon-button { width: 24px; height: 24px; position: relative; }
.icon-button::before {
  content: ''; position: absolute; inset: -10px;
}

NEVER:

  • Use arbitrary spacing values outside your scale
  • Make all spacing equal (variety creates hierarchy)
  • Wrap everything in cards (not everything needs a container)
  • Nest cards inside cards (use spacing and dividers for hierarchy within)
  • Use identical card grids everywhere (icon + heading + text, repeated)
  • Default to the hero metric layout (big number, small label, stats, gradient) as a template. If showing real user data, a prominent metric can work, but it should display actual data, not decorative numbers.

Verify Layout Improvements

  • Squint test: Can you identify primary, secondary, and groupings with blurred vision?
  • Rhythm: Does the page have a satisfying beat of tight and generous spacing?
  • Hierarchy: Is the most important content obvious within 2 seconds?
  • Breathing room: Does the layout feel comfortable, not cramped or wasteful?
  • Consistency: Is the spacing system applied uniformly?
  • Responsiveness: Does the layout adapt gracefully across screen sizes?

When the rhythm and hierarchy land, hand off to {{command_prefix}}impeccable polish for the final pass.

Live-mode signature params

Each variant MUST declare a density param. Drive all spacing tokens in the variant's scoped CSS through calc(var(--p-density, 1) * <base>): paddings, gaps, column widths. Users slide from airy to packed and see layout re-breathe with no regeneration.

{"id":"density","kind":"range","min":0.6,"max":1.4,"step":0.05,"default":1,"label":"Density"}

For variants whose topology genuinely changes (stacked vs. side-by-side, grid vs. bento), use a steps param whose scoped CSS branches via :scope[data-p-structure="X"]. One structure param + one density param is a powerful combo; resist adding a third.

{"id":"structure","kind":"steps","default":"grid","label":"Structure","options":[
  {"value":"stacked","label":"Stacked"},
  {"value":"grid","label":"Grid"},
  {"value":"bento","label":"Bento"}
]}

See reference/live.md for the full params contract.