홈 / Skills / 웹 및 UI 디자인 / 디자인 테이스트 프런트엔드 Design Taste Frontend
웹 및 UI 디자인

디자인 테이스트 프런트엔드 Design Taste Frontend

LeonxlnxMITSkill 언어: 영어
라이선스 확인됨스크립트 없음중간 위험
실행 예시실제 실행 · claude-sonnet-5-5 · 2026년 10월
Brief: a landing page for "Stillwater", a fictional small-batch loose-leaf tea subscription for design-conscious customers in their 30s. It should feel premium but not stuffy. Stack: Next.js + Tailwind. Do not write the whole page. Give me: (1) your design read and the three dial values with a one-line reason each, (2) a plan of the first five sections with the layout family of each, (3) the full code of the hero section only, (4) a short pre-flight check result listing anything you could not tick.
Skill: design-taste-frontend

1. Design read and dials

Reading this as: a consumer subscription landing page for design-conscious customers in their 30s, with a calm, warm, premium-but-not-stuffy language. It leans toward Tailwind v4 utilities and a sans display face (Geist), with a green palette. There's no official design system for this brief, so the aesthetic is custom and I'm not recreating any system's CSS.

Palette is "Forest": deep tea-green accent on a cool off-white, with a green-tinted off-black for dark mode. I avoided the beige, brass and espresso default, and the accent is locked to one green across the page.

Dial Value Reason
DESIGN_VARIANCE 7 Asymmetric, offset compositions signal design literacy. I'm not going to 9-10 because that tips into agency-experimental, which feels precious rather than approachable.
MOTION_INTENSITY 5 A tea brand should feel unhurried. Spring entrances, hover and press feedback, and scroll reveals are enough, with no pinning or hijacks.
VISUAL_DENSITY 3 Generous space reads as premium, and each section carries one message.

2. First five sections

# Section Layout family Mobile (<768px)
1 Hero: promise, subscribe CTA, and a link to the teas Asymmetric split with an overlapping inset image Single column, text first, then the image
2 This month's three teas Horizontal scroll-snap rail with mixed image aspect ratios (not three equal cards) The rail is the mobile layout, with the next card peeking in
3 How a box works (verb-noun labels such as "Choose", "Brew", "Adjust", not "Step 1") Sticky split: headline pinned left, items scroll right Plain vertical stack, no sticky
4 Where the leaf comes from Full-bleed photo band with one short statement beneath it, not on top of it Same, with a shorter image height
5 What's in the box Bento with exactly 5 cells (a 4+2 row, then 2+2+2), mixing photo, tinted green and plain cells Single column, cells in the same order
  • Layout families: five different families, and no three consecutive image+text splits.
  • Eyebrows: the hero uses none and I'd allow at most one across sections 2-5, which keeps a roughly 9-section page under its cap.
  • Marquee: none planned here. If the page gets one, it belongs in the later logo section.

3. Hero code

Install:

npm install motion @phosphor-icons/react

next.config.ts: needed for the placeholder images.

images: {
  remotePatterns: [
    { protocol: "https", hostname: "picsum.photos" },
    { protocol: "https", hostname: "fastly.picsum.photos" },
  ],
},

app/globals.css: one token strategy, CSS variables, light and dark.

@import "tailwindcss";

:root {
  --surface: #f3f5f1;
  --ink: #151a17;
  --ink-muted: #4b564f;
  --accent: #2c5b43;
  --accent-ink: #f3f5f1;
  --line: #d5dad3;
}

@media (prefers-color-scheme: dark) {
  :root {
    --surface: #0e1310;
    --ink: #e9ede7;
    --ink-muted: #a3aea6;
    --accent: #9ccaa9;
    --accent-ink: #0e1310;
    --line: #26302a;
  }
}

@theme inline {
  --color-surface: var(--surface);
  --color-ink: var(--ink);
  --color-ink-muted: var(--ink-muted);
  --color-accent: var(--accent);
  --color-accent-ink: var(--accent-ink);
  --color-line: var(--line);
  --font-sans: var(--font-geist), ui-sans-serif, system-ui, sans-serif;
}

app/layout.tsx: font wiring only.

import { Geist } from "next/font/google";
const geist = Geist({ subsets: ["latin"], variable: "--font-geist", display: "swap" });
// <html lang="en" className={geist.variable}><body className="bg-surface font-sans text-ink antialiased">

components/reveal.tsx: the only client leaf, which handles entrance motion.

"use client";

import { motion, useReducedMotion } from "motion/react";
import type { ReactNode } from "react";

type RevealProps = {
  children: ReactNode;
  delay?: number;
  y?: number;
  scale?: number;
  className?: string;
};

// Entrance only: sequences the hero so the eye lands on headline, then CTAs, then image.
export function Reveal({ children, delay = 0, y = 16, scale = 1, className }: RevealProps) {
  const reduce = useReducedMotion();
  return (
    <motion.div
      className={className}
      initial={reduce ? false : { opacity: 0, y, scale }}
      animate={{ opacity: 1, y: 0, scale: 1 }}
      transition={{ type: "spring", stiffness: 100, damping: 20, delay }}
    >
      {children}
    </motion.div>
  );
}

components/hero.tsx: a Server Component.

import Image from "next/image";
import { ArrowRight } from "@phosphor-icons/react/dist/ssr";
import { Reveal } from "./reveal";

// Shape rule: one radius (rounded-2xl) for buttons and images.
const button =
  "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-2xl px-6 py-3.5 text-base font-medium " +
  "transition-transform duration-300 ease-[cubic-bezier(0.16,1,0.3,1)] " +
  "hover:-translate-y-0.5 active:translate-y-px active:scale-[0.98] " +
  "motion-reduce:transition-none motion-reduce:hover:translate-y-0 motion-reduce:active:scale-100 " +
  "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent";

export function Hero() {
  return (
    <section className="bg-surface text-ink">
      <div className="mx-auto grid min-h-[100dvh] w-full max-w-7xl grid-cols-1 items-center gap-12 px-4 pb-16 pt-24 sm:px-6 lg:grid-cols-12 lg:gap-8 lg:px-8 lg:pb-12">
        <div className="lg:col-span-6">
          <Reveal>
            <h1 className="text-balance text-5xl font-semibold leading-[1.05] tracking-tight sm:text-6xl xl:text-7xl">
              Good tea, in small batches.
            </h1>
          </Reveal>

          <Reveal delay={0.1}>
            <p className="mt-6 max-w-[44ch] text-lg leading-relaxed text-ink-muted">
              Three single-estate loose-leaf teas, packed in small batches and sent to your door
              every month.
            </p>
          </Reveal>

          <Reveal delay={0.2} className="mt-10 flex flex-wrap items-center gap-3">
            <a href="#plans" className={`${button} bg-accent text-accent-ink`}>
              Start my box
              <ArrowRight size={18} weight="regular" aria-hidden />
            </a>
            <a href="#teas" className={`${button} border border-ink/30 text-ink hover:border-ink`}>
              See the teas
            </a>
          </Reveal>
        </div>

        <div className="relative lg:col-span-5 lg:col-start-8">
          <Reveal y={0} scale={1.04}>
            {/* bg-line reserves the box so there is no layout shift while the image loads */}
            <div className="relative h-[56dvh] w-full overflow-hidden rounded-2xl bg-line lg:h-[min(72dvh,680px)]">
              {/* TODO: replace with real photo, 1200x1500, tea pouring into a ceramic cup */}
              <Image
                src="https://picsum.photos/seed/stillwater-tea-pour/1200/1500"
                alt="Loose-leaf tea being poured into a handmade ceramic cup"
                fill
                priority
                sizes="(min-width: 1024px) 40vw, 100vw"
                className="object-cover"
              />
            </div>
          </Reveal>

          <Reveal delay={0.35} className="absolute -bottom-8 -left-6 hidden sm:block lg:-left-16">
            <div className="relative h-40 w-32 overflow-hidden rounded-2xl border-4 border-surface bg-line lg:h-48 lg:w-40">
              {/* TODO: replace with real photo, 400x520, tin of dried leaf */}
              <Image
                src="https://picsum.photos/seed/stillwater-tea-tin/400/520"
                alt="A tin of dried loose-leaf tea"
                fill
                sizes="160px"
                className="object-cover"
              />
            </div>
          </Reveal>
        </div>
      </div>
    </section>
  );
}

The nav is a separate fixed component. The hero's pt-24 leaves room for a 64px bar.

4. Pre-flight: what I could not tick

  • Real images: no image-generation tool is available here. I used Picsum seeds, which return random photos, not tea. The alt text describes the intended photos, so it will be wrong until real images replace them (TODO comments mark both slots).
  • Both modes tested: not done. I haven't run the app or viewed either theme. The contrast figures are my hand estimates (all above 7:1 for text on surface and for the button labels), not measured.
  • Hero fits the viewport: I reasoned this from the sizing (a 5-word headline that wraps to at most 2 lines, a 15-word subtext, pt-24, image height capped at 72dvh). I haven't checked it in a browser at real viewport sizes.
  • Core Web Vitals and Lighthouse: not run. The hero image uses priority and a reserved box, so LCP and CLS should be fine, but that's unmeasured.
  • Dependency verification: I didn't scaffold a project or inspect a package.json. The install line above is the assumption to check.
  • Navigation (one line, height 80px or less): not built, so not checked.
  • Page-level checks: I only built the hero, so these are planned, not verified:
    • section-layout repetition
    • eyebrow count
    • bento cell count
    • duplicate CTA intent (use "Start my box" everywhere for subscribe intent)
    • logo wall
    • quotes
    • empty, loading and error states beyond the image placeholder

Everything else applicable to the hero ticks. That covers:

  • zero em-dashes
  • theme, accent and radius locks
  • button contrast and no CTA wrap
  • palette and font rules
  • hero stack (headline, subtext, two CTAs, no eyebrow)
  • min-h-[100dvh]
  • reduced-motion handling
  • icons from Phosphor only
  • motion confined to one client leaf

Test run: a fictional tea-subscription brief, asking for the design read, dials, a section plan and only the hero code. Nothing was built or opened in a browser; the model itself listed what it could not check (real images, both themes, Lighthouse). Hero uses placeholder Picsum images, so the alt text will not match until real photos are added.

하는 일

랜딩 페이지, 포트폴리오, 리디자인을 위한 'AI 티 빼기' 프런트엔드 Skill입니다. 코드를 쓰기 전에 에이전트가 요구(페이지 종류, 분위기 단어, 대상, 브랜드 자산, 암묵적 제약)를 읽고 한 줄의 '디자인 리드'를 밝힌 뒤, 디자인 변화도, 모션 강도, 정보 밀도라는 세 개의 다이얼을 정합니다. 그다음 기반을 고릅니다. 요구가 공식 디자인 시스템(Material, Fluent, Carbon, Primer, GOV.UK, USWDS, shadcn/ui 등)에 맞으면 공식 패키지를 쓰고, 글래스모피즘, 벤토, 브루탈리즘 같은 미학이면 순수 CSS로 만들며 그 사실을 솔직히 밝힙니다. 보라색 그라디언트, 같은 폭의 카드 세 장, 어디에나 Inter, div로 만든 가짜 대시보드, 긴 줄표와 장식용 라벨처럼 AI가 흔히 쓰는 기본값을 피하는 규칙이 담겨 있습니다. 다크 모드, 모션 줄이기, 리디자인 모드(유지 또는 전면 개편), 긴 출시 전 체크리스트도 포함합니다.

결과물

디자인 리드, 이유가 붙은 다이얼 값, 레이아웃 유형이 표시된 섹션 계획, 코드(기본은 React, Next.js, Tailwind), 끝내지 못한 점검 항목.

이런 때 좋습니다

마케팅 사이트, 포트폴리오, 리디자인. 대시보드, 데이터 표, 여러 단계의 제품 UI에는 맞지 않다고 Skill 스스로 밝히고 있습니다. 2판은 작성자가 실험 버전으로 표시했습니다.

참고 사항 및 위험

중간 위험:지침만 있는 파일로 자체 스크립트는 없지만, 에이전트가 패키지 설치(npm install, npx shadcn init)를 실행하고 프로젝트에 코드를 쓰게 합니다. 실행 전에 설치 명령을 확인하고 브랜치에서 작업하세요. 약 1200줄로 길어 컨텍스트를 많이 씁니다. 가상의 차 구독 브랜드로 한 번 시험했고, 디자인 리드, 다이얼, 계획, 히어로 코드를 내놓았으며 확인하지 못한 점(실제 이미지 없음, 브라우저 미실행)도 밝혔습니다. 아무것도 설치하거나 실행하지 않았습니다. 작성자 Leonxlnx, MIT, 2판은 실험 버전.

SKILL.md 원본패키지에 파일 2개