Skip to content

Best Practices

AI Web Launcher ships with a rule pack in ai_rules/rules/. This page condenses the most important rules so you (and your AI assistant) keep the codebase clean. The full, enforceable versions live in ai_rules/rules/*.md.

Next.js 15

  • Async dynamic APIs. params, searchParams, headers(), and cookies() return Promises. Always await them in Server Components and generateMetadata.
  • Server Components by default. Add "use client" only when you need state, effects, or browser APIs. Push interactivity to small leaf components.
  • Env-gate every integration. Never assume a key exists. Guard client init so a missing variable disables the feature instead of crashing the build.
page.tsx
export default async function Page(props: {
  params: Promise<{ slug: string }>;
}) {
  const { slug } = await props.params;
  // ...
}

SEO

  • getSEOTags() on every page. Each app/*/page.tsx exports metadata via the helper in @/libs/seo, with a canonicalUrlRelative.
  • Structured data. Use renderStructuredData() for JSON-LD (Organization, WebSite, SoftwareApplication).
  • Sitemap. next-sitemap runs on postbuild. Keep next-sitemap.config.js pointed at your production domain.
page.tsx
export const metadata = getSEOTags({
  title: "Page Title — Your Brand",
  description: "120–160 chars including the primary keyword.",
  canonicalUrlRelative: "/page-path",
});

Design

  • Every animation has a job. Highlight, guide flow, give feedback, or showcase content. No decoration on decoration.
  • Honor prefers-reduced-motion. CSS animations are covered globally in globals.css; gate JS/canvas motion with the useReducedMotion() hook.
  • Centralize tokens. Colors, spacing, and easing live in the @theme block in app/globals.css. Don't hardcode hex values in components.

Performance budget

  • Animate only transform, opacity, clip-path, filter — they are GPU-composited. Avoid animating width, height, top/left, box-shadow, or background-position.
  • Accordions: animate grid-template-rows: 0fr → 1fr, never max-height.
  • Avoid transition-all. Use explicit lists like transition-[transform,opacity].
  • Lazy-load heavy client libs with next/dynamic. Add prefetch={false} to <Link>s pointing at heavy routes from the homepage.
  • Declare browserslist in package.json to drop legacy polyfills, and run ANALYZE=true pnpm build before merging perf-sensitive changes.

TypeScript

  • No any. Prefer Record<string, unknown> or a real type. Use optional chaining on typed globals (window.gtag?.()).
  • interface for object shapes, type for unions.
  • Import types separately: import type { User } from "@supabase/supabase-js";
Let the rules drive the AI
Point Claude Code at ai_rules/rules/ and CLAUDE.md at the start of a session. The rules are written as enforceable instructions, not suggestions.