Philosophy
This skill produces landing pages that are visually audacious — not the typical nested-container, card-grid, predictable web template. Every output should feel like a deliberate design artifact:
- Bold Layout — Clip-path dividers instead of horizontal lines. Type bleeding off-screen. Elements breaking out of their grid. Full-viewport headlines.
- SVG as the Design Core — Not decorative sprinkles. SVG paths animate on scroll, icons have personality, background textures from
<feTurbulence>noise. - Layering and Depth — GSAP ScrollTrigger creates genuine spatial depth: sections that overlap and cover the previous one, sticky panels pinned while content slides over them, parallax on separate z-layers.
- Background Texture — Every section has texture. Never a flat solid background.
- Navigation Surprise — The nav is never a standard horizontal bar.
Bundled Assets (USE THESE — do not reinvent)
This skill comes with pre-built assets. Read and use them directly:
| File | What's in it | When to use |
|---|---|---|
assets/style-preview-template.html |
57-city style preview cards | Step 2: sed fill __PRODUCT_NAME__ + __PRODUCT_HEADLINE__, save as style-preview.html, open |
assets/options-preview-template.html |
Interactive demos: nav styles, color variants, transition styles, hero/features/testimonials variants | Step 3: sed fill city color tokens + product name, save as options-preview.html, open |
assets/textures.css |
6 CSS texture classes (.texture-kyoto, .texture-paris, .texture-tokyo, etc.) |
Copy the matching class into style.css |
assets/gsap-snippets.js |
9 GSAP animation + utility functions (blur entrance, line reveal, parallax, sticky steps, blast menu, magnetic pill, hero demo stepper, animated count, dark mode toggle) | Copy the relevant functions into main.js |
assets/clip-paths.css |
8 clip-path divider classes (.clip-diagonal-br, .clip-parallelogram, .clip-arc-bottom, etc.) |
Use at least 2 in style.css for section dividers |
assets/sections/hero-variants.html |
7 Hero section templates (Full-screen extravagance/Split-screen tension/Minimal descent/Product demo/Text explosion/Magazine tear/Pop-up card) | Step 4: pick the variant matching the user's typography preference, copy and adapt |
assets/sections/features-variants.html |
6 Features section templates (Big numbers/Alternating display/Timeline/Bento grid/Horizontal scroll/Q&A expand) | Step 4: pick based on content type (stats → big number, how-it-works → timeline) |
assets/sections/testimonial-variants.html |
6 Testimonials templates (Compact cards/Single-column quotes/Mosaic collage/Scrolling marquee/Speech bubbles/Avatar wall) | Step 4: pick based on testimonial volume and visual style preference |
assets/sections/conversion-variants.html |
Pricing table, FAQ, brand wall, power CTA | Step 4: copy relevant section, all use CSS custom properties |
assets/sections/footer-variants.html |
3 Footer templates (Minimal single-line/Multi-column links/Magazine editorial) | Step 4: pick based on page complexity and brand tone |
assets/sections/page-variants.html |
3 Sub-page templates (About Us/Contact/Blog List) | Step 4: when user requests multi-page site |
assets/sections/form-variants.html |
3 Form section templates (Email subscription/Waitlist/Inline contact form) | Step 4: when page needs a form section |
assets/sections/extra-variants.html |
6 Extra section templates (Team/Stats/Logo marquee/Portfolio/Tech integrations/Timeline) | Step 4: pick based on product type and content needs |
references/product-demo-hero.md |
Product demo hero principles + scene design guide | Read when user wants to show product workflow in hero (see Step 3/4) |
The quality guarantee of this skill comes from using these assets. They encode specific design decisions that make outputs distinct. Don't describe what to do — copy the code and adapt it.
The Workflow
Step 1: Understand the Product
Use AskUserQuestion to ask:
"Tell me what your landing page is about—the product/service name, and a one-sentence introduction."
Wait for the answer before proceeding.
Detect the conversation language: If the user wrote their answer in English, set LANG_VALUE=en for all subsequent preview commands. If in Chinese, use LANG_VALUE=zh. This determines the UI language of the preview pages.
Check if the user needs sub-pages: After getting the product info, ask:
"Besides the home page, do you need any other pages? You can choose: About Us / Contact / Blog List, or a single-page landing page is enough."
Record the user's choice. If they want sub-pages, note which ones (about / contact / blog). This will be used in Step 4 to generate additional HTML files.
Step 2: Generate the Style Preview
Fill in the two placeholders and open the result — do NOT read the template file into context:
PRODUCT_NAME→ the product name from Step 1PRODUCT_HEADLINE→ a short punchy phrase (3–5 words) that captures the product's essence
_SKILL_DIR=$(ls -d ~/.agents/skills/citycraft 2>/dev/null || ls -d ~/.claude/skills/citycraft 2>/dev/null)
PYTHON=$(command -v python3 2>/dev/null || command -v python 2>/dev/null || echo "")
if [ -n "$PYTHON" ]; then
# Python available (macOS / Linux / WSL / Windows with Python)
# LANG_VALUE detected in Step 1 (zh or en)
"$PYTHON" "$_SKILL_DIR/assets/scripts/run_preview.py" \
--template "$_SKILL_DIR/assets/style-preview-template.html" \
--output ./style-preview.html \
--port 17433 \
--timeout 300 \
"LANG=$LANG_VALUE" \
"PRODUCT_NAME=ACTUAL_PRODUCT_NAME" \
"PRODUCT_HEADLINE=ACTUAL_HEADLINE" \
"RECEIVER_PORT=17433"
else
# No Python — substitute via sed and open as a local file.
# The submit button falls back to clipboard copy automatically.
sed "s/__PRODUCT_NAME__/ACTUAL_PRODUCT_NAME/g; s/__PRODUCT_HEADLINE__/ACTUAL_HEADLINE/g" \
"$_SKILL_DIR/assets/style-preview-template.html" > ./style-preview.html
open ./style-preview.html 2>/dev/null || xdg-open ./style-preview.html 2>/dev/null \
|| echo "Open in browser: $(pwd)/style-preview.html"
echo "Python not found — no live bridge. The submit button will copy the city name to clipboard. Paste it here."
fi
Replace ACTUAL_PRODUCT_NAME and ACTUAL_HEADLINE with the real values from Step 1 in the script arguments.
Windows PowerShell (no WSL/Git Bash): Run
run_preview.ps1directly — it has the same interface. Seeassets/scripts/run_preview.ps1for usage.
Tell the user: "I've opened 57 city-style preview cards in the browser, each one a real rendered result. Scroll down to see them all—from Kyoto to Lagos to Palm Springs, and on to Istanbul, Miami, Chengdu, Copenhagen, Vienna, Cape Town, Bogotá, Amsterdam, Beirut, Portland, as well as Shanghai, Beijing, Chongqing, Xi'an, Hangzhou, Shenzhen Night, Dunhuang, Suzhou, Lhasa, Rome, Prague, Melbourne, Athens, Casablanca, Busan, Bali, Toronto, Tel Aviv, Warsaw, Mumbai Night, plus the newly added Osaka, Chiang Mai, Milan, Taipei, New Orleans, Zurich, and Vancouver. Once you've chosen, just click the card to send it to me; if the local bridge isn't connected, you can also copy the city name and tell me. If none of the 57 cities is right, just describe it to me in your own words."
Step 3: Open the Interactive Options Preview
The user has chosen their city. Now open the visual options preview so they can feel the layout and nav choices instead of reading descriptions.
If the user clicked "让 AI 来选" (city =
__AI_CHOOSE__): Skip the preview entirely. Instead, look back at the conversation to understand the product's audience, industry, and tone. Then pick the single most fitting city fromreferences/city-styles.mdand briefly explain why (2–3 sentences). Confirm with the user: "我为你选了 [城市]——[理由]. 继续吗?" Then proceed to Step 3 with that city.
3a — Get city color tokens (script, not file read)
Run get_city_tokens.py to extract just the 5 color values — do NOT read city-styles.md into context:
_SKILL_DIR=$(ls -d ~/.agents/skills/citycraft 2>/dev/null || ls -d ~/.claude/skills/citycraft 2>/dev/null)
PYTHON=$(command -v python3 2>/dev/null || command -v python 2>/dev/null || echo "")
# Outputs CITY_BG=, CITY_SURFACE=, CITY_INK=, CITY_MUTED=, CITY_ACCENT=
eval $("$PYTHON" "$_SKILL_DIR/assets/scripts/get_city_tokens.py" "ACTUAL_CITY_NAME")
Replace ACTUAL_CITY_NAME with the city name the user chose (Chinese or English). The script handles both. If the city isn't found, it exits 1 — in that case fall back to reading the ### Colors section of references/city-styles.md manually.
3b — Generate and open options-preview.html
Use the $CITY_* variables from 3a. Do NOT read the template file into context:
if [ -n "$PYTHON" ]; then
# LANG_VALUE detected in Step 1 (zh or en)
"$PYTHON" "$_SKILL_DIR/assets/scripts/run_preview.py" \
--template "$_SKILL_DIR/assets/options-preview-template.html" \
--output ./options-preview.html \
--port 17432 \
--timeout 300 \
"LANG=$LANG_VALUE" \
"PRODUCT_NAME=ACTUAL_PRODUCT_NAME" \
"PRODUCT_HEADLINE=ACTUAL_HEADLINE" \
"CITY_NAME=ACTUAL_CITY_NAME" \
"CITY_BG=$CITY_BG" \
"CITY_SURFACE=$CITY_SURFACE" \
"CITY_INK=$CITY_INK" \
"CITY_MUTED=$CITY_MUTED" \
"CITY_ACCENT=$CITY_ACCENT" \
"CITY_DARK_BG=#0e0c09" \
"CITY_DARK_SURFACE=#1e1b16" \
"CITY_DARK_INK=#f2ede4" \
"CITY_DARK_ACCENT=$CITY_ACCENT" \
"CITY_BRIGHT_BG=#fdf9f2" \
"CITY_BRIGHT_SURFACE=#fffdf8" \
"CITY_BRIGHT_INK=#1a1510" \
"CITY_BRIGHT_ACCENT=$CITY_ACCENT" \
"RECEIVER_PORT=17432"
else
sed \
-e "s/__PRODUCT_NAME__/ACTUAL_PRODUCT_NAME/g" \
-e "s/__PRODUCT_HEADLINE__/ACTUAL_HEADLINE/g" \
-e "s/__CITY_NAME__/ACTUAL_CITY_NAME/g" \
-e "s/__CITY_BG__/$CITY_BG/g" \
-e "s/__CITY_SURFACE__/$CITY_SURFACE/g" \
-e "s/__CITY_INK__/$CITY_INK/g" \
-e "s/__CITY_MUTED__/$CITY_MUTED/g" \
-e "s/__CITY_ACCENT__/$CITY_ACCENT/g" \
-e "s/__CITY_DARK_BG__/#0e0c09/g" \
-e "s/__CITY_DARK_SURFACE__/#1e1b16/g" \
-e "s/__CITY_DARK_INK__/#f2ede4/g" \
-e "s/__CITY_DARK_ACCENT__/$CITY_ACCENT/g" \
-e "s/__CITY_BRIGHT_BG__/#fdf9f2/g" \
-e "s/__CITY_BRIGHT_SURFACE__/#fffdf8/g" \
-e "s/__CITY_BRIGHT_INK__/#1a1510/g" \
-e "s/__CITY_BRIGHT_ACCENT__/$CITY_ACCENT/g" \
"$_SKILL_DIR/assets/options-preview-template.html" > ./options-preview.html
open ./options-preview.html 2>/dev/null || xdg-open ./options-preview.html 2>/dev/null \
|| echo "Open in browser: $(pwd)/options-preview.html"
echo "Python not found — no live bridge. Use the copy button in the preview and paste the result here."
fi
The dark variant (__CITY_DARK_*) is always the luxury/night treatment — near-black bg, warm light text, same accent. The bright variant is always the fresh/modern treatment — near-white bg, dark text, same accent. The city's identity comes from the base colors and accent, not from the dark/bright shell.
Windows PowerShell (no WSL/Git Bash): Run
run_preview.ps1directly. Seeassets/scripts/run_preview.ps1for usage.
When the script exits, it prints the result JSON to stdout. If it times out, ask the user to type their choice manually before proceeding.
Tell the user: "I've opened an interactive selection page in the browser—with live demos of typography and navigation, a comparison of three color schemes, and a visual preview of the transition styles between sections. You can click the full-screen menu to see how it bursts open, and move the cursor close to the bottom pill to feel the magnetic effect. Once everything is selected, click the '告诉 Agent →' button at the bottom, and I'll automatically receive the results and continue generating; if the local bridge isn't connected, just copy the results and paste them to me."
If the user chose a non-city description (scene, era, material, emotion): read references/imagery-derivation.md to derive the design token system first, use those derived colors as the CITY_* arg values above, then proceed normally.
If the script prints JSON, parse it directly and continue to Step 4 with city, layout, nav, tone, transitions, hero, features, and sections. If it times out, ask the user to paste their choices manually before proceeding.
Additional choices not in the preview JSON — these are determined by the agent based on Step 1 and the product context:
footer: Pick A (minimal), B (multi-column), or C (editorial) fromfooter-variants.htmlbased on page complexityform: Pick NEWSLETTER, WAITLIST, or CONTACT_INLINE fromform-variants.htmlif the user's sections include a form need, or skip if notpages: List of sub-pages from Step 1 (e.g.["about", "contact"]), or empty if single-page
Step 4: Generate the Landing Page
Output into {product-name}-landing/:
{product-name}-landing/
├── index.html
├── style.css
├── main.js
├── about.html ← optional sub-pages
├── contact.html ← optional sub-pages
├── blog.html ← optional sub-pages
└── assets/
└── icons.svg
Multi-page support: If the user requests sub-pages (about, contact, blog), generate them as separate HTML files in the same directory. Each sub-page:
- Shares the same
style.css,main.js, andassets/icons.svgasindex.html - Uses the same nav (with links updated to point to sibling pages) and footer
- Content comes from
assets/sections/page-variants.html(variants:ABOUT,CONTACT,BLOG) - Has its own
<title>and<meta>tags following the SEO baseline (Design Law 11)
Extract sub-page content in the Bash Assembly step:
python3 "$_SKILL_DIR/assets/scripts/extract_variant.py" \
"$_SKILL_DIR/assets/sections/page-variants.html" ABOUT >> "$_OUT/_pages.html"
python3 "$_SKILL_DIR/assets/scripts/extract_variant.py" \
"$_SKILL_DIR/assets/sections/page-variants.html" CONTACT >> "$_OUT/_pages.html"
Read _pages.html alongside other staging files, then write each sub-page as a complete HTML document wrapping the nav + page content + footer.
4a — Bash Assembly (do this first, before writing any file)
The goal is to avoid outputting bundled asset code as model tokens. Instead, use Bash to copy and pipe the ready-made assets into the output files. Only product-specific content (copy, tokens, overrides) is written by the model.
Step 1 — Set up directories
_SKILL_DIR=$(ls -d ~/.agents/skills/citycraft 2>/dev/null || ls -d ~/.claude/skills/citycraft 2>/dev/null)
_OUT="./{product-name}-landing"
mkdir -p "$_OUT/assets"
Step 2 — Assemble section variants into a staging file
Plan which variants to use (see table below), then pipe each into a staging file:
# Replace B / C / B / PRICING with the user's actual choices
python3 "$_SKILL_DIR/assets/scripts/extract_variant.py" \
"$_SKILL_DIR/assets/sections/hero-variants.html" B > "$_OUT/_sections.html"
python3 "$_SKILL_DIR/assets/scripts/extract_variant.py" \
"$_SKILL_DIR/assets/sections/features-variants.html" C >> "$_OUT/_sections.html"
python3 "$_SKILL_DIR/assets/scripts/extract_variant.py" \
"$_SKILL_DIR/assets/sections/testimonial-variants.html" B >> "$_OUT/_sections.html"
python3 "$_SKILL_DIR/assets/scripts/extract_variant.py" \
"$_SKILL_DIR/assets/sections/conversion-variants.html" PRICING >> "$_OUT/_sections.html"
python3 "$_SKILL_DIR/assets/scripts/extract_variant.py" \
"$_SKILL_DIR/assets/sections/conversion-variants.html" CTA >> "$_OUT/_sections.html"
python3 "$_SKILL_DIR/assets/scripts/extract_variant.py" \
"$_SKILL_DIR/assets/sections/footer-variants.html" B >> "$_OUT/_sections.html"
# If user needs a form section, add it:
python3 "$_SKILL_DIR/assets/scripts/extract_variant.py" \
"$_SKILL_DIR/assets/sections/form-variants.html" NEWSLETTER >> "$_OUT/_sections.html"
# If user requested sub-pages, extract them:
python3 "$_SKILL_DIR/assets/scripts/extract_variant.py" \
"$_SKILL_DIR/assets/sections/page-variants.html" ABOUT >> "$_OUT/_pages.html"
python3 "$_SKILL_DIR/assets/scripts/extract_variant.py" \
"$_SKILL_DIR/assets/sections/page-variants.html" CONTACT >> "$_OUT/_pages.html"
For testimonials use: A, B, C, D, E, F
For conversion sections use: PRICING, COMPARE_PRICING, BRAND_WALL, CTA, FAQ_A, FAQ_B
For footer use: A (minimal), B (multi-column), C (editorial)
For forms use: NEWSLETTER, WAITLIST, CONTACT_INLINE
For sub-pages use: ABOUT, CONTACT, BLOG
Step 3 — Copy bundled CSS utilities into style.css base
# Texture: use --texture flag (never read full city-styles.md)
python3 "$_SKILL_DIR/assets/scripts/get_city_tokens.py" "CITY_NAME" --texture > "$_OUT/_texture.css"
# Clip-paths: copy all classes, model picks which to apply via class names
cat "$_SKILL_DIR/assets/clip-paths.css" >> "$_OUT/_texture.css"
Step 4 — Copy GSAP snippets into main.js base
cat "$_SKILL_DIR/assets/gsap-snippets.js" > "$_OUT/_gsap-base.js"
Now read the staging files (_sections.html, _texture.css, _gsap-base.js, and _pages.html if sub-pages were requested) to understand what's available, then write the final output files.
4b — Section Variant Reference
Common page sequences:
- SaaS tool: Hero D → Features C → Features A → Testimonials A → Pricing → FAQ A → Newsletter → CTA → Footer B
- Agency portfolio: Hero A → Features B → Testimonials C → Contact Inline → CTA → Footer C
- Developer tool: Hero B → Features C → Features A → Testimonials A → Pricing → FAQ B → Newsletter → CTA → Footer B
- Luxury product: Hero C → Features B → Testimonials B → CTA → Footer C
- B2C app: Hero E → Features E → Testimonials F → Waitlist → CTA → Footer A
- Startup pre-launch: Hero G → Features D → Waitlist → FAQ A → Footer A
| If the user needs... | Use this template | Variant |
|---|---|---|
| Hero — massive bold statement | Full-screen extravagance | A |
| Hero — product visual + headline | Split-screen tension | B |
| Hero — elegant, story-first | Minimal descent | C |
| Hero — product has a workflow to show | Product demo type | D (also read references/product-demo-hero.md) |
| Hero — typography-led, high-impact | Text explosion type | E |
| Hero — editorial storytelling | Magazine tear type | F |
| Hero — playful product launch | Pop-up card type | G |
| Features — data/metrics focus | Big numbers | A |
| Features — product screenshots | Alternating display | B |
| How it works — step-by-step | Timeline | C |
| Features — modular story blocks | Bento grid type | D |
| Features — browseable capability ribbon | Horizontal scrolling cassette type | E |
| Features — objection handling | Q&A expand type | F |
| Pricing table | Pricing table | PRICING |
| Pricing comparison with toggle | Comparison pricing table | COMPARE_PRICING |
| Testimonials — compact grid | Compact card grid | A |
| Testimonials — magazine style | Single-column quote wall | B |
| Testimonials — masonry layout | Mosaic collage | C |
| Testimonials — horizontal scroll | Scrolling Marquee | D |
| Testimonials — conversation bubbles | Chat Bubble | E |
| Testimonials — avatar wall | Video Avatar Wall | F |
| Trusted brand logos | Brand Wall | BRAND_WALL |
| Final CTA | Strong CTA Section | CTA |
| FAQ — editorial layout | Editorial Layout Type | FAQ_A |
| FAQ — card grid | Full-Width Focus Type | FAQ_B |
| Footer — minimal single row | Minimalist Single Line | A (footer-variants.html) |
| Footer — multi-column links | Multi-Column Links | B (footer-variants.html) |
| Footer — editorial with watermark | Magazine Editorial Type | C (footer-variants.html) |
| Sub-page — About / Brand story | About Us | ABOUT (page-variants.html) |
| Sub-page — Contact with form | Contact Information | CONTACT (page-variants.html) |
| Sub-page — Blog post listing | Blog List | BLOG (page-variants.html) |
| Form — Newsletter subscribe | Email Subscription | NEWSLETTER (form-variants.html) |
| Form — Waitlist signup | Waitlist | WAITLIST (form-variants.html) |
| Form — Inline contact form | Embedded Contact Form | CONTACT_INLINE (form-variants.html) |
| Team member cards | Team Members | TEAM (extra-variants.html) |
| Stats / Numbers showcase | Data Statistics | STATS (extra-variants.html) |
| Logo infinite scroll | Brand Scrolling Wall | LOGO_SCROLL (extra-variants.html) |
| Gallery / Portfolio grid | Portfolio Showcase | GALLERY (extra-variants.html) |
| Integrations / Tech stack | Technology Integration | INTEGRATIONS (extra-variants.html) |
| Timeline / Milestones | Timeline | TIMELINE (extra-variants.html) |
4c — Write the Output Files
index.html — Write with the Write tool. No markdown block, directly to file.
- Document structure:
<html>,<head>(Google Fonts, GSAP CDN, link to style.css + main.js),<body> - Nav HTML matching the selected nav style
- Paste
<style>blocks and<section>HTML from_sections.htmlin page order - Replace all placeholder copy with real product copy — fit the city aesthetic's tone of voice
- No Lorem Ipsum, no placeholder text
- Break template uniformity: vary visual weight across items within each section. The template shows a repeating pattern — make one item the focal point (accent background, larger card, featured badge, different internal layout) and let others recede. No section should look like a grid of clones.
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/ScrollTrigger.min.js"></script>
style.css — Write with the Write tool. Structure:
:rootblock — full design token system: colors from$CITY_*tokens, chosen fonts, spacing scale, radii. This is the only part the model writes from scratch.[data-theme="dark"]block — dark variant tokens using$CITY_DARK_*values from Step 3. This enables runtime dark mode toggle.- Paste texture + clip-path CSS from
_texture.css - Nav CSS matching the selected nav style (from
references/nav-catalog.md) - Layout and typography overrides — only what differs from section defaults
clamp() for ALL headline font sizes:
- Hero Main Title:
clamp(2.8rem, 7vw, 7rem)— even the extravagant type does not exceed 7rem - Section Title:
clamp(2rem, 4vw, 4rem) - Large Numbers/Decorative Numbers:
clamp(4rem, 10vw, 9rem) - Subtitle/Description Text:
clamp(1rem, 1.4vw, 1.2rem)
Do NOT add comments to style.css — they consume tokens and add no value to the output file.
main.js — Write with the Write tool. Structure:
gsap.registerPlugin(ScrollTrigger)- Paste the relevant functions from
_gsap-base.js— required minimum:initHeroEntrance()— stagger hero elements ininitParallax()— at least 2 layers at different speeds- Section heading reveals on viewport entry
initStickySteps()ORinitBlastMenu()ORinitMagneticPill()— matching nav/layout
initDarkModeToggle(".theme-toggle")— enable dark/light mode switching- Call sequence at bottom;
ScrollTrigger.refresh()after fonts load
Do NOT add comments to main.js.
assets/icons.svg — SVG sprite with <symbol> elements. At minimum: logo mark, nav toggle, arrow, checkmark, 2–3 product-relevant feature icons. Icon style must match the city aesthetic's stroke weight and geometry.
After all files are written, delete the staging files:
rm -f "$_OUT/_sections.html" "$_OUT/_texture.css" "$_OUT/_gsap-base.js" "$_OUT/_pages.html"
Step 5: Preview the Result
After all files are written, open the generated page in the browser so the user sees it immediately:
open "$_OUT/index.html" 2>/dev/null || xdg-open "$_OUT/index.html" 2>/dev/null || echo "Preview ready: $(cd "$_OUT" && pwd)/index.html"
Tell the user: "The landing page has been generated and opened in the browser. If you need to adjust any details, just let me know."
Step 6: Deploy (Optional)
After the user confirms the page looks good, ask if they want to deploy it online:
"Would you like me to help you deploy this site online? It supports three methods: Netlify, Vercel, and GitHub Pages."
Option A: Netlify
cd "$_OUT"
npx netlify deploy --dir=. --message="Landing page deploy from citycraft"
This creates a draft deploy with a preview URL. If confirmed:
npx netlify deploy --dir=. --prod --message="Production deploy from citycraft"
Option B: Vercel
cd "$_OUT"
npx vercel --yes
This deploys a preview. If confirmed:
npx vercel --prod --yes
Option C: GitHub Pages
cd "$_OUT"
git init && git add -A && git commit -m "deploy: landing page"
gh repo create {product-name}-site --public --source=. --push
gh api -X POST repos/{owner}/{product-name}-site/pages -f source='{"branch":"main","path":"/"}'
Then the site will be live at https://{owner}.github.io/{product-name}-site/.
Notes:
- First-time users will be prompted to log in to the chosen platform via browser
- All three platforms deploy static files directly, no build step needed
- If the user doesn't specify a platform, default to Netlify
Design Laws (Never Break These)
- No
#ffffffbackgrounds. Not on sections, not on cards. Warm neutrals:#f5ede0. Cool:#edf0ee. Dark:#08060f. Cards get a slight tint, never pure white. - No
#6366f1. Color comes from the city style palette. - Decide the transition type independently for each section boundary. Every pair of adjacent sections has its own visual relationship — don't reuse the same clip-path class everywhere. The user chooses a transition direction (geometric sharp / organic soft / cover-blend / minimal line / AI auto) in the options preview. Use that direction to constrain which classes you pick:
GEOMETRIC→ diagonals, chamfers, steps;ORGANIC→ curves, scallops, arcs;BLEND→ cover overlays and gradient dissolves;MINIMAL→ hairline rules. If__AI_CHOOSE__, scan the selected city's entry inreferences/city-styles.mdfor divider/transition language first. Then apply per-boundary logic: consider what the two sections are (hero → features, features → pricing, etc.), their relative energy, and the overall page rhythm. Available classes inassets/clip-paths.css: diagonal (clip-diagonal-*,clip-parallelogram), curved (clip-round-bottom,clip-scallop,clip-arc-bottom), gradient dissolve (section-dissolve), flat rule (section-rule). - No generic icons. Match the city style's stroke weight and geometry.
- Two typefaces minimum. Display/serif for headlines + clean sans for body. From
references/city-styles.md. Decorative/script accent fonts (when a city style mentions one) go on watermarks, pull quotes, or ornamental elements — never on buttons, nav, or body copy. - Nav must surprise. Use the chosen nav from
references/nav-catalog.mdwith its full surprise element implemented. - Use bundled assets. The texture, GSAP snippets, and clip-paths must come from the skill's asset files — not reimplemented from scratch.
.line-wrapCJK fix. Whenever the page has Chinese or Japanese text and uses.line-wrap { overflow: hidden }for line reveal animations, addpadding-top: 0.15em; margin-top: -0.15em;to prevent CJK ascenders from being clipped at the top.- No clone grids. When a section contains multiple repeating items (feature rows, pricing cards, FAQ items, testimonials), they must not all share the same visual treatment. One item should be the focal point — larger, accented, or with a distinct layout — while others form the supporting cast. A section should feel like a poster with visual hierarchy, not a spreadsheet of identical rows. This is the single biggest cause of pages looking "templated" rather than designed.
- Responsive by default. Every page must work on mobile (375px) through desktop (1440px). Rules:
- Hero text: use
clamp()for all font sizes, never fixedpx/remalone - Grid layouts: collapse to single column below 768px via
@media (max-width: 768px) - Navigation: pill nav shrinks gap/padding on mobile; side nav hides on mobile with a toggle
- Touch targets: all buttons and links minimum 44px height
- No horizontal scroll: test with
overflow-x: hiddenonbody, but fix the root cause - Images/SVGs: use
max-width: 100%andaspect-ratioto prevent layout shift
- Hero text: use
- SEO baseline. Every generated
index.htmlmust include:<title>with product name and value proposition (under 60 chars)<meta name="description">with a compelling summary (under 155 chars)<meta property="og:title">,og:description,og:type(website)<meta name="viewport" content="width=device-width, initial-scale=1.0">- Semantic HTML: one
<h1>, sequential heading hierarchy (h1→h2→h3),<nav>,<main>,<footer> langattribute on<html>matching the page language
- Footer required. Every page must have a
<footer>with at minimum: brand name, copyright year, and a link back to top or to the product. No page ends abruptly after the last section. - Accessibility baseline. Every generated page must:
- Use the
prefersReducedMotionguard fromgsap-snippets.js(function 0) - Include
<a class="skip-link" href="#main">for keyboard users - Ensure all interactive elements have visible
:focus-visiblestyles - Use
aria-expandedon FAQ accordion triggers and nav toggles
- Use the
Reference Files
references/city-styles.md— Exact design parameters (fonts, colors, textures, motion, icons) for each city aestheticreferences/nav-catalog.md— 4 nav styles with full implementation notes and GSAP codereferences/imagery-derivation.md— How to translate any non-city description (scene, era, material, emotion) into a concrete design token system. Read this whenever the user describes something that isn't one of the 57 city cards.references/product-demo-hero.md— When and how to build a time-driven product workflow demo in the Hero (Variant D). Includes scene design guide, 3-act structure, onEnter() callback patterns, and product-type → scene mapping table. Read this whenever the user wants to show their product's process in the hero.