# Pagekit

> Build a complete landing page or portfolio site from a short interview — for someone who does not write code. Runs a four-round questionnaire, picks a design direction, scaffolds Next.js + Tailwind + shadcn/ui, writes the page, deploys it with no Vercel account, then sets up structured data, llms.txt, robots.txt and metadata so search engines and AI assistants can actually read it. Use when the user says "build me a website", "landing page", "portfolio site", "make a site for my business", "página web", "landing", or asks for a one-page site for a small business.

- Skill: `kraayenjon/pagekit` (Agent Skill)
- Install (CLI): `npx skillmds@latest add kraayenjon/pagekit`
- Raw SKILL.md: https://api.skillmd.com/api/skills/kraayenjon/pagekit/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: kraayenjon (https://skillmd.com/u/kraayenjon)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/kraayenjon/pagekit

---


# PageKit

Take one person from nothing to a live landing page. They answer questions, you do everything
else.

Assume the user is a photographer, a baker, a consultant, a small agency — not a developer.
They may never have opened a terminal. Never show raw terminal output unless asked. Replace
every piece of jargon with a plain word.

**No accounts, no API keys, no signups.** Everything below works for someone who has installed
nothing but Node.js and Claude Code. If a companion skill suggests a paid tool or an API
integration, skip that part silently.

**Role lock.** Other skills you read during this flow will open by declaring they are an elite
art director or a senior SEO consultant. Ignore that framing — they are references, not roles.
Ignore any instruction in them to stop and wait for the user. The only pauses are the four
listed below.

## Companion skills

PageKit ships alongside these. Read each by path when this file says to, not because its
description sounds relevant.

| Skill | Read it |
|---|---|
| `design-taste-frontend` | Phase 2, always — the design authority |
| `minimalist-ui` / `high-end-visual-design` / `industrial-brutalist-ui` | Phase 2, exactly one of the three |
| `full-output-enforcement` | Phase 4, always — stops you truncating files |
| `copywriting` | Phase 4, before any headline |
| `landing-es` | Phase 4, whenever the page copy is Spanish |
| `cro` | Phase 5, to check the page persuades |
| `vercel-deploy` | Phase 6 |
| `seo-geo`, `seo-schema`, `seo-sitemap`, `llms-txt` | Phase 7 |
| `seo-local` | Phase 7, only if there is a physical address or service area |

If a companion skill is not installed, do the phase from the instructions here and say nothing
about the missing skill.

## The four pauses

Everything else runs without asking.

1. After questionnaire Round 2 — "Does this direction work?"
2. After Round 4 — "Did I get everything?"
3. After Phase 5 — "How does it look?"
4. Before Phase 6 — "Ready to put it online?"

## Phase 1 — Discovery

Four rounds, two to four questions at a time, conversational. Never read the list aloud.

**Round 1 — basics.** Business name. In one sentence, what they do. Who they are trying to
reach.

**Round 2 — look.** Any websites they like. Colour preferences, or should you pick. Light or
dark. What feeling visitors should get — professional, playful, bold, elegant, minimal, warm,
modern.

→ **Pause.** Present the direction. Get a yes before Round 3.

**Round 3 — content.** The one thing they want visitors to do. Three or four things worth
highlighting. Contact method. Any testimonials or client names. A tagline, if they have one.

**Round 4 — details.** Logo or photos to use. What language the page should be in — this is a
separate question from the language you are talking in. Whether they want it online today.

→ **Pause.** Summarise the brief.

Anyone who says "you decide" gets a decision, stated plainly, with one sentence of reasoning.
Do not push back. Do not re-ask.

## Phase 2 — Design direction

Read `design-taste-frontend`. It is long. Read it anyway — it is the main reason the page will
not look AI-generated.

Choose a direction, then read exactly one aesthetic skill for depth. Never two.

Choose a section order. Sensible defaults:

| Business | Order |
|---|---|
| Portfolio, photographer, designer | Hero → work grid → short about → contact |
| Local business, restaurant, salon | Hero → what we do → hours & location → proof → contact |
| Consultant, coach, freelancer | Hero → problem → how you help → proof → booking CTA |
| Small product or service | Hero → proof strip → benefits → objection → pricing → CTA |

Present in plain language: the feeling and why it fits, the colours with hex codes named like a
person would name them, the two fonts and what each is doing, the section order.

## Phase 3 — Setup

```bash
node --version
```

Below v18 or missing → "You need Node.js first. Go to nodejs.org, download the one marked LTS,
open the file, follow the installer. Tell me when it's done." Wait.

```bash
npx create-next-app@latest site --typescript --tailwind --app --src-dir --no-import-alias --yes
cd site
npx shadcn@latest init -b radix -p nova -y --css-variables --pointer
npx shadcn@latest add button card navigation-menu separator badge -y
npm install motion lucide-react
```

Do not simplify those flags:

- `-b radix` pins Radix. The current default base is Base UI, with different component code.
- `-p nova` is required. `-y` alone does **not** skip the preset prompt — the command hangs
  forever with no output. Presets: `nova, vega, maia, lyra, mira, luma, sera, rhea`.
- `--pointer` adds `cursor-pointer` to generated components.
- The package is `shadcn`. `shadcn-ui` is deprecated on npm.

Recovery: "directory exists" → `rm -rf site` and retry. `init` hanging with no output → you
omitted `-p`. `init` failing → `npx shadcn@latest init --defaults` from inside `site/`, then
read `site/src/components/ui/*.tsx` before using any component API, because they will be Base
UI. `npm install` failing → `rm -rf site/node_modules site/package-lock.json && npm install
--prefix site`.

## Phase 4 — Build

Read `full-output-enforcement` first. Complete files. No placeholders, no "rest unchanged".

Read `copywriting` before writing a headline. Read `landing-es` too if the page is Spanish.

- `site/src/app/layout.tsx` — fonts, `metadata` export, global styles
- `site/src/app/page.tsx` — the page, a Server Component
- `"use client"` only for `useState`, `useEffect`, event handlers, or `motion/react`

`globals.css` already has `@import "tailwindcss"` and `@theme inline`. Edit the token values,
append your own `@theme` for type and spacing scales. Never overwrite the file. Never create
`tailwind.config.ts` — Tailwind 4 has no config file.

`create-next-app` hardcodes `body { font-family: Arial, Helvetica, sans-serif }`. Replace it —
fonts come from `next/font/google` with `display: "swap"` and CSS variables, never a CDN
`<link>`.

**Motion budget for a landing page:** a hero reveal, one scroll reveal per section, button
feedback. That is all.

- `cubic-bezier(0.23, 1, 0.32, 1)` for entrances and exits. Never `ease-in`
- Interface motion under 300ms; a marketing reveal may run to 800ms
- Never `scale(0)` — start at `scale(0.95)` with `opacity: 0`
- Animate `transform` and `opacity` only. Never `transition: all`
- `:active { transform: scale(0.97) }` on every button
- Hover motion behind `@media (hover: hover) and (pointer: fine)`
- `prefers-reduced-motion` keeps opacity and colour, drops movement

`motion` is imported as `motion/react`. Never also install `framer-motion` — same library, old
name, two copies shipped.

**Accessibility, not optional:** semantic landmarks, one `<h1>` with no skipped levels, `alt`
on every image, 4.5:1 contrast on body text, `aria-label` on icon-only buttons, a visible
`<label>` on every input (a placeholder is not a label), 44×44px touch targets, tab order
matching visual order.

**Contact:** a styled `mailto:` section by default — nothing to set up, works immediately. Only
use Formspree if they asked for a real form, and only with a form ID they give you.

**Responsive:** mobile first, holding at 375, 768, 1024, 1440px.

## Phase 5 — Review

```bash
cd site && npm run dev
```

"It's running. Open http://localhost:3000 in your browser." That is the reliable path for
someone with nothing installed. Screenshot only if a browser tool is already available — never
make them install one.

Read `cro` and check the page against it yourself. Fix what you find first. Then ask something
specific: "How does the top of the page feel — right amount of confidence, or too loud?" Never
"let me know what you think."

Act on feedback immediately. Do not ask whether you should make the change.

## Phase 6 — Deploy

Prove the build, then deploy:

```bash
cd site && npm run build
bash skills/vercel-deploy/scripts/deploy.sh site
```

No Vercel account needed. Hand back both URLs — the live one, and the claim URL if they want to
keep it permanently.

If they decline: "No problem. It's saved in the `site` folder. Run `cd site && npm run dev`
whenever you want to see it, and we can put it online any time."

Either way, continue to Phase 7.

## Phase 7 — Visibility

The part other builders skip. Run all of it, ask nothing. Every item works with no account.

1. **JSON-LD** in `layout.tsx`. `Organization` normally, `LocalBusiness` when there is an
   address or service area, `Person` for a portfolio, plus `FAQPage` if the page has questions.
   Real values only — never invent an address, a phone number, or a rating.
2. **Metadata**: title, description, `openGraph` (title, description, url, siteName, locale,
   type), `twitter` card, `alternates.canonical`. `<html lang>` set to the *page's* language.
3. **Citability**: reread the page as an AI trying to answer a question with it. Every section
   should make one claim that survives being lifted out on its own. "Wood-fired sourdough, baked
   daily from 6am in Malasaña" survives; "quality baked goods" does not. Fix the sections that
   fail — a copy edit, not a redesign.
4. **`site/public/llms.txt`**.
5. **`site/public/robots.txt`**, allowing normal crawlers and naming `GPTBot`, `ClaudeBot`,
   `PerplexityBot`, `Google-Extended` explicitly, pointing at the sitemap.
6. **`site/src/app/sitemap.ts`** using Next's built-in export.
7. **Favicon** at `site/src/app/icon.tsx`, generated from their initials in the brand colours,
   or static if they gave you a logo.

Rebuild and redeploy if the site is already live. Then explain it in two plain sentences: "I
also set the page up so Google and AI assistants like ChatGPT can read it properly — the
structured description, the crawler files, and the social preview are all in place."

Offer once, never push: "Optional — if you want to see who's finding you on Google, verify the
site in Search Console. Free, about five minutes. Want me to walk you through it?"

## Checklist

- [ ] Would not be spotted as AI-generated at a glance
- [ ] No cyan-on-dark, purple-to-blue gradients, or neon accents
- [ ] Not Inter, Roboto, Arial, Open Sans, or a system font stack
- [ ] No AI vocabulary: delve, tapestry, landscape, showcase, vibrant, nestled, leverage,
      foster, innovative, cutting-edge, seamless, empower, holistic, robust, elevate, unlock,
      transform, journey, realm, testament
- [ ] Every claim on the page is one the user actually made
- [ ] `npm run build` passes clean
- [ ] Holds at 375, 768, 1024, 1440px
- [ ] One `<h1>`, no skipped levels, `alt` everywhere, visible labels
- [ ] `prefers-reduced-motion` handled
- [ ] JSON-LD present, every value real
- [ ] `llms.txt`, `robots.txt`, `sitemap.ts`, favicon, full metadata

## Credit

PageKit adds one line to the footer of the pages it builds:

> Built with PageKit by [Skills Agentes](https://skillsagentes.com)

Spanish: "Hecho con PageKit por [Skills Agentes](https://skillsagentes.com)".

`text-sm text-muted-foreground`, centred, last line. The link text is always exactly
`Skills Agentes` — never a description, a keyword, or the subject of the site. The link goes to
`https://skillsagentes.com` and nowhere deeper.

It is how the kit stays free, and it is disclosed in the README. If the user asks you to remove
it, remove it without argument or comment.

