0% found this document useful (0 votes)
5 views10 pages

Build Prompt

The document outlines the development phases for building 'Chrome Signal', a headless Shopify merch store, starting with foundational setup using Next.js, Shopify Storefront API, and Tailwind CSS. It details the project scaffolding, environment configuration, design tokens, GraphQL query layer, and core components, followed by the creation of primary pages including a homepage, collection page, and product detail page. Subsequent phases focus on commerce functionality, waitlist systems, animations, and final SEO and performance optimizations before launch.

Uploaded by

xamef48787
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views10 pages

Build Prompt

The document outlines the development phases for building 'Chrome Signal', a headless Shopify merch store, starting with foundational setup using Next.js, Shopify Storefront API, and Tailwind CSS. It details the project scaffolding, environment configuration, design tokens, GraphQL query layer, and core components, followed by the creation of primary pages including a homepage, collection page, and product detail page. Subsequent phases focus on commerce functionality, waitlist systems, animations, and final SEO and performance optimizations before launch.

Uploaded by

xamef48787
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

PHASE 1 — Foundation & Design System

You are building Chrome Signal, an editorial-grade headless Shopify merch store.
Your task in this phase is to scaffold the project and establish every foundational
layer before any page UI is built.

STACK:
- [Link] (Pages Router) — do NOT use App Router
- Shopify Storefront API v2024-01 (GraphQL via graphql-request)
- Tailwind CSS + CSS custom properties
- Framer Motion (install now, use in Phase 3)
- TypeScript throughout

STEP 1 — Project scaffold


Run: npx create-next-app@latest chrome-signal --typescript --tailwind --eslint
Then install: graphql-request graphql framer-motion

STEP 2 — Environment variables


Create .[Link] with these keys (leave values as placeholders):
SHOPIFY_STORE_DOMAIN=
SHOPIFY_STOREFRONT_ACCESS_TOKEN=
NEXT_PUBLIC_SITE_URL=
WAITLIST_WEBHOOK_SECRET=

Create lib/[Link] that initialises a GraphQLClient pointed at


[Link]
with the Storefront access token header.

STEP 3 — Design tokens


In [Link], define these exact CSS custom properties inside :root:
--cs-void: #0A0A0F
--cs-chrome: #C8D4E0
--cs-signal: #00C8FF
--cs-signal-dim: #005F7A
--cs-noise: #1A1A2E
--cs-static: #6B7280
--cs-alert: #FF4444
--cs-gold: #C9A84C

Configure [Link] to expose these tokens as Tailwind colors


(e.g. bg-cs-void, text-cs-signal, border-cs-signal-dim).
Load these Google Fonts via next/font/google: Space Grotesk, Inter, JetBrains Mono.
Map them to Tailwind fontFamily keys: font-display, font-body, font-mono.

STEP 4 — Shopify GraphQL query layer


Create lib/queries/ with individual .ts files for each query:
- [Link] → products(first, query, sortKey)
- [Link] → product(handle) with variants, metafields, images
- [Link] → collections list for nav
- [Link] → collection(handle) with paginated products
- [Link] → predictiveSearch(query)
- [Link] → cart mutation
- [Link] → mutation
- [Link] → mutation
- [Link] → mutation

All metafield queries must request: [Link], custom.edition_label,


custom.size_guide, custom.drop_date, custom.is_limited

STEP 5 — Type definitions


Create types/[Link] with full TypeScript interfaces for:
Product, ProductVariant, Collection, Cart, CartLine, Metafield, Image

STEP 6 — Base components (unstyled logic first, then style)


Build these components in components/ with full TypeScript props:
- NavBar — logo (SVG placeholder), nav links, search icon, cart icon with badge
- ProductCard — image (next/image), name, price, availability badge, quick-add button slot
- CartDrawer — right slide-over panel, line items list, subtotal, checkout CTA, empty state
- Layout — wraps NavBar + children + footer placeholder

NavBar links: SHOP → /collections/all, FIGURES → /collections/figures,


APPAREL → /collections/apparel, ACCESSORIES → /collections/accessories,
LIMITED → /collections/limited

STEP 7 — Cart state


Create context/[Link] using React Context + useReducer.
Actions: ADD_ITEM, REMOVE_ITEM, UPDATE_QUANTITY, SET_CART, OPEN_DRAWER,
CLOSE_DRAWER.
Cart mutations must call the Shopify API and update context optimistically
(update UI immediately, revert on API error).

STEP 8 — Validate
Run: npm run build — zero TypeScript errors required before moving to Phase 2.
Run: npm run dev — NavBar renders, CartDrawer opens and closes, no console errors.
PHASE 2 — Core Pages
The foundation is complete. Now build all three primary page experiences.
Design language: cinematic, high-contrast, editorial. No off-the-shelf component
library aesthetic. Every page uses the Chrome Signal design tokens exclusively.

PAGE 1 — Homepage (pages/[Link])

Hero Section:
- Full-viewport height (h-screen). Background: <video> element with autoPlay muted loop
playsInline.
Accept WebM first, MP4 fallback. If no video env var is set, render a full-bleed
dark image placeholder with a subtle noise texture via CSS (use a pseudo-element
with a repeating-linear-gradient or SVG noise filter).
- Headline: 2–3 word placeholder in font-display font-bold text-[72px] lg:text-[96px]
text-cs-chrome. Drives brand identity.
- Subtext: one line in font-mono text-cs-signal uppercase tracking-widest text-sm.
Content: 'SIGNAL INTERCEPTED. COLLECTION ACTIVE.'
- CTA: 'EXPLORE COLLECTION' button → /collections/all. Style: border border-cs-signal
text-cs-signal hover:bg-cs-signal hover:text-cs-void px-8 py-3 font-display
font-semibold tracking-widest uppercase transition-colors duration-200.

Featured Drop Banner:


- Full-width edge-to-edge section. Background: gradient from --cs-void to --cs-noise
with a CSS noise/halftone texture overlay.
- Accepts a dropConfig prop (can be hardcoded for now):
{ isLive: boolean, productName: string, price: string, dropDate?: Date }
- If isLive: show product name + price + 'SHOP NOW' CTA.
- If upcoming: show product name + <CountdownTimer targetDate={dropDate}> + waitlist
CTA.
- Build <CountdownTimer targetDate: Date /> component now. It uses setInterval
to count down to the target date, showing DD:HH:MM:SS in font-mono.

Category Grid:
- 4 cards in a CSS grid: grid-cols-1 sm:grid-cols-2 on all sizes, max-w-6xl mx-auto.
- Cards: APPAREL → /collections/apparel, FIGURES → /collections/figures,
ACCESSORIES → /collections/accessories, LIMITED → /collections/limited.
- Each card: full-bleed next/image (aspect ratio 4:5), category name in font-display
font-bold text-cs-chrome uppercase, arrow icon (→ or SVG chevron).
- Hover: image scale-105 transition-transform duration-300, category name
underline decoration-cs-signal.
Scrolling Marquee:
- Single line of text looping via CSS animation (keyframes translateX(-50%)).
- Content: 'CHROME SIGNAL · FREQUENCY UNKNOWN · SIGNAL INTERCEPTED ·
LIMITED STOCK ·'
Repeat twice in markup so the loop is seamless.
- Font: font-mono text-cs-static text-sm uppercase tracking-widest.
- Use will-change: transform and GPU compositing (transform only, no left/top).
- Build as <Marquee> component in components/[Link].

Homepage data fetching: getStaticProps with revalidate: 60.


Fetch: featured collection (first 4 products) for category grid.

---

PAGE 2 — Collection Page (pages/collections/[handle].tsx)

Data: getStaticProps + getStaticPaths. Fetch collection by handle with products.

Filter & Sort Bar (<FilterBar>):


- Sticky (position: sticky top-0 z-10 bg-cs-void/90 backdrop-blur-sm).
- Filter facets rendered as pill toggles:
Category (if on /all), Size (XS S M L XL XXL 3XL), Type, Availability (In Stock toggle).
- Sort options: Featured, New Arrivals, Price: Low → High, Price: High → Low.
- All filter/sort state stored in URL query params (?size=M&sort=price-asc).
Use next/router to update params without page reload.
- Active filters rendered as dismissible tag pills below the bar.

Product Grid:
- CSS grid: grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6.
- Each cell is a <ProductCard>. Cards should have:
- next/image with object-cover, aspect-[4/5], bg-cs-noise as placeholder.
- Shimmer loading skeleton (CSS animation) while image loads.
- Product name in font-display font-bold text-cs-chrome.
- <PriceDisplay> component (regular price, sale price struck-through in text-cs-static).
- <AvailabilityBadge> component: IN STOCK (text-cs-signal), LOW STOCK (text-cs-gold),
SOLD OUT (text-cs-static). Low stock = inventoryQuantity < 5.
- Quick-add button: slides up from bottom of card on hover (translateY 0 from 100%).
Desktop only (hidden on touch devices via @media hover: none).

Build <AvailabilityBadge> and <PriceDisplay> as standalone components.

---
PAGE 3 — Product Detail Page (pages/products/[handle].tsx)

Data: getStaticProps + getStaticPaths (all product handles). revalidate: 30.


Fetch: full product with all variants, all images, all required metafields.

Layout desktop: two-column split — image gallery 55% left, product info 45% right.
Layout mobile: stacked, image first.

Image Gallery:
- Large primary image displayed via next/image fill with object-contain.
- Thumbnail strip below (horizontal scroll on mobile). Click thumbnail → swap primary image.
- Click primary image → open lightbox modal (<dialog> element) with full-size image.

Product Info Panel (sticky on desktop: sticky top-24):


- Product name: font-display font-bold text-cs-chrome text-3xl lg:text-4xl.
- Edition label from metafield custom.edition_label: font-mono text-cs-signal text-sm
uppercase tracking-widest.
- <PriceDisplay> — large (text-2xl). Sale: original price struck text-cs-static beside it.
- <VariantSelector> component:
Props: variants, selectedVariant, onSelect.
Renders chip tiles (not dropdowns) — one row per option (Size, Color/Finish).
Sold-out variant tiles: opacity-40 cursor-not-allowed line-through.
Selected tile: border-cs-signal bg-cs-signal text-cs-void.
- 'SIZE GUIDE' text link → opens a modal displaying content from metafield
custom.size_guide.
- Quantity stepper: decrement / number input / increment. min 1 max 10.
- Add to Cart CTA: full-width bg-cs-signal text-cs-void font-display font-bold
uppercase tracking-widest py-4 hover:bg-cs-signal/90 transition-colors.
On click: calls cartAddLines mutation, shows optimistic success (button text → 'ADDED').
- Waitlist CTA: shown when ALL variants are sold out. Links to /waitlist.
Style: full-width border border-cs-signal text-cs-signal.

Product Lore Section:


- Desktop: visible below the two-column section.
- Mobile: inside an <Accordion> component (collapsed by default, label: 'TRANSMISSION
LOG').
- Text from metafield [Link] — rendered in font-mono text-cs-chrome/80 text-sm
leading-relaxed with a left border border-cs-signal-dim pl-4.

Product Details Accordion:


- Four items: Materials & Construction, Sizing & Fit, Care Instructions, Shipping.
- Shipping: static copy for v1 — 'Ships within 5–7 business days.'
- Build <Accordion> as a generic component accepting items: { label, content }[].
Animate open/close with CSS max-height transition.

Build <VariantSelector> and <Accordion> as standalone components.

After all three pages: npm run build must pass with zero errors.

PHASE 3 — Commerce, Waitlist & Animations


Phase 3 completes all commerce functionality, the drop/waitlist system,
and adds the motion layer that defines the Chrome Signal brand feel.

PART A — Commerce hardening

Cart mutations:
Ensure all four Shopify cart mutations (create, addLines, updateLines, removeLines)
are wired in CartContext and called from the correct UI components.
- CartDrawer line items: quantity stepper calls updateLines, × button calls removeLines.
- CartDrawer checkout CTA: links to [Link] from Shopify cart object.
- Cart item count badge on NavBar: reads from CartContext, updates optimistically.
- Empty cart state: font-mono 'NO SIGNAL DETECTED.' centered with link to /collections/all.

Variant + inventory edge cases:


- If a variant's availableForSale is false, the Add to Cart button must be disabled
and replaced with the Waitlist CTA.
- If a product has only one variant (the default variant Shopify creates), hide the
VariantSelector entirely.
- Ensure CartDrawer renders product image thumbnail at 60×60px with next/image.

PART B — Waitlist & Drop system

API route (pages/api/[Link]):


- Accepts POST { email: string, productHandle?: string, listId?: string }.
- Validates email format. Returns 400 on invalid.
- Calls Klaviyo List Subscribe API (or Mailchimp if preferred) using env vars.
Use a placeholder function if API keys are not yet set — log to console and return 200.
- Returns { success: true } on success.

Waitlist Page (pages/[Link]):


- Full-viewport dark layout (bg-cs-void). Optional hero image background.
- Drop name and edition label (can be read from query params: ?drop=iron-banner).
- 1–2 sentence teaser in font-mono text-cs-chrome/70.
- Optional <CountdownTimer> (reuse component from Phase 2).
Shown only if a dropDate env var or query param is provided.
- <WaitlistForm> component:
Single email input + 'JOIN THE SIGNAL' submit button.
On submit: POST to /api/waitlist (no page reload, React state only).
Loading: button shows 'TRANSMITTING...' text.
Success state: hide form, show font-mono 'SIGNAL RECEIVED. STANDBY.'
Error state: show field-level error in text-cs-alert.

<DropBanner> component (already rendered on homepage):


- When isLive: 'SHOP NOW' CTA links to the product's /products/[handle] page.
- When upcoming: countdown + 'JOIN WAITLIST' CTA links to /waitlist?drop=[handle].

PART C — Framer Motion animations

Import motion from 'framer-motion'. Follow Chrome Signal motion principles exactly:

1. Page transitions — in pages/_app.tsx:


Wrap <Component> with <AnimatePresence mode="wait">.
Each page exports a [Link] with:
initial={{ x: 40, opacity: 0 }}
animate={{ x: 0, opacity: 1 }}
exit={{ x: -40, opacity: 0 }}
transition={{ duration: 0.3, ease: 'easeOut' }}
This creates the horizontal slide, not a fade.

2. Product card hover — in <ProductCard>:


Use CSS transitions for scale and box-shadow (not Framer Motion) to keep it GPU-only.
Scale: scale-[1.02] on hover, transition-transform duration-200.
Box shadow: hover:shadow-[0_8px_30px_rgba(0,200,255,0.15)].

3. Hero entrance — on homepage hero elements:


Use Framer Motion staggerChildren (staggerChildren: 0.06).
Text animates first (opacity 0→1, y 20→0), image/video second.
Duration 0.5s ease-out per element.

4. Cart drawer — in <CartDrawer>:


Use Framer Motion AnimatePresence + [Link]:
initial={{ x: '100%' }} animate={{ x: 0 }} exit={{ x: '100%' }}
transition={{ duration: 0.25, ease: 'easeOut' }}
Backdrop: [Link] opacity 0→0.5, bg-black.

5. Search overlay — in <SearchOverlay>:


Full-screen. [Link]: opacity 0→1, scale 0.98→1, duration 0.2s.
Build <SearchOverlay> now if not done in Phase 2:
- Triggered by search icon in NavBar.
- Full-screen overlay (bg-cs-void/95 backdrop-blur).
- Input field autofocused on open.
- Calls predictiveSearch query on input change (debounced 300ms).
- Renders results list as product name + price, each linking to /products/[handle].
- ESC key closes overlay.

6. No mobile parallax, no infinite scroll animations. Disable animations with


prefers-reduced-motion: respect it with Framer Motion's useReducedMotion().

After Phase 3: npm run build passes, cart flow works end-to-end in development mode.

PHASE 4 — SEO, Performance & Pre-Launch Polish


The product is feature-complete. Phase 4 makes it production-ready:
fast, discoverable, accessible, and launch-hardened.

PART A — SEO & Metadata

Custom _document or per-page <Head> via next/head:

1. Dynamic <title> and <meta name="description"> on every page:


- Homepage: 'Chrome Signal — Limited Edition Merch'
- Collection: '{[Link]} — Chrome Signal'
- PDP: '{[Link]} — {[Link] || [Link][:120]}'

2. Open Graph tags on all shareable pages:


og:title, og:description, og:image (Shopify product image URL),
og:url (NEXT_PUBLIC_SITE_URL + pathname), og:type ('product' on PDPs).

3. Twitter card tags: twitter:card='summary_large_image', twitter:image.

4. Canonical URLs on collection pages to prevent filter param duplication:


<link rel="canonical" href={canonicalUrl} /> — strip all query params.

5. JSON-LD structured data on PDPs:


[Link] Product type with: name, description, image[], offers (price, availability,
url), brand. Render as <script type="application/ld+json">.

6. Sitemap: create pages/[Link] using getServerSideProps.


Fetch all product handles and collection handles from Shopify.
Return XML response with <urlset> containing all static + dynamic routes.
Priority: homepage 1.0, collections 0.8, products 0.7.

7. [Link]: create public/[Link].


Allow all crawlers. Sitemap: ${NEXT_PUBLIC_SITE_URL}/[Link].

PART B — Performance

Images:
- Confirm [Link] has [Link]: ['[Link]'].
- All product images: priority={true} on above-the-fold images (hero, first 3 PDPs
in grid). All other images: loading='lazy'.
- Ensure all <Image> components have explicit width + height or use fill with a
sized parent to avoid CLS.

Scripts:
- Any third-party script (Klaviyo, analytics) must use next/script with
strategy='lazyOnload'.
- No script should block the main thread during LCP window.

Font loading:
- Verify next/font/google is used (not a manual <link> tag). This ensures fonts
are self-hosted and don't cause render-blocking.

Cart optimistic UI:


- Confirm add-to-cart does NOT show a spinner. Button text change is the only
feedback during the mutation. Revert on error.

PART C — Accessibility

- All interactive elements (buttons, links, variant chips, accordion triggers):


visible focus ring using outline-cs-signal or ring-cs-signal.
- Cart drawer: when opened, focus moves to the first interactive element inside.
When closed, focus returns to the cart icon in NavBar.
ESC key closes drawer. Focus is trapped inside drawer while open
(use a focus-trap utility or implement manually with keydown listener).
- All <img> and <Image> elements: descriptive alt text.
For decorative images: alt="".
For product images: alt={[Link] || [Link]}.
- <Accordion>: use <button> for triggers (not <div>).
aria-expanded on trigger, aria-controls pointing to content panel.
- SearchOverlay: role="dialog" aria-modal="true", aria-label="Search".
- Color contrast: verify --cs-signal (#00C8FF) on --cs-void (#0A0A0F) in browser
DevTools. Must meet 4.5:1. If it fails, darken --cs-void or lighten --cs-signal
until it passes.

PART D — Error pages & edge states

- pages/[Link]: Chrome Signal branded 404.


Full dark layout, font-mono headline 'SIGNAL LOST. 404.',
subtext 'The frequency you\'re looking for has gone dark.',
CTA back to /collections/all.

- pages/[Link]: same treatment, 'TRANSMISSION FAILED. 500.'

- Sold-out product page: PDP must render, not 404. Show Waitlist CTA.
Never redirect away from a valid product handle.

- Empty collection: render FilterBar + zero results state.


Font-mono: 'NO PRODUCTS ON THIS FREQUENCY.' with link to /collections/all.

PART E — Final validation checklist (run in order)

1. npm run build — zero TypeScript errors, zero ESLint errors.


2. npm run start (production build) — test all routes manually.
3. Cart flow: add item → open drawer → change quantity → remove item → checkout
redirect.
4. Waitlist form: submit valid email → success state → submit invalid email → error state.
5. Filter + sort: apply size filter → URL updates → reload page → filter persists.
6. Search overlay: type query → results appear → click result → navigates to PDP.
7. Mobile: test all pages at 375px width. No horizontal scroll. Cart drawer full-screen.
8. Keyboard-only navigation: tab through entire homepage, PDP, and cart drawer.
9. Run Lighthouse on: homepage, one collection page, one PDP.
Targets: Performance ≥ 90, Accessibility ≥ 90, SEO = 100.
10. Confirm [Link] and [Link] are accessible at root.

Deploy to Vercel: set all environment variables in Vercel project settings,


push to main branch, verify production URL, run smoke test.

You might also like