create-page

Scaffold a new page in apps/web/src/app following the project's established pattern. Use when creating any new page or route under the web app.

Best use case

create-page is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Scaffold a new page in apps/web/src/app following the project's established pattern. Use when creating any new page or route under the web app.

Teams using create-page should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/create-page/SKILL.md --create-dirs "https://raw.githubusercontent.com/solana-foundation/solana-com/main/apps/web/openspec/skills/create-page/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/create-page/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How create-page Compares

Feature / Agentcreate-pageStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Scaffold a new page in apps/web/src/app following the project's established pattern. Use when creating any new page or route under the web app.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Create Page

Scaffold a new page in `apps/web/src/app/` following the project's established
pattern. All pages are created under the `[locale]` dynamic segment at
`apps/web/src/app/[locale]/`.

## When to Use This Skill

- Any time a new page or route is being created in `apps/web/src/app/`
- Adding a landing page, event page, or any new section to solana.com
- Duplicating a page structure for a new campaign or feature

## Instructions

Create a new page at route: **$ARGUMENTS**

If no route was provided, ask the user for the desired route path (e.g.
`/hackathon`, `/universities/spring-2026`).

### Step 1 — Determine naming conventions

Parse the route to derive:

- **Directory path**: under `apps/web/src/app/[locale]/` (e.g.
  `/universities/spring-2026` → `universities/spring-2026/`)
- **Translation namespace**: dot-separated key (e.g. `universities.spring2026`)
- **Component name**: PascalCase (e.g. `Spring2026Page`)
- **File name**: kebab-case (e.g. `spring-2026.tsx`)

### Step 2 — Ask the user what sections the page needs

Unless already specified, ask what content sections are needed (hero, timeline,
CTA, cards, etc.).

### Step 3 — Create the server component (`page.tsx`)

This is the **required** entry point for every page.

Rules:

- Async server component — no `"use client"`
- All `t()` calls happen here, NOT in client components
- Use `t()` for strings, `t.raw()` with type cast for arrays/objects
- Export `generateMetadata` using `getIndexMetadata` from `@/app/metadata`
- Props type is `{ params: Promise<{ locale: string }> }`
- If the page is simple (no client-only hooks or components), render JSX
  directly in this file
- If a separate client component is needed, pass a single `translations` object
  as its only prop

### Step 4 (optional) — Create a client component (`<page-name>.tsx`)

Only create a separate client component when the page requires client-only
features such as `useState`, `useEffect`, `useRef`, event handlers, browser
APIs, or third-party client-only components.

Rules:

- `"use client"` directive at top
- Named export (not default) matching the import in `page.tsx`
- Define a `*PageProps` interface with a typed `translations` object
- Use existing shared components from `@/components/` where applicable

### Step 5 — Add translation keys

Add English keys to `apps/web/public/locales/en/common.json`:

- Namespace matches the route (e.g. `privacyhack`, `universities`)
- Nested pages use dot-separated keys (e.g. `universities.hackathon.*`)
- Root-level `title` and `description` are used by `generateMetadata`
- Arrays are stored as JSON arrays and accessed via `t.raw()`
- Only edit the `en` locale — other locales are handled by the i18n pipeline

### Step 6 — Verify

Check for TypeScript issues to confirm the page builds without errors.

### Guardrails

- Follow exact patterns from existing pages (`privacyhack/`, `universities/`,
  `universities/hackathon-fall-2025/`)
- Keep the scaffold minimal with placeholder translations — do not invent
  content
- `page.tsx` and translation keys are always required
- A separate client component is only needed when client-only hooks or
  components are used — do not create one unnecessarily

## Examples

### Simple page — server component only (`page.tsx`)

When no client-only features are needed, everything lives in `page.tsx`:

```tsx
import { getTranslations } from "next-intl/server";
import { getIndexMetadata } from "@/app/metadata";

type Props = { params: Promise<{ locale: string }> };

export default async function Page(_props: Props) {
  const t = await getTranslations();

  return (
    <div className="overflow-hidden">
      <h1>{t("pageName.hero.title")}</h1>
      <p>{t("pageName.hero.subtitle")}</p>
    </div>
  );
}

export async function generateMetadata({ params }: Props) {
  const { locale } = await params;
  return await getIndexMetadata({
    titleKey: "pageName.title",
    descriptionKey: "pageName.description",
    path: "/page-name",
    locale,
  });
}
```

### Page with client component — `page.tsx` + `<page-name>.tsx`

When client-only hooks/components are required, split into two files:

**`page.tsx`** (server component — handles i18n):

```tsx
import { PageNamePage } from "./page-name";
import { getTranslations } from "next-intl/server";
import { getIndexMetadata } from "@/app/metadata";

type Props = { params: Promise<{ locale: string }> };

export default async function Page(_props: Props) {
  const t = await getTranslations();

  const translations = {
    heroTitle: t("pageName.hero.title"),
    heroSubtitle: t("pageName.hero.subtitle"),
    // ... all translation keys passed as props
  };

  return <PageNamePage translations={translations} />;
}

export async function generateMetadata({ params }: Props) {
  const { locale } = await params;
  return await getIndexMetadata({
    titleKey: "pageName.title",
    descriptionKey: "pageName.description",
    path: "/page-name",
    locale,
  });
}
```

**`<page-name>.tsx`** (client component — uses hooks/browser APIs):

```tsx
"use client";

import React from "react";

interface PageNamePageProps {
  translations: {
    heroTitle: string;
    heroSubtitle: string;
    // ... typed translation props
  };
}

export function PageNamePage({ translations }: PageNamePageProps) {
  return (
    <div className="overflow-hidden">{/* Sections using translations.* */}</div>
  );
}
```

### Translation keys (`apps/web/public/locales/en/common.json`)

```json
"pageName": {
  "title": "Page Title | Solana",
  "description": "Meta description for SEO",
  "hero": {
    "title": "...",
    "subtitle": "..."
  }
}
```

Related Skills

migrate-page

447
from solana-foundation/solana-com

Migrate a legacy page from apps/web/src/pages/ (Pages Router) to apps/web/src/app/ (App Router). Use when moving any existing page from the pages directory to the app directory.

refresh-agent-context

447
from solana-foundation/solana-com

Audit this Turborepo for stale or missing agent-reference docs, then refresh repo and app-level `AGENTS.md` and related onboarding docs using the bundled workspace inventory script. Use when apps, packages, routes, ports, or shared tooling changed and the repo needs a fresh agent-oriented context pass.

llms-txt-generator

447
from solana-foundation/solana-com

Upgrade llmtxt-generator.py by scanning apps/ for doc structure changes, then regenerate llms.txt and llms-en.txt while only adding missing sections. Use when updating the generator, adding new doc sections, or refreshing LLM text files.

landing-page-generator

31392
from sickn33/antigravity-awesome-skills

Generates high-converting Next.js/React landing pages with Tailwind CSS. Uses PAS, AIDA, and BAB frameworks for optimized copy/components (Heroes, Features, Pricing). Focuses on Core Web Vitals/SEO.

Front-End DevelopmentClaudeCursorGemini

create-pr

31392
from sickn33/antigravity-awesome-skills

Alias for sentry-skills:pr-writer. Use when users explicitly ask for "create-pr" or reference the legacy skill name. Redirects to the canonical PR writing workflow.

Developer ToolsClaude

create-issue-gate

31392
from sickn33/antigravity-awesome-skills

Use when starting a new implementation task and an issue must be created with strict acceptance criteria gating before execution.

Software DevelopmentClaude

create-branch

31392
from sickn33/antigravity-awesome-skills

Create a git branch following Sentry naming conventions. Use when asked to "create a branch", "new branch", "start a branch", "make a branch", "switch to a new branch", or when starting new work on the default branch.

Developer ToolsClaude

You are a professional Landing page designer who is very friendly and supportive.

5
from Harmeet10000/skills

This AI skill transforms your agent into a friendly landing page design mentor. It guides beginners through planning and designing a conceptual blueprint for their landing page or personal portfolio.

Workflow & Productivity

ui-page

31392
from sickn33/antigravity-awesome-skills

Scaffold a new mobile-first page using StyleSeed Toss layout patterns, section rhythm, and existing shell components.

wiki-page-writer

31392
from sickn33/antigravity-awesome-skills

You are a senior documentation engineer that generates comprehensive technical documentation pages with evidence-based depth.

seo-page

31392
from sickn33/antigravity-awesome-skills

Deep single-page SEO analysis covering on-page elements, content quality, technical meta tags, schema, images, and performance. Use when user says "analyze this page", "check page SEO", or provides a single URL for review.

seo-competitor-pages

31392
from sickn33/antigravity-awesome-skills

Generate SEO-optimized competitor comparison and alternatives pages. Covers "X vs Y" layouts, "alternatives to X" pages, feature matrices, schema markup, and conversion optimization. Use when user says "comparison page", "vs page", "alternatives page", "competitor comparison", or "X vs Y".