Introduction
This blog has been with me for nearly five years and has gone through two major redesigns. The first version was a static blog I built myself with Gatsby + MDX. This time, for the second redesign, I aimed higher: rebuilding it with the modern Next.js 15 and integrating a complete AI generation pipeline.
Early this year, I decided to get started. I also set a challenge for myself: to build the core architecture of the new blog in a single day, collaborating with Claude Code AI.
The result? I actually did it. This post is a complete record of the redesign, covering the pain points of the old site, the design decisions for the new architecture, the hands-on experience of developing with AI, and the full process of integrating Vertex AI Veo 3.1 to generate a showcase video.
1. Old Site's Tech Stack: What Were the Pain Points?
The first version of the blog used Gatsby + gatsby-theme-flexiblog. Articles were written in MDX format and stored directly in a Git repository, with Gatsby statically generating pages at build time. It was quite modern at the time, but after a few years, more and more problems emerged.
First, theme customization was limited. gatsby-theme-flexiblog uses a system called Theme Shadowing for customization. While you could override components, the overall design style was basically fixed. Trying to make significant layout changes or add new interactive elements always felt like a battle against the theme's underlying structure. Changing one small thing could mean digging through several layers of source code.
Next was the maintenance burden of the Gatsby ecosystem. To be honest, Gatsby's position in the React ecosystem has largely been taken over by Next.js. Plugin version conflicts, a complicated GraphQL data layer, and occasional build failures made the maintenance cost increasingly high. Every upgrade was a nerve-wracking experience.
Finally, MDX support wasn't great. Integrating custom components was cumbersome, and syntax highlighting for code blocks required configuring a bunch of plugins. Want to embed an interactive component or a video player in an article? The amount of setup required would make you want to give up.
2. New Site's Tech Stack: What Problems Did It Solve?
The new site uses the following tech stack, and has accumulated 244 articles to date:
| Aspect | Technology Choice |
|---|---|
| Framework | Next.js 15 + React 19 |
| Language | TypeScript |
| Styling | Tailwind CSS 4 |
| Bundler | Turbopack (default) |
| Content Format | MDX (parsed with gray-matter) |
| Deployment | Vercel |
| Comments | Giscus (GitHub Discussions) |
| Analytics | Google Analytics 4 |
MDX-centric Content Architecture
Each article is a separate directory with a very simple structure:
public/content/posts/{handle}/
├── index.mdx # 文章本文 + frontmatter
├── summary.json # AI 生成的摘要文字
├── audio/
│ └── summary.mp3 # TTS 語音摘要
├── images/
│ └── cover.webp # AI 生成封面圖
└── videos/
└── demo.mp4 # AI 生成展示影片
The frontmatter defines all of the article's metadata: title, date, category, tags, thumbnail path, as well as multimedia fields like video and audio URLs.
Seamless Migration with SEO 301 Redirects
The biggest fear with a redesign is having all the old URLs result in 404s, wiping out years of accumulated SEO rankings overnight. So, I designed a 301 redirect mechanism:
舊 URL: /my-post-slug
↓ middleware.ts 攔截(Edge Runtime)
↓ 查詢 redirect-map.json
新 URL: /post/my-post-slug (HTTP 301)
Each article's frontmatter has a oldSlug field to record the old path. Before the build, generate-redirect-map.mjs automatically scans all articles and generates a lookup table, redirect-map.json:
{
"/my-old-slug": "/post/my-new-handle"
}
middleware.ts intercepts requests in the Edge Runtime, looks up the table, and returns a 301. It also performs a case-insensitive comparison (since some URLs on the old platform used mixed case). All 246 migrated articles' old links are seamlessly redirected, fully preserving their accumulated search engine authority.
App Router + Static Generation
The App Router in Next.js 15 makes route organization more intuitive. generateStaticParams pre-generates all article pages at build time, resulting in a first-paint load speed far superior to the old platform.
Turbopack Developer Experience
With the old Webpack setup, starting the dev server for a large project took several seconds. After switching to Turbopack, Fast Refresh is nearly 10 times faster. Changes to components are reflected almost instantly, making the developer experience so much better.
3. AI-Automated Content Generation Pipeline
The biggest differentiator for the new blog is this AI media generation pipeline. All scripts run locally and offline (saving API costs and avoiding Vercel timeouts), and the generated assets are committed directly to Git as static resources.
Cover Image Generation (Gemini Image)
npm run generate-post-cover -- --handle migrate-blog-with-ai
The script reads the article's title and category, has gemini-2.5-flash generate an image prompt, and then uses gemini-3.1-flash-image-preview to create a 16:9 tech-style cover image. Each category has a corresponding color scheme—purple for AI, blue for Frontend, green for DevOps—creating a visually consistent look.
AI Audio Summary (Gemini + VoAI Offline TTS)
npm run generate-audio -- --handle migrate-blog-with-ai
The script uses Gemini to generate a 350-500 word summary and podcast script in Traditional Chinese for each article, then synthesizes an mp3 audio file offline using VoAI.
VoAI is an AI voice synthesis tool developed locally in Taiwan. It supports Traditional Chinese and offers a variety of natural-sounding voices, delivering a smooth and fluent Chinese AI voiceover experience.
Background Music (Google Lyria)
npm run generate-music
I use Google's Lyria music generation model to create background music suitable for a reading environment. The music style is described by an AI music curator persona named "Melody."
Category Icons and Banners
Each of the 22 article categories has an iOS-style icon and banner, all generated by the Gemini image model, resulting in a very consistent style.
4. Vertex AI Veo 3.1: Generating a Tech Showcase Video with AI
This is the key technology highlighted in this post: using Google Vertex AI's veo-3.1-generate-001 model to generate video directly from a text prompt.
Why do this?
Pairing technical articles with videos can certainly help readers understand the content better. But honestly, the cost of recording and editing is high; just setting up screen recording software takes a significant amount of time. Veo 3.1 allows me to generate a pretty decent tech architecture showcase video from just a text description—no screen recording, no editing software needed.
How to Call the Veo 3.1 API
Veo 3.1 uses Vertex AI's Long-running Operation model because video generation takes a considerable amount of time:
// 1. 發起生成請求
const response = await fetch(
`https://us-central1-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/us-central1/publishers/google/models/veo-3.1-generate-001:predictLongRunning`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
instances: [{
prompt: "A cinematic visualization of a modern Next.js 15 blog architecture: data flowing from MDX files through gray-matter parsing, through React Server Components, rendered as a beautiful dark-themed blog. Indigo and teal color scheme, technical diagram style with glowing nodes and connecting lines."
}],
parameters: {
aspectRatio: "16:9",
sampleCount: 1,
durationSeconds: 8,
generateAudio: false,
}
})
}
)
// 2. 取得 operation name
const { name: operationName } = await response.json()
// 3. 輪詢等待完成
let result
while (true) {
const pollResponse = await fetch(
`https://us-central1-aiplatform.googleapis.com/v1/${operationName}`,
{ headers: { 'Authorization': `Bearer ${accessToken}` } }
)
result = await pollResponse.json()
if (result.done) break
await sleep(10000) // 每 10 秒輪詢一次
}
// 4. 取出影片 base64 並存檔
const videoBase64 = result.response.videos[0].bytesBase64Encoded
fs.writeFileSync(outputPath, Buffer.from(videoBase64, 'base64'))
The generate-video.mjs script
scripts/generate-video.mjs integrates the entire generation process:
# 為指定文章生成展示影片(從文章標題與描述自動生成 prompt)
npm run generate-video -- --handle migrate-blog-with-ai
# 指定自訂 prompt
npm run generate-video -- --handle migrate-blog-with-ai --prompt "Modern blog architecture visualization"
# 強制重新生成
npm run generate-video -- --handle migrate-blog-with-ai --force
The script's job is simple: it reads the article's title and description, uses Gemini to translate the Chinese title into an English visual prompt suitable for Veo, calls the API, polls for completion, and finally saves the .mp4 to public/content/posts/{handle}/videos/architecture-demo.mp4.
Video Too Big? Auto-Upload to YouTube
Videos generated by Veo 3.1 can easily be 10-20MB. If stored directly in the Git repository, the repo would bloat quickly. Therefore, generate-video-youtube.mjs has a built-in file size check: if a video exceeds 5MB, it's automatically uploaded to YouTube and the local file is deleted.
# 自動判斷:影片 > 5MB 就上傳 YouTube,並刪除本地檔案
npm run generate-video-youtube -- --handle migrate-blog-with-ai
# 批次處理最近 5 篇文章
npm run generate-video-youtube:recent -- 5
# 強制重新生成並上傳(即使已有 YouTube URL)
npm run generate-video-youtube -- --handle migrate-blog-with-ai --force
The process is roughly as follows: first, call generate-video.mjs to generate the video. Check the file size. If it's over 5MB, upload it via the YouTube Data API v3, then automatically update the frontmatter's videoUrl to the YouTube URL, and finally delete the local video file. This way, the video is hosted by YouTube's CDN, and the Git repository only stores the YouTube URL, preventing the repo from getting bloated by AI-generated videos.
Embedding Videos in Articles
Just add videoUrl to the frontmatter:
videoUrl: "https://www.youtube.com/watch?v=tTQklpzEEzk"
scrollAutoPlay: false
The blog's video component automatically handles path resolution, supporting both local .mp4 and YouTube URL formats.
5. Results and Future Plans
Traffic grew from 10,000 to 60,000 visits per year, a 6x increase. This isn't just an effect of the redesign itself; it's a direct result of search engines awarding higher rankings after improvements to SEO structure and loading speed.
The Biggest Takeaway
Honestly, the biggest takeaway isn't just a better-looking blog, but a reusable AI content generation infrastructure. The cover image, audio summary, and showcase video for each new article can be generated with a single command. This has significantly lowered the barrier to writing—what used to take half an hour just to create a cover image is now done with a single line in the terminal.
What's Next
- Use Veo 3.1 in more scenarios, like tutorial animations or dynamic architecture diagrams.
- Experiment with Gemini's multimodal capabilities, for example, by feeding it screenshots to automatically generate descriptive text.
- Build a RAG knowledge base so readers can ask questions directly about the blog's content.
Building this new blog in a day wasn't the end, but a new beginning.
AI tools allowed me to compress what would have been a week's work into a single day. The time saved can now be spent on a more valuable question: What should I write about next?




























Comments