Agent Skills: Frontend Design

Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.

UncategorizedID: Spectaculous-Code/raamattu-nyt/frontend-design

Install this agent skill to your local

pnpm dlx add-skill https://github.com/Spectaculous-Code/raamattu-nyt/tree/HEAD/.claude/skills/frontend-design

Skill Files

Browse the full folder contents for frontend-design.

Download Skill

Loading file tree…

.claude/skills/frontend-design/SKILL.md

Skill Metadata

Name
frontend-design
Description
Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.

Frontend Design

Build polished, native-feeling interfaces for Raamattu Nyt using shadcn/ui, Tailwind CSS, and React.

Tech Stack

  • Components: shadcn/ui (Radix primitives)
  • Styling: Tailwind CSS 3.4 with CSS variables
  • Icons: Lucide React
  • State: React Query + React Hook Form + Zod

Responsive Design — Non-Negotiable

Every component must work on mobile first. The app is used primarily on phones in portrait orientation. Desktop is a md: upgrade, not the baseline.

Rules:

  • Author classes mobile-first; add md:/lg: only to widen, never to fix mobile
  • Test at 375px (iPhone SE / 12-13 mini) AND 430px (iPhone 14 Pro Max) widths mentally before declaring done — different sizes need different rules
  • No fixed pixel widths on layout containers; use w-full, max-w-*, flex-1
  • Hover-only affordances are forbidden — every action must have a touch path
  • Anything fixed at viewport edges must respect safe areas (env(safe-area-inset-*))
  • Text scales down only via text-sm md:text-base patterns, never below 14px on mobile body copy
  • Long labels must truncate or wrap; never let header titles push off-screen
  • For oversized text (cinema verses, prayer headlines): use CSS clamp(min, vw, max) so the screen-size detection happens in CSS, not JS. Add overflow-wrap: break-word; hyphens: none so long Finnish names wrap without tavutusviivoja. See references/mobile.md → Adaptive Typography
  • Avoid @media (max-width: 479px) for "small phone" rules — it matches iPhone 14 Pro Max (430px). For genuine small-phone tier (iPhone SE / 12-13 mini at 375px), use @media (max-width: 380px)

Verified mobile view types

The skill must produce these view archetypes correctly. See references/mobile-views.md for full compositions:

  1. Reader view (light theme): top header with breadcrumb + action icons, centered chapter title, inline superscript verse numbers, highlight-able passages, inline images, bottom tab bar
  2. Cinema/immersive layout (dark, background image + scrim): participant avatar row with active-speaker indicator, step pill nav (1·2·3·4) with progress badge, centered large prayer/verse text, side floating prev/next arrows, circular icon bottom controls
  3. Participants grid + bottom-sheet menu (dark): 2-col avatar tile grid with states (active-speaker, selected, muted), header with counter, bottom sheet stacked over scrim with toggle row + destructive action
  4. Room/landing card view (dark): step pill nav, uppercase section label + large heading, avatar row with invite-tile, large verse card with reference pill, mid-screen action bar (icon — primary CTA — icon), bottom tab bar

If asked to build any of these, read references/mobile-views.md for the exact composition. Do not freelance.

Quick Patterns

Responsive Layout

// Mobile-first with desktop override
<div className="flex flex-col md:flex-row gap-4">
  <div className="w-full md:w-1/3">Sidebar</div>
  <div className="flex-1">Content</div>
</div>

Mobile Bottom Navigation

<nav className="fixed bottom-0 left-0 right-0 z-50 bg-background/95 backdrop-blur-md border-t md:hidden safe-area-bottom">
  <div className="flex items-center justify-around h-16">
    {/* 44px+ touch targets */}
  </div>
</nav>

Sheet for Mobile, Dialog for Desktop

const isMobile = useIsMobile();

return isMobile ? (
  <Sheet>
    <SheetContent side="bottom" className="h-[85vh]">
      {content}
    </SheetContent>
  </Sheet>
) : (
  <Dialog>
    <DialogContent className="max-w-lg">
      {content}
    </DialogContent>
  </Dialog>
);

Modals inside Fullscreen Elements (Cinema Mode, Prayer Room, etc.)

shadcn Dialog, AlertDialog, Sheet, Popover and DropdownMenu use Radix Portal → render to document.body. The browser Fullscreen API only shows DOM inside the fullscreen element, so portaled content disappears. Symptom: button does nothing, no visible dialog, no errors in console.

Two valid fixes — pick by case:

A. Portal-container (preferred for shadcn Sheet / Popover / Dialog): keep using shadcn but redirect the portal target to the fullscreen element.

// apps/raamattu-nyt/src/components/cinema/cinemaPortalContainer.ts
export function getCinemaPortalContainer(): HTMLElement | undefined {
  return (document.fullscreenElement as HTMLElement | null)
    ?? ((document as any).webkitFullscreenElement as HTMLElement | null)
    ?? undefined;  // outside fullscreen → Radix falls back to body
}

// In the sheet:
<Sheet open={open} onOpenChange={...}>
  <SheetContent
    side="bottom"
    container={getCinemaPortalContainer()}
    className="z-[10002] bg-black/95"
    overlayClassName="z-[10002]"
  >
    ...
  </SheetContent>
</Sheet>

B. Inline overlay (use for confirmations / one-off prompts when shadcn is overkill):

{showConfirm && (
  <div className="absolute inset-0 z-[10003] bg-black/70 backdrop-blur-sm flex items-center justify-center p-6">
    <div className="bg-background rounded-2xl p-6 max-w-md w-full">
      <h2>{title}</h2>
      <p>{description}</p>
      <div className="flex gap-2 justify-end mt-4">
        <Button variant="outline" onClick={onCancel}>{t("cancel")}</Button>
        <Button variant="destructive" onClick={onConfirm}>{t("confirm")}</Button>
      </div>
    </div>
  </div>
)}

z-index ladder inside fullscreen: header 10001, content overlays 10002, modals 10003. See cinema-voice-architect skill for details.

Cinema OS — defer to the architect, don't freelance

Cinema OS (the orchestration layer that runs every cinema inside one persistent CinemaShell — Topic / Search / Question / Curated / Discipleship / Prayer Room / Summary as a single session) is owned by the cinema-voice-architect skill, not this one. Any UI work that lands inside src/cinema-os/**, src/features/cinema/**, or a CinemaShell consumer is cinema work: invoke cinema-voice-architect and read Docs/cinema/CINEMA-OS.md first. This skill builds the pixels; the architect owns the contracts.

Load-bearing UI invariants you must NOT break when styling/structuring inside Cinema OS:

  • Apps are shell-less. A Cinema OS app (src/cinema-os/apps/*.tsx) consumes useCinemaShell() — it must never render its own CinemaShell, CinemaPreferencesProvider, or fullscreen wrapper. Two shells = double music + double fullscreen + auto-close race.
  • Never add your own portal. CinemaShell already portals to document.body. For modals inside fullscreen, redirect Radix to getCinemaPortalContainer() (pattern above) — do not createPortal(document.body) from an app.
  • Respect the z-index ladder (header 10001 / overlays 10002 / modals 10003) and ownsChrome apps (PrayerRoom/Discipleship/Summary) that replace OS pills with their own chrome — don't double up nav.
  • Two-level back / ESC is wired by the host. Internal layers register useCinemaBackHandler; don't add competing ESC/back listeners.

If a request is purely "make this cinema screen look/feel better" (spacing, typography, touch targets, animation polish) you can do it here — but check the invariants above and hand any structural/navigation/audio change to cinema-voice-architect.

Touch-Optimized Button

<Button
  className="h-12 px-6 active:scale-95 transition-transform"
  variant="default"
>
  Touch Me
</Button>

Mobile-Native Feel Checklist

  • [ ] Bottom nav visible only on mobile (md:hidden)
  • [ ] Touch targets min 44px (h-11/h-12)
  • [ ] active:scale-95 on tappable elements
  • [ ] Safe area padding (safe-area-bottom class)
  • [ ] Backdrop blur on overlays (bg-background/95 backdrop-blur-md)
  • [ ] Swipe gestures where appropriate
  • [ ] No hover-only interactions on mobile

Design Tokens

/* Use semantic colors */
--background, --foreground
--primary, --primary-foreground
--muted, --muted-foreground
--destructive
--border, --ring

/* Border radius */
--radius: 0.5rem (8px)

When Building UI

  1. Read image inputs - Analyze screenshots/mockups for layout and style
  2. Mobile-first - Start with mobile, add md: breakpoint for desktop
  3. Match an archetype - If the request matches a Verified mobile view type, read references/mobile-views.md first and reuse its composition
  4. Use shadcn - Import from @ui/ not raw Radix
  5. Native feel - Add touch feedback, proper spacing, animations
  6. Accessibility - ARIA labels, focus states, keyboard nav
  7. Verify responsive - Mentally check at 375px width: nothing overflows, all touch targets ≥44px, no hover-only actions

References