2026-08-14

このブログの仕組み — MDX に p5.js を埋め込む

#astro #mdx #meta

このブログは Astro の content collections + MDX で動いている.ページは純粋な静的 HTML として配信され,インタラクティブな部分(q5.js のスケッチや React の UI)だけが island として個別にロードされる.つまり文章は速く,デモは動く.

1記事 = 1フォルダ

記事は src/content/blog/ 以下のフォルダが単位で,フォルダ名がそのまま URL になる.画像もコンポーネントも記事のフォルダに同居させる.

src/content/blog/
└── interactive-boids/
    ├── index.mdx      ← 本文(これを書く)
    ├── thumbnail.svg  ← サムネイル(png/jpg でも可)
    └── BoidsDemo.tsx  ← インタラクティブな部分(必要なら)

index.mdx の先頭に frontmatter を書く.スキーマは Zod で検証されるので,フィールドを忘れるとビルドが落ちて教えてくれる.

---
title: "記事タイトル"
date: 2026-08-15
description: "一覧カードと OGP に使われる要約."
thumbnail: "./thumbnail.svg"
tags: ["p5js", "simulation"]
draft: false # true にすると一覧・RSS から消える
---

あとは Markdown を書くだけ.見出し・リスト・数式もどき・コードブロックはすべて prose(Tailwind Typography)が組版してくれるので,スタイルのことは一切考えなくていい.コードブロックは Shiki がビルド時にハイライトする(ランタイム JS ゼロ).

インタラクティブな部分の埋め込み

React コンポーネントを同じフォルダに置いて import し,client:visible を付けてタグを書く.

import BoidsDemo from "./BoidsDemo";

ここまでは普通の文章.

<BoidsDemo client:visible />

ここからも普通の文章.

client:visible が island 宣言で,「このコンポーネントの JS は,画面に入った瞬間に初めてロードする」という意味になる.ファーストビューに置くなら client:load でもよい.

スケッチは q5.js(p5 互換 API の軽量・高速実装.p5 の約 1/10 のサイズで,WebGPU レンダラも持つ)を,共通ラッパー SketchCanvas 経由で使う.p5 と同じ書き方のスケッチ関数を渡すだけで,キャンバスの生成・リサイズ・破棄はラッパーが面倒を見る.

import SketchCanvas, {
  type SketchFn,
} from "../../../components/sketch/SketchCanvas";

export default function MyDemo() {
  const sketch: SketchFn = (q, root) => {
    q.setup = () => q.createCanvas(root.clientWidth, root.clientHeight);
    q.draw = () => {
      q.background("#f8fafc");
      q.circle(q.mouseX, q.mouseY, 40);
    };
  };
  return <SketchCanvas sketch={sketch} caption="キャプション(任意)" />;
}

q5 本体は動的 import されるので,スケッチのない記事や,まだスクロールが届いていないデモのために読み込まれることはない.色は CSS の色文字列("#f8fafc""hsla(190, 70%, 50%, 0.9)")がそのまま使えて,デフォルトの座標系・カラーモードは p5 と同じ(左上原点・0–255).

画像

記事フォルダに置いて相対パスで参照する.![ボイドの図](./thumbnail.svg) のように普通の Markdown 記法でよく,ラスタ画像(png/jpg)はビルド時に自動で最適化される.

公開

npm run dev    # 手元でプレビュー
npm run build  # 型チェック + 静的ビルド

書き終えたら commit して push するだけ.データベースも管理画面もない.記事は git の履歴に残り,ビルドのたびに一覧・RSS・sitemap・OGP タグが自動で更新される.