This is the single source of truth for all AI agents working on this project. Referenced by:
CLAUDE.md,AI_PROMPTS.md, and any future AI tool configs.
Static Next.js 13+ website for a video editing agency (VaaS — Video as a Service).
- No database. No CMS. No auth. All content lives in JSON files under
data/(NOTcontent/). - Images/media are stored in
data/images/(NOTpublic/images/), organized by section. - Auto-deploys to Vercel on push to
mainbranch. - Designed to be fully maintained by the founder using AI tools + plain JSON/HTML files.
- Never add a database, CMS, or backend — all content lives in JSON/HTML files under
data/ - Never hardcode content in components — always import/read from JSON or HTML files under
data/ - Images go in
data/images/— organized by section subfolder - Blog posts are individual
.htmlfiles nested underdata/blogs/YYYY/MM/(organized by publish year and month) - Blog media (cover images, inline images, local video clips) must be organized by year/month under
data/images/blog/posts/YYYY/MM/ - Only set
published: truein headers when a post is ready to go live - Credit image sources (especially Pexels) in HTML headers (
COVER_IMAGE_CREDIT) - Run
pnpm buildbefore pushing — must pass cleanly - Keep it simple — no unnecessary abstractions, no over-engineering
data/
├── site.json ← Global config (agency name, tagline, SEO defaults, social links)
├── hero.json ← Hero section content
├── services.json ← VaaS service offerings
├── about.json ← Founder bio + agency story
├── testimonials.json ← Client testimonials
├── portfolio.json ← Video portfolio showcase
├── pricing.json ← Pricing tiers
├── brands.json ← Client/partner logos
├── contact.json ← Contact details
├── menu.json ← Navigation structure
├── images/ ← All media assets
└── blogs/
├── _authors.json ← Reusable author profiles
├── _template.html ← Active HTML blog template (copy this for new posts)
├── _template.json ← Historical JSON blog template
└── YYYY/ ← Nested year directories
└── MM/ ← Nested month directories
└── YYYY-MM-DD-slug.html ← Individual blog posts
| Component | Reads from |
|---|---|
| Hero | data/hero.json |
| Features (Services) | data/services.json |
| About | data/about.json |
| Testimonials | data/testimonials.json |
| Portfolio | data/portfolio.json |
| Pricing | data/pricing.json |
| Brands | data/brands.json |
| Blog | data/blogs/**/*.html |
| Contact | data/contact.json |
| Header / Footer | data/site.json + data/menu.json |
data/images/
├── logo/ ← Agency logos (dark + light variants)
├── hero/ ← Hero section background/decorative images
├── about/ ← Founder photo (founder.jpg), agency pictures
├── portfolio/ ← Portfolio video thumbnails
├── services/ ← Service icons or illustrations
├── testimonials/ ← Client headshots
├── brands/ ← Client / partner logos
├── blog/
├── authors/ ← Author avatars (founder uses /images/about/founder.jpg)
└── posts/ ← Blog cover images, organized by Year > Month
├── YYYY/
│ └── MM/ ← Post cover images (e.g. /images/blog/posts/YYYY/MM/slug.jpg)
└── inline/
└── YYYY/
└── MM/ ← Inline images embedded inside post body (e.g. /images/blog/posts/inline/YYYY/MM/slug-desc.jpg)
- Cover image →
/images/blog/posts/YYYY/MM/{slug}.jpg(physically resolves todata/images/blog/posts/YYYY/MM/{slug}.jpg) - Inline image →
/images/blog/posts/inline/YYYY/MM/{slug}-{description}.jpg(physically resolves todata/images/blog/posts/inline/YYYY/MM/{slug}-{description}.jpg) - Always use JPG for photos (smaller file size). Use PNG only for logos/icons with transparency.
Blog cover images are automatically fetched from Pexels using the scripts/fetch-blog-images.mjs script.
- Get a free Pexels API key at https://www.pexels.com/api/
- Create
.env.localin the project root (already gitignored):PEXELS_API_KEY=your_key_here
The script:
- Reads every HTML file in
data/blogs/recursively - Checks if
publishedheader istrue(skips drafts) - Checks if the physical cover image already exists — skips it if so
- Searches Pexels using the
PEXELS_QUERYheader (or falls back toTITLE+ firstTAGS) - Downloads the best landscape result to the correct
data/images/blog/posts/YYYY/MM/path - Writes the
COVER_IMAGE_CREDITheader back to the HTML file automatically
pnpm fetch-imagesEach blog post HTML header has an optional PEXELS_QUERY field:
PEXELS_QUERY: video editor working at computer dark studio
- Write a descriptive visual scene, not just the topic title
- Think: what would the ideal photo look like?
- Good:
PEXELS_QUERY: cinematic color grading monitor dark room - Bad:
PEXELS_QUERY: color grading article - If omitted, the script uses
TITLE + TAGS[0]which may give generic results
- Create
data/blogs/YYYY/MM/YYYY-MM-DD-slug.htmlfromdata/blogs/_template.html - Set
PEXELS_QUERY: describe the ideal cover photo visuallyin headers - Run
pnpm fetch-images— image downloads automatically - Verify the image looks right under
data/images/blog/posts/YYYY/MM/ - If not ideal: change
PEXELS_QUERY, delete the downloaded file, run again - Set
PUBLISHED: truein headers pnpm build→ commit → push → Vercel deploys
- Open the relevant JSON file in
data/ - Edit the values (keep the structure intact)
- Save and verify with
pnpm dev - Commit and push — Vercel auto-deploys
- Post file:
data/blogs/YYYY/MM/YYYY-MM-DD-slug.html - Cover image:
data/images/blog/posts/YYYY/MM/{slug}.jpg - Example:
data/blogs/2026/04/2026-04-10-why-brands-need-video.html→/images/blog/posts/2026/04/why-brands-need-video.jpg
Each blog post contains a metadata header block followed by --- and raw HTML content:
TITLE: Why Every Brand Needs Video Content in 2026
SLUG: why-every-brand-needs-video-content
EXCERPT: Discover why video content is essential...
COVER_IMAGE: /images/blog/posts/2026/04/why-every-brand-needs-video-content.jpg
COVER_IMAGE_CREDIT: Photo by John Doe on Pexels
AUTHOR: founder
TAGS: video-marketing, branding, strategy
CATEGORY: Video Marketing
PUBLISH_DATE: 2026-04-10
PUBLISHED: true
PEXELS_QUERY: video production editing studio monitor
META_TITLE: Why Every Brand Needs Video Content | Motion Luma
META_DESCRIPTION: Discover why video content is essential...
---
<p>Opening paragraph...</p>
<h2>Section Title</h2>
<p>More content...</p>
<figure>
<img src="/images/blog/posts/inline/2026/04/inline-image.jpg" alt="description" />
<figcaption>Photo by Pexels</figcaption>
</figure>
<ul>
<li>Point 1</li>
<li>Point 2</li>
</ul>
<blockquote>
<p>A compelling quote</p>
<cite>— Someone</cite>
</blockquote>- Blog posts:
YYYY-MM-DD-slug-words.html(e.g.,2026-04-10-why-brands-need-video.html) - Blog images: match the slug (e.g.,
why-brands-need-video.jpg) - Components: PascalCase (e.g.,
ServiceCard.tsx) - JSON content: kebab-case (e.g.,
services.json)
- Framework: Next.js 13+ (App Router), TypeScript
- Styling: Tailwind CSS
- Content: JSON/HTML files in
data/(no CMS, no database) - Images: Local files in
data/images/(Pexels for blog images) - Hosting: Vercel (auto-deploy from GitHub
mainbranch) - Package Manager: pnpm
pnpm dev # Start development server
pnpm build # Production build (MUST pass before pushing)
pnpm lint # Run linter
pnpm fetch-images # Auto-download missing blog cover images from PexelsLocal Edit (AI tool or manual)
↓
pnpm build (verify it passes)
↓
git add + commit + push
↓
GitHub (main branch)
↓
Vercel auto-deploy
↓
Live website
| Route | Purpose |
|---|---|
/ |
Homepage (hero, services, portfolio, testimonials, pricing, blog preview) |
/about |
Founder intro + agency story |
/blog |
Blog listing |
/blog/[slug] |
Individual blog post |
/contact |
Contact page |
If you're a new AI agent working on this project:
- Read this file first
- Read
CLAUDE.mdandAI_PROMPTS.mdfor reference overrides and prompts - Content changes → edit JSON or HTML under
data/ - Design changes → edit components in
components/ - Never introduce a database, CMS, or authentication
- Always test with
pnpm buildbefore committing