MDX 內容編輯與維護指南

這一頁是本網站唯一的內容編輯手冊。新增或修改作業、專案、報告前,先依本頁的資料夾規則建立檔案,再更新 config/AllData.ts

快速流程

  1. markdown/ 對應課程資料夾新增 .mdx
  2. 將一般圖片放入 public/images/,banner 放入 public/thumbs/,可下載檔案放入 public/files/
  3. config/AllData.ts 新增或更新該頁的 namenavNameslugimage
  4. pnpm dev 開啟預覽,確認網址、banner、圖片與連結。
  5. 停止開發伺服器後再執行 pnpm build

不要同時執行 pnpm devpnpm build。兩者同時寫入 .next 時,可能出現 Cannot find module './xx.js'。若開發畫面或 chunk 異常,停止服務後執行 pnpm dev:clean

資料夾規則

markdown/
  homework/computer-animation/
  project/computer-animation/
  paper/computer-animation/

public/
  images/   一般內容圖片
  thumbs/   每個頁面最上方的 banner
  files/    可直接下載的 PDF、blend、stl、zip 等檔案

建議依內容分類,並讓資料夾名稱與 AllData.ts 的內容相對應:

public/images/homework/computer-animation/hw15/
public/thumbs/homework/computer-animation/hw15/
public/files/homework/

public/images/project/computer-animation/project02-w16-final/
public/thumbs/project/computer-animation/project02-w16-final/
public/files/paper/computer-animation/paper03/

瀏覽器使用的網址不需要寫 public

public/images/example.png  ->  /images/example.png
public/files/example.blend ->  /files/example.blend

AllData 與路由

config/AllData.ts 決定 navbar、頁面標題、banner 與網址。slug 必須和 MDX 檔名一致,但不包含 .mdx

Homework 與 Paper

{
  name: "Homework 15_完整頁面標題",
  navName: "HW15",
  slug: "CG_HW15",
  image: "/thumbs/homework/computer-animation/hw15/banner.jpg"
}

產生的頁面網址:

/homework/computer-animation/CG_HW15
  • name:banner 與頁面顯示的完整標題。
  • navName:navbar 內較短的名稱,例如 HW15
  • slug:網址最後一段,也是 MDX 檔名,例如 CG_HW15.mdx
  • image:banner 路徑,必須位於 public/thumbs/

Project 的多層選單

Project 可用 children 建立第三層詳細頁。父層不可直接點擊,詳細頁放在 children 中。

{
  name: "PROJECT02",
  navName: "PROJECT02",
  slug: "project02",
  image: "/thumbs/project/computer-animation/project02-w11/banner.jpg",
  children: [
    {
      name: "PROJECT02_W11",
      navName: "PROJECT02_W11",
      slug: "CG_Proj02_W11",
      image: "/thumbs/project/computer-animation/project02-w11/banner.jpg"
    }
  ]
}

詳細頁 MDX 仍放在課程資料夾,不需要再建立 project02/ 子資料夾:

markdown/project/computer-animation/CG_Proj02_W11.mdx

新增檢查清單

  • MDX 檔案已建立,檔名與 slug 一致。
  • banner 位於 public/thumbs/
  • 一般圖片位於 public/images/
  • 下載檔案位於 public/files/
  • AllData.ts 已新增對應資料。
  • 手機與桌面 navbar 都能找到該頁。

頁面建議結構

# 是頁面主標題,課程頁的 banner 已經會顯示主標題,因此一般不要在 MDX 再寫 # Homework 02

<MarkdownMeta hours={6} />

## 作品技術概念

說明作品使用的技術與設計想法。

<ContentImages
  src="/images/homework/computer-animation/hw15/overview.png"
  alt="作品總覽"
  maxWidth="2xl"
/>

## 節點概念說明(附上實際節點、面數等截圖)

<ContentImages
  src="/images/homework/computer-animation/hw15/node-count.png"
  alt="模型面數"
  caption="模型面數"
  maxWidth={200}
/>

### step 1-1:建立基本形狀

1. 先完成基本模型。
    - 用第一個節點建立輪廓。
    - 再調整尺寸。

## 自我評量與作品建議

<RatingSummary score={["8/10"]} />

## 解決問題之能力與參考資源

補上參考資料、問題與解法。

Markdown 基本語法

標題

# H1:一般頁面不要使用,banner 已有主標題
## H2:主要章節,例如作品技術概念、過程記錄、自我評量
### H3:章節中的步驟,例如 step 1-1
#### H4:必要時才使用的更小分類

文字樣式與段落

一般文字。

空一行會形成新段落。
**粗體**
*斜體*
***粗斜體***
~~刪除線~~
`inline code`

需要在同一段換行時使用:<br/>

連結與下載檔案

[一般連結](https://example.com)
[官方文件](https://docs.blender.org/)
[下載練習檔](/files/homework/repeat___join.blend)

雲端 Google Drive、YouTube、Gemini 等連結可直接保留外部網址。網站內的檔案則放入 public/files/,再使用 /files/... 路徑。

清單與正確縮排

- 第一個主要項目
- 第二個主要項目

1. 第一個步驟
2. 第二個步驟
    - 這是第二個步驟底下的小項目。
    - 小項目要縮排四個空白。
        - 再下一層使用八個空白。
3. 第三個步驟

- 若屬於某個數字步驟的說明,一定要縮排四個空白;獨立的主清單則不要縮排。

引言、分隔線與跳脫字元

> 這是一段引用或重點提醒。

---

\*這不是斜體\*

程式碼區塊

```ts
const score = ["8/10"];
```

可用的常見語言標示有 tstsxjsjsxjsonbashtxtmdx

表格、核取方塊與自動連結

本網站已啟用 GitHub Flavored Markdown(GFM)。

| 欄位 | 說明 |
| :--- | :--- |
| `name` | 完整標題 |
| `navName` | navbar 短標題 |

- [x] 已完成
- [ ] 尚未完成

https://example.com

數學公式

本網站已啟用 remark-mathrehype-katex

行內公式:$E = mc^2$

區塊公式:

$$
\int_a^b f(x)\,dx = F(b) - F(a)
$$

MDX 元件總覽

以下元件已在 mdx-components.tsx 全域註冊,直接在 MDX 使用即可,不需要 import

元件用途
MarkdownMeta製作時數與檔案連結
ContentImages單張圖片、多張 grid、圖片比例與說明
ImageCarousel可自動播放的輪播圖
YouTubeEmbedYouTube 單支或 grid 影片
RatingSummary自我評量分數
ScrollReveal進入視窗時的淡入動畫
ImageNext.js 原生圖片元件;一般情況優先使用 ContentImages

MarkdownMeta

用於頁面最上方的製作時數與檔案按鈕。

可用參數

參數型別預設說明
hoursnumberstringstring[]不顯示製作時數。數字會顯示為小時;多週資料用陣列。
links{ label, text, href }[][]檔案或外部連結按鈕。
links[].labelstring必填按鈕左側的標籤。
links[].textstring必填按鈕內文字。
links[].hrefstring必填外部網址或 /files/... 本機檔案路徑。
<MarkdownMeta
  hours={6}
  links={[
    {
      label: "Blender 檔案",
      text: "File Link",
      href: "https://drive.google.com/"
    },
    {
      label: "練習檔案",
      text: "Download",
      href: "/files/homework/repeat___join.blend"
    }
  ]}
/>

多週時數:

<MarkdownMeta
  hours={[
    "[week06] 7 小時",
    "[week08] 9 小時"
  ]}
/>

Paper 沒有製作時數時,只傳入 links,頁面只會顯示按鈕。

<MarkdownMeta
  links={[
    {
      label: "File Download",
      text: "File Download",
      href: "/files/paper/computer-animation/paper01/report.pdf"
    }
  ]}
/>

ContentImages

所有一般圖片優先使用此元件。可呈現單張圖片、grid、caption、指定最大寬度,以及統一圖片比例。

可用參數

參數型別/可用值預設說明
srcstring單張圖片路徑。與 images 二擇一。
images圖片物件陣列多張圖片 grid。若有值會優先使用。
altstring圖片單張圖片的替代文字。
captionstring單張圖片說明;不需要就不要傳。
widthnumber900圖片原始寬度資訊。主要顯示尺寸請用 maxWidth
heightnumber506圖片原始高度資訊。主要顯示尺寸請用 maxWidth
columns12341grid 欄數;手機會自動縮為較少欄。
maxWidth尺寸名稱或 number"xs"單張圖片最大寬度。數字單位為 px。
aspectRatio"auto""square""video""4/3""3/4""auto"固定圖片框比例。
fit"contain""cover""contain"固定比例框內的圖片填滿方式。

images 陣列內每一張可使用:src(必填)、altcaptionwidthheightaspectRatiofit。單張設定會覆蓋外層的 aspectRatiofit

maxWidth 尺寸表

實際最大寬度
"xs"20rem,320px
"sm"24rem,384px
"md"28rem,448px
"lg"48rem,768px
"xl"64rem,1024px
"2xl"80rem,1280px;仍受頁面容器限制
"full"父容器全寬
maxWidth={300}300px

單張一般大圖

<ContentImages
  src="/images/homework/computer-animation/hw15/overview.png"
  alt="作品總覽"
  maxWidth="2xl"
/>

節點概念的模型面數圖

<ContentImages
  src="/images/homework/computer-animation/hw15/node-count.png"
  alt="模型面數"
  caption="模型面數"
  maxWidth={200}
/>

多張圖片 grid

<ContentImages
  columns={2}
  maxWidth="2xl"
  images={[
    { src: "/images/example-1.jpg", alt: "步驟一", caption: "步驟一" },
    { src: "/images/example-2.jpg", alt: "步驟二", caption: "步驟二" }
  ]}
/>

統一比例,但保留完整圖片

<ContentImages
  columns={3}
  maxWidth="2xl"
  aspectRatio="video"
  fit="contain"
  images={[
    { src: "/images/example-1.jpg", alt: "分鏡一" },
    { src: "/images/example-2.jpg", alt: "分鏡二" },
    { src: "/images/example-3.jpg", alt: "分鏡三" }
  ]}
/>

contain 會完整顯示圖片,比例不同時可能有留白;cover 會填滿比例框,但可能裁切邊緣。

每一張使用不同設定

<ContentImages
  columns={2}
  images={[
    {
      src: "/images/example-1.jpg",
      alt: "方形裁切圖",
      aspectRatio: "square",
      fit: "cover"
    },
    {
      src: "/images/example-2.jpg",
      alt: "完整影片比例圖",
      aspectRatio: "video",
      fit: "contain"
    }
  ]}
/>

ImageCarousel

適合連續步驟截圖。輪播固定為 16:9 顯示框、圖片完整呈現、可手動切換與暫停。若有多張圖片,預設每 6000ms 自動播放。

可用參數

參數型別/可用值預設說明
images{ src, alt?, caption? }[]必填輪播圖片。沒有有效 src 時不顯示。
images[].srcstring必填圖片路徑。
images[].altstring替代文字。
images[].captionstring圖片下方說明。沒有說明文字時使用 " "
labelstring"Image carousel"無障礙標籤。
autoPlaytruefalsetrue是否自動播放。
intervalnumber6000自動切換間隔,單位為毫秒。
<ImageCarousel
  label="HW15 製作步驟"
  interval={8000}
  images={[
    {
      src: "/images/homework/computer-animation/hw15/step-1.png",
      alt: "建立基本形狀",
      caption: "建立基本形狀"
    },
    {
      src: "/images/homework/computer-animation/hw15/step-2.png",
      alt: "調整節點",
      caption: " "
    }
  ]}
/>

停止自動播放:

<ImageCarousel
  autoPlay={false}
  images={[
    { src: "/images/example-1.png", caption: " " },
    { src: "/images/example-2.png", caption: " " }
  ]}
/>

YouTubeEmbed

YouTube 連結必須使用 /embed/ 格式,例如 https://www.youtube.com/embed/VIDEO_ID

可用參數

參數型別/可用值預設說明
srcstring單支影片網址。與 videos 擇一使用。
titlestring"YouTube video"單支影片標題。
videos{ src, title? }[]多支影片;有值時會優先於 src
videos[].srcstring必填YouTube embed 網址。
videos[].titlestring自動編號iframe 標題。
columns1231影片 grid 欄數。手機自動單欄。

單支影片:

<YouTubeEmbed
  src="https://www.youtube.com/embed/ag5sb85o8jQ"
  title="成果影片"
/>

兩支連續影片並排:

<YouTubeEmbed
  columns={2}
  videos={[
    { src: "https://www.youtube.com/embed/video-id-1", title: "製作過程" },
    { src: "https://www.youtube.com/embed/video-id-2", title: "成果展示" }
  ]}
/>

三支影片:

<YouTubeEmbed
  columns={3}
  videos={[
    { src: "https://www.youtube.com/embed/video-id-1" },
    { src: "https://www.youtube.com/embed/video-id-2" },
    { src: "https://www.youtube.com/embed/video-id-3" }
  ]}
/>

RatingSummary

用於「自我評量與作品建議」的分數。score 必須是陣列,即使只有一個分數也要用 [] 包起來。

可用參數

參數型別預設說明
titlestring"自我評量與作品建議"顯示在左側的標題。
scorestring[]必填每個字串會顯示為一行分數。
<RatingSummary score={["8/10"]} />

多週評分:

<RatingSummary
  title="自我評量與作品建議"
  score={[
    "[week06] 9/10",
    "[week08] 8/10"
  ]}
/>

ScrollReveal

讓包住的內容在進入視窗時淡入上移。一般 Markdown 的標題、段落與上述常用元件已自動套用,不需要再包一次;只在自訂 JSX 區塊需要額外動畫時使用。

可用參數

參數型別預設說明
childrenJSX 內容必填要產生動畫的內容。
classNamestring加在外層動畫容器的 class。
delaynumber0動畫延遲秒數,例如 0.2
<ScrollReveal delay={0.2}>
  <div className="not-prose border border-neutral-200 p-4">
    自訂內容
  </div>
</ScrollReveal>

Image

Image 是 Next.js 原生圖片元件,已全域提供。除非需要 Next.js 的特殊 props,否則優先使用 ContentImages,因為它已處理圖片寬度、caption、grid 與比例。

常用參數:

<Image
  src="/images/example.png"
  alt="圖片說明"
  width={900}
  height={506}
  className="h-auto w-full object-contain"
/>

srcaltwidthheight 為最常用欄位。使用 fill 時,父容器必須有 relative 與固定高度或 aspect-ratio

開發與部署

# 一般開發預覽
pnpm dev

# `.next` 快取異常時,清除後重啟
pnpm dev:clean

# production build;先停止 pnpm dev
pnpm build

部署到 Vercel 前確認:

  • package.jsonpnpm-lock.yaml 都已提交。
  • 所有 /images/thumbs/files 路徑的檔案都在 public/
  • MDX 檔名、slug、動態網址一致。
  • pnpm build 成功。

常見問題

圖片大小沒有改變

widthheight 主要提供圖片原始比例與最佳化資訊;畫面寬度應調整 maxWidth

maxWidth={200}
maxWidth="2xl"

圖片比例不一致

使用 aspectRatio,並決定要完整顯示或裁切:

aspectRatio="video"
fit="contain"

輪播圖沒有說明文字

輪播圖片仍要傳入空白 caption:

{ src: "/images/example.png", caption: " " }

單張圖片沒有說明文字

不要傳 caption,不會自動顯示 Picture 或其他替代文字。

內容更新後出現 Cannot find module './xx.js'

停止正在執行的 pnpm dev,然後執行:

pnpm dev:clean

© 2026 Yen-Chia, Feng. All rights reserved.