diff --git a/crates/op-ai-skills/skills/phases/generation/jsonl-format.md b/crates/op-ai-skills/skills/phases/generation/jsonl-format.md index ce218a3cc..2adf7d7b7 100644 --- a/crates/op-ai-skills/skills/phases/generation/jsonl-format.md +++ b/crates/op-ai-skills/skills/phases/generation/jsonl-format.md @@ -38,6 +38,7 @@ RULES: DESIGN SYSTEM TOKENS — prefer refs over literals so output respects the user's design system. The renderer resolves refs against `doc.variables` (or a default light palette when un-seeded), so refs are SAFE even when the doc has no design system seeded yet. - COLORS: `$color-{bg-deep|surface|surface-2|surface-3|border|border-strong|text-primary|text-body|text-muted|text-subtle|accent|destructive|success|scrim|info-bg|info-text|success-bg|success-text|warning-bg|warning-text|danger-bg|danger-text|chart-1..6}`. Light defaults: bg-deep `#F8FAFC`, surface `#FFFFFF`, surface-2 `#F1F5F9`, border `#E2E8F0`, text-primary `#0F172A`, text-body `#334155`, text-muted `#64748B`, text-subtle `#94A3B8`, accent `#2563EB`, destructive `#EF4444`, success `#10B981`. +- SEMANTIC-COLOR DISCIPLINE (critical): the `*-bg` / `*-text` state tokens (`info-bg/info-text`, `success-bg/success-text`, `warning-bg/warning-text`, `danger-bg/danger-text`) are RESERVED for status/feedback elements ONLY — error banners, success toasts, validation messages, status badges. NEVER use them as a decorative or neutral surface. A search input, a category chip, a filter pill, a card, a section background, an icon tile — these are NEUTRAL surfaces: use `$color-surface` / `$color-surface-2` / `$color-surface-3`, or a tint of `$color-accent`, NEVER `$color-danger-bg` (it is a pinkish-red and will clash with the theme). Picking a state token just because it is "a light color" is a bug — match the token's SEMANTICS to the element's purpose. - TYPOGRAPHY: `$type-{display|h1|h2|h3|body|caption}-{size|weight|line-height}`. Defaults: display 64/700/1.0, h1 24/600/1.2, h2 20/600/1.25, h3 16/600/1.3, body 14/400/1.5, caption 12/400/1.4. Plus `$type-display-letter-spacing` (-0.5), `$type-uppercase-label-letter-spacing` (1.5). - SPACING / RADIUS: `$spacing-{1|2|3|4|5}` = 4/8/12/16/24 px. `$radius-{sm|md|lg}` = 4/8/12 px. diff --git a/crates/op-ai-skills/skills/phases/generation/overflow.md b/crates/op-ai-skills/skills/phases/generation/overflow.md index 7ad523f3d..09203fe53 100644 --- a/crates/op-ai-skills/skills/phases/generation/overflow.md +++ b/crates/op-ai-skills/skills/phases/generation/overflow.md @@ -51,11 +51,15 @@ Structure: - Inside it, a row frame with `width="fit_content"`, `height="fit_content"`, `layout="horizontal"`, `gap=12`, `padding=[0,20]`. - The row frame holds the actual cards. -Every card in the row MUST: +Every **content / product / workout card** in the row MUST: - Have a FIXED numeric `width` (typically 120-160 for mobile, 200-260 for desktop). Never `fill_container`, never `fit_content` - fixed pixels. - Share identical width with its siblings for visual rhythm. +**EXCEPTION — nav chips / category chips / filter tags** (icon + short label like "All" / "Pizza" / "Videos"): use `width="fit_content"`, NEVER a fixed 120-160. That fixed width is content-card sizing; a 6-chip category row at 132px each becomes ~800px and scrolls off-screen for what should comfortably fit on one screen. With `fit_content`, a handful of short chips sit on one row (no scroll), and only a genuinely long list scrolls. Keep the same clipContent wrapper + fit_content row — just let each chip hug its content (icon + label + small horizontal padding). + +**COUNT CAP for a no-scroll chip row (mobile 375px):** even at `fit_content`, only ~4-5 icon+label chips fit one phone width. If the design is meant to fit on screen WITHOUT horizontal scrolling, emit only the chips that fit (the top 4-5 categories) — do NOT pack 6+ chips into the row, the extras render off the right edge of the device. If you genuinely need all categories, you MUST place the row inside the `clipContent` wrapper above so the overflow clips at the screen edge (scroll row) instead of spilling past the phone frame. A bare horizontal frame with 6+ chips and no `clipContent` ancestor is the #1 mobile overflow bug — never emit it. + Example - 6 workout cards inside a 375px-wide mobile page: ```json @@ -112,5 +116,5 @@ Anti-patterns (do NOT emit any of these): - Putting 5+ cards directly inside a `layout="horizontal"` page-root frame (they overflow the phone width). - Using `fill_container` on cards in a horizontal row (they squish down to invisibility). -- Using `width="fit_content"` on cards - text-driven widths are unpredictable and break rhythm. +- Using `width="fit_content"` on **content/product cards** - text-driven widths are unpredictable and break rhythm. (Nav / category chips are the EXCEPTION above — those SHOULD use fit_content so a short row fits one screen.) - Skipping the `clipContent=true` wrapper and relying on Skia to clip (it doesn't — only `clipContent:true` enables clipping). diff --git a/crates/op-ai-skills/skills/phases/planning/decomposition.md b/crates/op-ai-skills/skills/phases/planning/decomposition.md index f142c698d..c1208d628 100644 --- a/crates/op-ai-skills/skills/phases/planning/decomposition.md +++ b/crates/op-ai-skills/skills/phases/planning/decomposition.md @@ -49,7 +49,8 @@ RULES: - STYLE SELECTION: Choose light or dark theme based on user intent. Dark: user mentions dark/cyber/terminal/neon/夜间/暗黑/deep/gaming/noir. Light (default): all other cases — SaaS, marketing, education, e-commerce, productivity, social. Never default to dark unless the content clearly calls for it. - Detect the design type FIRST, then choose the appropriate structure and subtask count. - Multi-section pages (type 1): include Navigation Bar as the FIRST subtask, followed by Hero, feature sections, CTA, footer, etc. (6-10 subtasks) -- Single-task screens (type 2): do NOT include Navigation Bar, Hero, CTA, or footer. Only include the actual UI elements needed (1-5 subtasks). +- Single-task mobile screens (type 2 — login, signup, profile, settings, a single form/detail view): do NOT include Navigation Bar, Hero, CTA, or footer. Only include the actual UI elements needed (1-5 subtasks). +- Mobile app HOME / feed / main / discover screens (type 2 but MULTI-section — a food/shopping/social/delivery app homepage, a dashboard feed, etc.): plan the content sections (header, search, categories, featured/banner, lists…) AND **ALWAYS include a "Bottom Navigation Bar" as the LAST subtask** — a fixed tab bar with 4-5 items (e.g. Home / Search / Orders / Profile), each an icon + label, active state on the first. A mobile app's main screen WITHOUT a bottom nav is incomplete — never omit it. (Only the single-task screens above are the exception: they have no bottom nav.) - FORM INTEGRITY: Keep a form's core elements (inputs + submit button) in the same subtask. Splitting inputs into one subtask and the button into another causes duplicate buttons. - Combine related elements: "Hero with title + image + CTA" = ONE subtask, not three. - Each subtask generates a meaningful section (~10-30 nodes). Only split if it would exceed 40 nodes.