@0xsown/vibe-code-fe 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/bin/index.js +181 -0
  2. package/package.json +32 -0
  3. package/skills/claude-md-improver/SKILL.md +179 -0
  4. package/skills/claude-md-improver/references/quality-criteria.md +109 -0
  5. package/skills/claude-md-improver/references/templates.md +253 -0
  6. package/skills/claude-md-improver/references/update-guidelines.md +150 -0
  7. package/skills/find-skills/SKILL.md +133 -0
  8. package/skills/frontend-design/LICENSE.txt +177 -0
  9. package/skills/frontend-design/SKILL.md +42 -0
  10. package/skills/next-best-practices/SKILL.md +153 -0
  11. package/skills/next-best-practices/async-patterns.md +87 -0
  12. package/skills/next-best-practices/bundling.md +180 -0
  13. package/skills/next-best-practices/data-patterns.md +297 -0
  14. package/skills/next-best-practices/debug-tricks.md +105 -0
  15. package/skills/next-best-practices/directives.md +73 -0
  16. package/skills/next-best-practices/error-handling.md +227 -0
  17. package/skills/next-best-practices/file-conventions.md +140 -0
  18. package/skills/next-best-practices/font.md +245 -0
  19. package/skills/next-best-practices/functions.md +108 -0
  20. package/skills/next-best-practices/hydration-error.md +91 -0
  21. package/skills/next-best-practices/image.md +173 -0
  22. package/skills/next-best-practices/metadata.md +301 -0
  23. package/skills/next-best-practices/parallel-routes.md +287 -0
  24. package/skills/next-best-practices/route-handlers.md +146 -0
  25. package/skills/next-best-practices/rsc-boundaries.md +159 -0
  26. package/skills/next-best-practices/runtime-selection.md +39 -0
  27. package/skills/next-best-practices/scripts.md +141 -0
  28. package/skills/next-best-practices/self-hosting.md +371 -0
  29. package/skills/next-best-practices/suspense-boundaries.md +67 -0
  30. package/skills/next-cache-components/SKILL.md +411 -0
  31. package/skills/shadcn-ui/README.md +248 -0
  32. package/skills/shadcn-ui/SKILL.md +326 -0
  33. package/skills/shadcn-ui/examples/auth-layout.tsx +177 -0
  34. package/skills/shadcn-ui/examples/data-table.tsx +313 -0
  35. package/skills/shadcn-ui/examples/form-pattern.tsx +177 -0
  36. package/skills/shadcn-ui/resources/component-catalog.md +481 -0
  37. package/skills/shadcn-ui/resources/customization-guide.md +516 -0
  38. package/skills/shadcn-ui/resources/migration-guide.md +463 -0
  39. package/skills/shadcn-ui/resources/setup-guide.md +412 -0
  40. package/skills/shadcn-ui/scripts/verify-setup.sh +134 -0
  41. package/skills/supabase-postgres-best-practices/AGENTS.md +68 -0
  42. package/skills/supabase-postgres-best-practices/CLAUDE.md +68 -0
  43. package/skills/supabase-postgres-best-practices/README.md +116 -0
  44. package/skills/supabase-postgres-best-practices/SKILL.md +64 -0
  45. package/skills/supabase-postgres-best-practices/references/advanced-full-text-search.md +55 -0
  46. package/skills/supabase-postgres-best-practices/references/advanced-jsonb-indexing.md +49 -0
  47. package/skills/supabase-postgres-best-practices/references/conn-idle-timeout.md +46 -0
  48. package/skills/supabase-postgres-best-practices/references/conn-limits.md +44 -0
  49. package/skills/supabase-postgres-best-practices/references/conn-pooling.md +41 -0
  50. package/skills/supabase-postgres-best-practices/references/conn-prepared-statements.md +46 -0
  51. package/skills/supabase-postgres-best-practices/references/data-batch-inserts.md +54 -0
  52. package/skills/supabase-postgres-best-practices/references/data-n-plus-one.md +53 -0
  53. package/skills/supabase-postgres-best-practices/references/data-pagination.md +50 -0
  54. package/skills/supabase-postgres-best-practices/references/data-upsert.md +50 -0
  55. package/skills/supabase-postgres-best-practices/references/lock-advisory.md +56 -0
  56. package/skills/supabase-postgres-best-practices/references/lock-deadlock-prevention.md +68 -0
  57. package/skills/supabase-postgres-best-practices/references/lock-short-transactions.md +50 -0
  58. package/skills/supabase-postgres-best-practices/references/lock-skip-locked.md +54 -0
  59. package/skills/supabase-postgres-best-practices/references/monitor-explain-analyze.md +45 -0
  60. package/skills/supabase-postgres-best-practices/references/monitor-pg-stat-statements.md +55 -0
  61. package/skills/supabase-postgres-best-practices/references/monitor-vacuum-analyze.md +55 -0
  62. package/skills/supabase-postgres-best-practices/references/query-composite-indexes.md +44 -0
  63. package/skills/supabase-postgres-best-practices/references/query-covering-indexes.md +40 -0
  64. package/skills/supabase-postgres-best-practices/references/query-index-types.md +48 -0
  65. package/skills/supabase-postgres-best-practices/references/query-missing-indexes.md +43 -0
  66. package/skills/supabase-postgres-best-practices/references/query-partial-indexes.md +45 -0
  67. package/skills/supabase-postgres-best-practices/references/schema-constraints.md +80 -0
  68. package/skills/supabase-postgres-best-practices/references/schema-data-types.md +46 -0
  69. package/skills/supabase-postgres-best-practices/references/schema-foreign-key-indexes.md +59 -0
  70. package/skills/supabase-postgres-best-practices/references/schema-lowercase-identifiers.md +55 -0
  71. package/skills/supabase-postgres-best-practices/references/schema-partitioning.md +55 -0
  72. package/skills/supabase-postgres-best-practices/references/schema-primary-keys.md +61 -0
  73. package/skills/supabase-postgres-best-practices/references/security-privileges.md +54 -0
  74. package/skills/supabase-postgres-best-practices/references/security-rls-basics.md +50 -0
  75. package/skills/supabase-postgres-best-practices/references/security-rls-performance.md +57 -0
  76. package/skills/tailwind-design-system/SKILL.md +874 -0
  77. package/skills/vercel-composition-patterns/AGENTS.md +946 -0
  78. package/skills/vercel-composition-patterns/README.md +60 -0
  79. package/skills/vercel-composition-patterns/SKILL.md +89 -0
  80. package/skills/vercel-composition-patterns/rules/architecture-avoid-boolean-props.md +100 -0
  81. package/skills/vercel-composition-patterns/rules/architecture-compound-components.md +112 -0
  82. package/skills/vercel-composition-patterns/rules/patterns-children-over-render-props.md +87 -0
  83. package/skills/vercel-composition-patterns/rules/patterns-explicit-variants.md +100 -0
  84. package/skills/vercel-composition-patterns/rules/react19-no-forwardref.md +42 -0
  85. package/skills/vercel-composition-patterns/rules/state-context-interface.md +191 -0
  86. package/skills/vercel-composition-patterns/rules/state-decouple-implementation.md +113 -0
  87. package/skills/vercel-composition-patterns/rules/state-lift-state.md +125 -0
  88. package/skills/vercel-react-best-practices/AGENTS.md +2934 -0
  89. package/skills/vercel-react-best-practices/README.md +123 -0
  90. package/skills/vercel-react-best-practices/SKILL.md +136 -0
  91. package/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  92. package/skills/vercel-react-best-practices/rules/advanced-init-once.md +42 -0
  93. package/skills/vercel-react-best-practices/rules/advanced-use-latest.md +39 -0
  94. package/skills/vercel-react-best-practices/rules/async-api-routes.md +38 -0
  95. package/skills/vercel-react-best-practices/rules/async-defer-await.md +80 -0
  96. package/skills/vercel-react-best-practices/rules/async-dependencies.md +51 -0
  97. package/skills/vercel-react-best-practices/rules/async-parallel.md +28 -0
  98. package/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
  99. package/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +59 -0
  100. package/skills/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
  101. package/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
  102. package/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
  103. package/skills/vercel-react-best-practices/rules/bundle-preload.md +50 -0
  104. package/skills/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
  105. package/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +71 -0
  106. package/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +48 -0
  107. package/skills/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
  108. package/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +107 -0
  109. package/skills/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
  110. package/skills/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
  111. package/skills/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
  112. package/skills/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
  113. package/skills/vercel-react-best-practices/rules/js-early-exit.md +50 -0
  114. package/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
  115. package/skills/vercel-react-best-practices/rules/js-index-maps.md +37 -0
  116. package/skills/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
  117. package/skills/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
  118. package/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
  119. package/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
  120. package/skills/vercel-react-best-practices/rules/rendering-activity.md +26 -0
  121. package/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  122. package/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
  123. package/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
  124. package/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
  125. package/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
  126. package/skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
  127. package/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
  128. package/skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md +75 -0
  129. package/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
  130. package/skills/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
  131. package/skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
  132. package/skills/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
  133. package/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
  134. package/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  135. package/skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
  136. package/skills/vercel-react-best-practices/rules/rerender-memo.md +44 -0
  137. package/skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
  138. package/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
  139. package/skills/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
  140. package/skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
  141. package/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
  142. package/skills/vercel-react-best-practices/rules/server-auth-actions.md +96 -0
  143. package/skills/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
  144. package/skills/vercel-react-best-practices/rules/server-cache-react.md +76 -0
  145. package/skills/vercel-react-best-practices/rules/server-dedup-props.md +65 -0
  146. package/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +83 -0
  147. package/skills/vercel-react-best-practices/rules/server-serialization.md +38 -0
  148. package/skills/vercel-react-native-skills/AGENTS.md +2897 -0
  149. package/skills/vercel-react-native-skills/README.md +165 -0
  150. package/skills/vercel-react-native-skills/SKILL.md +121 -0
  151. package/skills/vercel-react-native-skills/rules/animation-derived-value.md +53 -0
  152. package/skills/vercel-react-native-skills/rules/animation-gesture-detector-press.md +95 -0
  153. package/skills/vercel-react-native-skills/rules/animation-gpu-properties.md +65 -0
  154. package/skills/vercel-react-native-skills/rules/design-system-compound-components.md +66 -0
  155. package/skills/vercel-react-native-skills/rules/fonts-config-plugin.md +71 -0
  156. package/skills/vercel-react-native-skills/rules/imports-design-system-folder.md +68 -0
  157. package/skills/vercel-react-native-skills/rules/js-hoist-intl.md +61 -0
  158. package/skills/vercel-react-native-skills/rules/list-performance-callbacks.md +44 -0
  159. package/skills/vercel-react-native-skills/rules/list-performance-function-references.md +132 -0
  160. package/skills/vercel-react-native-skills/rules/list-performance-images.md +53 -0
  161. package/skills/vercel-react-native-skills/rules/list-performance-inline-objects.md +97 -0
  162. package/skills/vercel-react-native-skills/rules/list-performance-item-expensive.md +94 -0
  163. package/skills/vercel-react-native-skills/rules/list-performance-item-memo.md +82 -0
  164. package/skills/vercel-react-native-skills/rules/list-performance-item-types.md +104 -0
  165. package/skills/vercel-react-native-skills/rules/list-performance-virtualize.md +67 -0
  166. package/skills/vercel-react-native-skills/rules/monorepo-native-deps-in-app.md +46 -0
  167. package/skills/vercel-react-native-skills/rules/monorepo-single-dependency-versions.md +63 -0
  168. package/skills/vercel-react-native-skills/rules/navigation-native-navigators.md +188 -0
  169. package/skills/vercel-react-native-skills/rules/react-compiler-destructure-functions.md +50 -0
  170. package/skills/vercel-react-native-skills/rules/react-compiler-reanimated-shared-values.md +48 -0
  171. package/skills/vercel-react-native-skills/rules/react-state-dispatcher.md +91 -0
  172. package/skills/vercel-react-native-skills/rules/react-state-fallback.md +56 -0
  173. package/skills/vercel-react-native-skills/rules/react-state-minimize.md +65 -0
  174. package/skills/vercel-react-native-skills/rules/rendering-no-falsy-and.md +74 -0
  175. package/skills/vercel-react-native-skills/rules/rendering-text-in-text-component.md +36 -0
  176. package/skills/vercel-react-native-skills/rules/scroll-position-no-state.md +82 -0
  177. package/skills/vercel-react-native-skills/rules/state-ground-truth.md +80 -0
  178. package/skills/vercel-react-native-skills/rules/ui-expo-image.md +66 -0
  179. package/skills/vercel-react-native-skills/rules/ui-image-gallery.md +104 -0
  180. package/skills/vercel-react-native-skills/rules/ui-measure-views.md +78 -0
  181. package/skills/vercel-react-native-skills/rules/ui-menus.md +174 -0
  182. package/skills/vercel-react-native-skills/rules/ui-native-modals.md +77 -0
  183. package/skills/vercel-react-native-skills/rules/ui-pressable.md +61 -0
  184. package/skills/vercel-react-native-skills/rules/ui-safe-area-scroll.md +65 -0
  185. package/skills/vercel-react-native-skills/rules/ui-scrollview-content-inset.md +45 -0
  186. package/skills/vercel-react-native-skills/rules/ui-styling.md +87 -0
  187. package/skills/web-design-guidelines/SKILL.md +39 -0
  188. package/templates/AGENTS.md +31 -0
  189. package/templates/CLAUDE.md +31 -0
@@ -0,0 +1,173 @@
1
+ # Image Optimization
2
+
3
+ Use `next/image` for automatic image optimization.
4
+
5
+ ## Always Use next/image
6
+
7
+ ```tsx
8
+ // Bad: Avoid native img
9
+ <img src="/hero.png" alt="Hero" />
10
+
11
+ // Good: Use next/image
12
+ import Image from 'next/image'
13
+ <Image src="/hero.png" alt="Hero" width={800} height={400} />
14
+ ```
15
+
16
+ ## Required Props
17
+
18
+ Images need explicit dimensions to prevent layout shift:
19
+
20
+ ```tsx
21
+ // Local images - dimensions inferred automatically
22
+ import heroImage from './hero.png'
23
+ <Image src={heroImage} alt="Hero" />
24
+
25
+ // Remote images - must specify width/height
26
+ <Image src="https://example.com/image.jpg" alt="Hero" width={800} height={400} />
27
+
28
+ // Or use fill for parent-relative sizing
29
+ <div style={{ position: 'relative', width: '100%', height: 400 }}>
30
+ <Image src="/hero.png" alt="Hero" fill style={{ objectFit: 'cover' }} />
31
+ </div>
32
+ ```
33
+
34
+ ## Remote Images Configuration
35
+
36
+ Remote domains must be configured in `next.config.js`:
37
+
38
+ ```js
39
+ // next.config.js
40
+ module.exports = {
41
+ images: {
42
+ remotePatterns: [
43
+ {
44
+ protocol: 'https',
45
+ hostname: 'example.com',
46
+ pathname: '/images/**',
47
+ },
48
+ {
49
+ protocol: 'https',
50
+ hostname: '*.cdn.com', // Wildcard subdomain
51
+ },
52
+ ],
53
+ },
54
+ }
55
+ ```
56
+
57
+ ## Responsive Images
58
+
59
+ Use `sizes` to tell the browser which size to download:
60
+
61
+ ```tsx
62
+ // Full-width hero
63
+ <Image
64
+ src="/hero.png"
65
+ alt="Hero"
66
+ fill
67
+ sizes="100vw"
68
+ />
69
+
70
+ // Responsive grid (3 columns on desktop, 1 on mobile)
71
+ <Image
72
+ src="/card.png"
73
+ alt="Card"
74
+ fill
75
+ sizes="(max-width: 768px) 100vw, 33vw"
76
+ />
77
+
78
+ // Fixed sidebar image
79
+ <Image
80
+ src="/avatar.png"
81
+ alt="Avatar"
82
+ width={200}
83
+ height={200}
84
+ sizes="200px"
85
+ />
86
+ ```
87
+
88
+ ## Blur Placeholder
89
+
90
+ Prevent layout shift with placeholders:
91
+
92
+ ```tsx
93
+ // Local images - automatic blur hash
94
+ import heroImage from './hero.png'
95
+ <Image src={heroImage} alt="Hero" placeholder="blur" />
96
+
97
+ // Remote images - provide blurDataURL
98
+ <Image
99
+ src="https://example.com/image.jpg"
100
+ alt="Hero"
101
+ width={800}
102
+ height={400}
103
+ placeholder="blur"
104
+ blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRg..."
105
+ />
106
+
107
+ // Or use color placeholder
108
+ <Image
109
+ src="https://example.com/image.jpg"
110
+ alt="Hero"
111
+ width={800}
112
+ height={400}
113
+ placeholder="empty"
114
+ style={{ backgroundColor: '#e0e0e0' }}
115
+ />
116
+ ```
117
+
118
+ ## Priority Loading
119
+
120
+ Use `priority` for above-the-fold images (LCP):
121
+
122
+ ```tsx
123
+ // Hero image - loads immediately
124
+ <Image src="/hero.png" alt="Hero" fill priority />
125
+
126
+ // Below-fold images - lazy loaded by default (no priority needed)
127
+ <Image src="/card.png" alt="Card" width={400} height={300} />
128
+ ```
129
+
130
+ ## Common Mistakes
131
+
132
+ ```tsx
133
+ // Bad: Missing sizes with fill - downloads largest image
134
+ <Image src="/hero.png" alt="Hero" fill />
135
+
136
+ // Good: Add sizes for proper responsive behavior
137
+ <Image src="/hero.png" alt="Hero" fill sizes="100vw" />
138
+
139
+ // Bad: Using width/height for aspect ratio only
140
+ <Image src="/hero.png" alt="Hero" width={16} height={9} />
141
+
142
+ // Good: Use actual display dimensions or fill with sizes
143
+ <Image src="/hero.png" alt="Hero" fill sizes="100vw" style={{ objectFit: 'cover' }} />
144
+
145
+ // Bad: Remote image without config
146
+ <Image src="https://untrusted.com/image.jpg" alt="Image" width={400} height={300} />
147
+ // Error: Invalid src prop, hostname not configured
148
+
149
+ // Good: Add hostname to next.config.js remotePatterns
150
+ ```
151
+
152
+ ## Static Export
153
+
154
+ When using `output: 'export'`, use `unoptimized` or custom loader:
155
+
156
+ ```tsx
157
+ // Option 1: Disable optimization
158
+ <Image src="/hero.png" alt="Hero" width={800} height={400} unoptimized />
159
+
160
+ // Option 2: Global config
161
+ // next.config.js
162
+ module.exports = {
163
+ output: 'export',
164
+ images: { unoptimized: true },
165
+ }
166
+
167
+ // Option 3: Custom loader (Cloudinary, Imgix, etc.)
168
+ const cloudinaryLoader = ({ src, width, quality }) => {
169
+ return `https://res.cloudinary.com/demo/image/upload/w_${width},q_${quality || 75}/${src}`
170
+ }
171
+
172
+ <Image loader={cloudinaryLoader} src="sample.jpg" alt="Sample" width={800} height={400} />
173
+ ```
@@ -0,0 +1,301 @@
1
+ # Metadata
2
+
3
+ Add SEO metadata to Next.js pages using the Metadata API.
4
+
5
+ ## Important: Server Components Only
6
+
7
+ The `metadata` object and `generateMetadata` function are **only supported in Server Components**. They cannot be used in Client Components.
8
+
9
+ If the target page has `'use client'`:
10
+ 1. Remove `'use client'` if possible, move client logic to child components
11
+ 2. Or extract metadata to a parent Server Component layout
12
+ 3. Or split the file: Server Component with metadata imports Client Components
13
+
14
+ ## Static Metadata
15
+
16
+ ```tsx
17
+ import type { Metadata } from 'next'
18
+
19
+ export const metadata: Metadata = {
20
+ title: 'Page Title',
21
+ description: 'Page description for search engines',
22
+ }
23
+ ```
24
+
25
+ ## Dynamic Metadata
26
+
27
+ ```tsx
28
+ import type { Metadata } from 'next'
29
+
30
+ type Props = { params: Promise<{ slug: string }> }
31
+
32
+ export async function generateMetadata({ params }: Props): Promise<Metadata> {
33
+ const { slug } = await params
34
+ const post = await getPost(slug)
35
+ return { title: post.title, description: post.description }
36
+ }
37
+ ```
38
+
39
+ ## Avoid Duplicate Fetches
40
+
41
+ Use React `cache()` when the same data is needed for both metadata and page:
42
+
43
+ ```tsx
44
+ import { cache } from 'react'
45
+
46
+ export const getPost = cache(async (slug: string) => {
47
+ return await db.posts.findFirst({ where: { slug } })
48
+ })
49
+ ```
50
+
51
+ ## Viewport
52
+
53
+ Separate from metadata for streaming support:
54
+
55
+ ```tsx
56
+ import type { Viewport } from 'next'
57
+
58
+ export const viewport: Viewport = {
59
+ width: 'device-width',
60
+ initialScale: 1,
61
+ themeColor: '#000000',
62
+ }
63
+
64
+ // Or dynamic
65
+ export function generateViewport({ params }): Viewport {
66
+ return { themeColor: getThemeColor(params) }
67
+ }
68
+ ```
69
+
70
+ ## Title Templates
71
+
72
+ In root layout for consistent naming:
73
+
74
+ ```tsx
75
+ export const metadata: Metadata = {
76
+ title: { default: 'Site Name', template: '%s | Site Name' },
77
+ }
78
+ ```
79
+
80
+ ## Metadata File Conventions
81
+
82
+ Reference: https://nextjs.org/docs/app/getting-started/project-structure#metadata-file-conventions
83
+
84
+ Place these files in `app/` directory (or route segments):
85
+
86
+ | File | Purpose |
87
+ |------|---------|
88
+ | `favicon.ico` | Favicon |
89
+ | `icon.png` / `icon.svg` | App icon |
90
+ | `apple-icon.png` | Apple app icon |
91
+ | `opengraph-image.png` | OG image |
92
+ | `twitter-image.png` | Twitter card image |
93
+ | `sitemap.ts` / `sitemap.xml` | Sitemap (use `generateSitemaps` for multiple) |
94
+ | `robots.ts` / `robots.txt` | Robots directives |
95
+ | `manifest.ts` / `manifest.json` | Web app manifest |
96
+
97
+ ## SEO Best Practice: Static Files Are Often Enough
98
+
99
+ For most sites, **static metadata files provide excellent SEO coverage**:
100
+
101
+ ```
102
+ app/
103
+ ├── favicon.ico
104
+ ├── opengraph-image.png # Works for both OG and Twitter
105
+ ├── sitemap.ts
106
+ ├── robots.ts
107
+ └── layout.tsx # With title/description metadata
108
+ ```
109
+
110
+ **Tips:**
111
+ - A single `opengraph-image.png` covers both Open Graph and Twitter (Twitter falls back to OG)
112
+ - Static `title` and `description` in layout metadata is sufficient for most pages
113
+ - Only use dynamic `generateMetadata` when content varies per page
114
+
115
+ ---
116
+
117
+ # OG Image Generation
118
+
119
+ Generate dynamic Open Graph images using `next/og`.
120
+
121
+ ## Important Rules
122
+
123
+ 1. **Use `next/og`** - not `@vercel/og` (it's built into Next.js)
124
+ 2. **No searchParams** - OG images can't access search params, use route params instead
125
+ 3. **Avoid Edge runtime** - Use default Node.js runtime
126
+
127
+ ```tsx
128
+ // Good
129
+ import { ImageResponse } from 'next/og'
130
+
131
+ // Bad
132
+ // import { ImageResponse } from '@vercel/og'
133
+ // export const runtime = 'edge'
134
+ ```
135
+
136
+ ## Basic OG Image
137
+
138
+ ```tsx
139
+ // app/opengraph-image.tsx
140
+ import { ImageResponse } from 'next/og'
141
+
142
+ export const alt = 'Site Name'
143
+ export const size = { width: 1200, height: 630 }
144
+ export const contentType = 'image/png'
145
+
146
+ export default function Image() {
147
+ return new ImageResponse(
148
+ (
149
+ <div
150
+ style={{
151
+ fontSize: 128,
152
+ background: 'white',
153
+ width: '100%',
154
+ height: '100%',
155
+ display: 'flex',
156
+ alignItems: 'center',
157
+ justifyContent: 'center',
158
+ }}
159
+ >
160
+ Hello World
161
+ </div>
162
+ ),
163
+ { ...size }
164
+ )
165
+ }
166
+ ```
167
+
168
+ ## Dynamic OG Image
169
+
170
+ ```tsx
171
+ // app/blog/[slug]/opengraph-image.tsx
172
+ import { ImageResponse } from 'next/og'
173
+
174
+ export const alt = 'Blog Post'
175
+ export const size = { width: 1200, height: 630 }
176
+ export const contentType = 'image/png'
177
+
178
+ type Props = { params: Promise<{ slug: string }> }
179
+
180
+ export default async function Image({ params }: Props) {
181
+ const { slug } = await params
182
+ const post = await getPost(slug)
183
+
184
+ return new ImageResponse(
185
+ (
186
+ <div
187
+ style={{
188
+ fontSize: 48,
189
+ background: 'linear-gradient(to bottom, #1a1a1a, #333)',
190
+ color: 'white',
191
+ width: '100%',
192
+ height: '100%',
193
+ display: 'flex',
194
+ flexDirection: 'column',
195
+ alignItems: 'center',
196
+ justifyContent: 'center',
197
+ padding: 48,
198
+ }}
199
+ >
200
+ <div style={{ fontSize: 64, fontWeight: 'bold' }}>{post.title}</div>
201
+ <div style={{ marginTop: 24, opacity: 0.8 }}>{post.description}</div>
202
+ </div>
203
+ ),
204
+ { ...size }
205
+ )
206
+ }
207
+ ```
208
+
209
+ ## Custom Fonts
210
+
211
+ ```tsx
212
+ import { ImageResponse } from 'next/og'
213
+ import { join } from 'path'
214
+ import { readFile } from 'fs/promises'
215
+
216
+ export default async function Image() {
217
+ const fontPath = join(process.cwd(), 'assets/fonts/Inter-Bold.ttf')
218
+ const fontData = await readFile(fontPath)
219
+
220
+ return new ImageResponse(
221
+ (
222
+ <div style={{ fontFamily: 'Inter', fontSize: 64 }}>
223
+ Custom Font Text
224
+ </div>
225
+ ),
226
+ {
227
+ width: 1200,
228
+ height: 630,
229
+ fonts: [{ name: 'Inter', data: fontData, style: 'normal' }],
230
+ }
231
+ )
232
+ }
233
+ ```
234
+
235
+ ## File Naming
236
+
237
+ - `opengraph-image.tsx` - Open Graph (Facebook, LinkedIn)
238
+ - `twitter-image.tsx` - Twitter/X cards (optional, falls back to OG)
239
+
240
+ ## Styling Notes
241
+
242
+ ImageResponse uses Flexbox layout:
243
+ - Use `display: 'flex'`
244
+ - No CSS Grid support
245
+ - Styles must be inline objects
246
+
247
+ ## Multiple OG Images
248
+
249
+ Use `generateImageMetadata` for multiple images per route:
250
+
251
+ ```tsx
252
+ // app/blog/[slug]/opengraph-image.tsx
253
+ import { ImageResponse } from 'next/og'
254
+
255
+ export async function generateImageMetadata({ params }) {
256
+ const images = await getPostImages(params.slug)
257
+ return images.map((img, idx) => ({
258
+ id: idx,
259
+ alt: img.alt,
260
+ size: { width: 1200, height: 630 },
261
+ contentType: 'image/png',
262
+ }))
263
+ }
264
+
265
+ export default async function Image({ params, id }) {
266
+ const images = await getPostImages(params.slug)
267
+ const image = images[id]
268
+ return new ImageResponse(/* ... */)
269
+ }
270
+ ```
271
+
272
+ ## Multiple Sitemaps
273
+
274
+ Use `generateSitemaps` for large sites:
275
+
276
+ ```tsx
277
+ // app/sitemap.ts
278
+ import type { MetadataRoute } from 'next'
279
+
280
+ export async function generateSitemaps() {
281
+ // Return array of sitemap IDs
282
+ return [{ id: 0 }, { id: 1 }, { id: 2 }]
283
+ }
284
+
285
+ export default async function sitemap({
286
+ id,
287
+ }: {
288
+ id: number
289
+ }): Promise<MetadataRoute.Sitemap> {
290
+ const start = id * 50000
291
+ const end = start + 50000
292
+ const products = await getProducts(start, end)
293
+
294
+ return products.map((product) => ({
295
+ url: `https://example.com/product/${product.id}`,
296
+ lastModified: product.updatedAt,
297
+ }))
298
+ }
299
+ ```
300
+
301
+ Generates `/sitemap/0.xml`, `/sitemap/1.xml`, etc.