はじめに
生成AIの登場で、簡単にコードを書く時間が大幅に減少した。で、空いた時間で、いろいろなことを考えることができるようになった。さて、そこで一つの疑問が浮かぶ。
圧倒的な力を手に入れたその先には何が見えるだろうか?
自分なりの回答を示したいと思う。今回Universal Markdown(以下umd)というものを作った。
PukiWiki AdvanceからLukiWikiへ
これは、もともとはPukiWiki Advance(以下PukiWiki Adv.)の後継として作っていたLukiWikiまで遡る。
PukiWiki Advanceでは開発初期の段階から、PukiWikiと互換性を取りつつも、Zend Frameworkへの置き換えを行い、本体を薄くしてPHPの仕様変更にも耐えうるようにするという方針で開発していたが、それでも、コードが肥大化しフロントエンド部分の圧縮済みコードが300kをオーバーするような状態であった。このため、2016年頃にメンテナンスしきれなくなった。
そこで、当時話題になっていたLaravelで書き直すことにした。これがLukiWikiの始まりである。Lを選んだのは単にLaravelだったからで深い意味はない。あと、PukiWikiの互換性の枷がなくなったので文法もMarkdownに寄せたものにしようと考えていた。当時の時点でPukiWikiは退潮気味で多くの人はQittaなりGFMなりでMarkdownに移行していたので、そっちに寄せたほうが良いと考えのである。
しかし、Markdownには色々不満があった。まず表現できることが少ない。文字の色を変えたり字を寄せたりする簡単なことでさえHTMLが必要になるというキメラ文法である。
いや、キメラはキメラでもそういう意味じゃないですw。重音テトさんには、今作っているvoyagerwave [1980 Nov 12-13]のミュージックビデオの歌手兼ダンサーとして出てもらうので、そのときに…ね。
「君はじつに馬鹿だな」
うるさい(w
ともあれ、PukiWikiを使ってた人間からすればMarkdown自由すぎる、あるいは仕様がしっかりしていないと感じられる。また、非ASCII文字での利用を考慮していないのか、アンカーリンクが汚かったりそもそも機能していないパターンがあるのも気になっている。
で、当時、基本的な文法仕様書を書いた。初版は、なんと2018年である。
特筆すべき点として、当時Laravelに標準搭載されていたVueを使ってフロントエンドを描画しようとしたことである。例えばメニューバーの項目やコメントフォーム、編集画面などが該当する。
SEOの観点からすると、こういったリッチなパーツは検索エンジンにとってノイズにしかならない上に、転送量の観点からもサーバーで処理させるメリットがない。PukiWiki Advanceの時点でも、jQueryでフォームを動的に書き換えてリッチインターフェースを実装する仕様にしていた。
しかし、Vueを使うことで、独自タグで描画させることにより、検索エンジンへのノイズを減らしつつ、UXを向上させることができるのではないかと考えた。同じコードをvueで実装したところ、明らかに早かったしね。
自分のVueとの長い付き合いはここから始まった。
また、この時点で、PukiWiki文法からLukiWiki文法に移行するプログラムもほぼ完成のレベルで作っていた。この移行プログラムは、本文だけでなく添付ファイルやバックアップなども含まれていた。
なぜ頓挫したのか?
単純に自分のキャパオーバーである。
文法仕様から技術スタック、インフラ、バックエンド、フロントエンド全部を考えるのは難しい。文法仕様が固まっており、データベースはLaravelで抽象化できると言っても、例えばこのページはこのひとだけ編集許可するなどの権限管理の仕様まで、単独の個人で全部考えて実装するのは困難である。
それに加えて、派生版という枷が外れた結果、プラグインも全部作り直さなければならない。あと、今回使用したVueは、独自タグの置換として使っていたが、作っているうちにVueの使い方が間違っていたらしいというのもある。
そのうち、どんどん関心がVueに移っていき、戻ってこれなくなってしまったというのが真相である。
Universal Markdownとしての復活
それから6年以上にわたり仕様書だけある忘れ去られた存在であったが、AI駆動開発でDrop Compress Imageを開発したときにふと思ったのだ。
バイブコーディングでこの仕様書をRustで組めいいのでは?
というわけで、さきのLukiWiki仕様書を読み込ませて仕様書を書かせた。確か2026年1月中旬だったと思う。
初期の設計:
単純に先の仕様書を読ませて、実装は全て生成AIにさせたが、AIがテストプログラムも一緒に生成したので、自分の思想がちゃんと伝わっているかのテストができるようになった。まさに、AIバイブコーディング+仕様駆動開発+テスト駆動開発のキメ・・・もとい、ハイブリッド開発である。
最初はPLAN.mdにまとめて管理していたがやりたいことが肥大化してきて次第に管理が困難になってきた。仕方がないのでファイルを分けて管理するようになった。開発から1か月経過した時点で人間が読める仕様書ではなくなっている。
日本語では書いてあるが、相当集中して読まないと何が書いてあるのかや意図がさっぱりだと思う。とりあえずこの記事では最低限の意図を書くことにする。
なぜRust?
これは明確な理由がある。まず、RustはAIにとって最も書きやすい言語であるということ。次に、Drop Compress Imageという実績があるということ、最後に、RustはWasmにコンパイルするための仕様が含まれているということである。
WASMはWebAssemblyのことで、ネイティブコードのスピードで動く。また、ブラウザだけでなくPHPなどからも扱えるので案外移植性が高い。本ライブラリでは、パースと最小限の変換のみを扱う責務なのでコード的に疎結合しやすいというメリットがある。
Bootstrap密結合
デザインシステムは逆にあえて、Bootstrapに密結合させている。Tailwindにしなかった理由はあまりにも自由度が高いからである。例えばTailwindでカードを書くだけでも、こんなに冗長な表現が必要になる。
<div class="mx-auto flex max-w-sm items-center gap-x-4 rounded-xl bg-white p-6 shadow-lg outline outline-black/5 dark:bg-slate-800 dark:shadow-none dark:-outline-offset-1 dark:outline-white/10">
<div>
<div class="text-xl font-medium text-black dark:text-white">タイトル</div>
<p class="text-gray-500 dark:text-gray-400">本文</p>
</div>
</div>
それよりも、長い歴史があってコンポーネント指向で、型がガッチリと決まっているBootstrapのほうが適切である。そもそもHTMLを簡素に扱うのがMarkdownのあり方であるのでどうとでもつくれてしまうTailwindは特にシステムにおいては本質的に不適格である。
<div class="card">
<div class="card-body">
<h5 class="card-title">タイトル</h5>
<p class="card-text">本文</p>
</div>
</div>
そもそも、Markdownでドキュメントを作成する層がTwilwindを使いこなすレベルにあるかどうか甚だ疑問である。Linterすら入れてないのでは?
また、ダークモード対応や色彩工学に基づいた11色の限られた色しかつかえないカラーパレットがあるのも強みだし、Githubもカラーリングは完全にBootstrapのそれである。
Tailwindだとカラーパレットの色数が多すぎる。例えば、灰色だけでも9種類ある。デザイナー目線では便利かもしれないが、ドキュメント作成においては明らかに過剰である。色数が多ければ多いほど表現しやすくなるとは限らないばかりか、UX目線でいくと混乱の原因になる。
よーく考えてほしい。Tailwindのカラーパレットで、隣り合った色の文字を並べて見分けがつくと思いますか?
安易にTailwindが良いと言っている連中は、何でもできるということは、自由度が高いではなく、どうとでもなってしまうことであることをいい加減に理解するべきである。
とにかく、視覚的にであれ、コード的であれ、混乱を招きかねない技術選定は割けるべきである。
UMDってぶっちゃけどういうMarkdownなの?
Twilwindディスりはやめて話を戻そう。一言で言うと、UMDは、セマンティック性を重視したマークダウン言語である。とはいっても、セマンティク性と言ってもわからないかもしれない。
セマンティック性
セマンティックとは、単語に明示的に意味の重みをもたせるということである。<b>タグと<strong>タグの違いなんかがわかりやすいと思う。この2つのタグは、表示上は、同じボールドの文字となるが、前者は見かけ上のみだが、後者は強調という意味がある。
Markdownでは、<strong>と<em>があるが、単にボールドやイタリックにしたい場合の表記方法がない。つまるところ、単に太文字にしたいだけのときに**でくくってしまうと、強調になってしまう。そこで、PukiWikiの表現を<b>と<i>タグに割り当てて使用目的を明確に分けた。
インライン書式
UMDではPukiWikiのインラインプラグイン記法からインスパイアされた&function(args){param};という表記でこれを拡張可能な形式で実現している。例えば、略字を表現する<abbr>の場合、&abbr(HTML){Hyper Text Markup Language};のように入力すると<abbr title="Hyper Text Markup Language">HTML</abbr>というように変換される感じだ。
ブロック書式
ブロック書式はPukiWikiのブロック型プラグインにインスパイアされている。
@function(args){{
...
}}
という書式だ。PukiWikiと異なるのは#が@に変わったことと、インデントを推奨することである。例えば、<detail>と<summary>を使ったDOMの場合下記のように表現される:
@detail(テキスト){{
▼をクリックしたときに展開される中身
}}
<detail>
<summary>テキスト</summary>
▼をクリックしたときに展開される中身
</detail>
メディアタグ
次に画像タグ()である。UMDではこの仕様を音声、動画などといった「メディアを扱うタグ」として再定義し、モダンな<picture>や<audio>や<video>タグとして出力する。また、セマンテック性を考慮し、<figure>タグでくくるようにしてある。
例えば画像の場合こうなる
<figure>
<picture title="会社ロゴ">
<source srcset="logo.png" type="image/png" />
<img src="logo.png" alt="Company logo" title="会社ロゴ" loading="lazy" />
</picture>
<figcaption>会社ロゴ</figcaption>
</figure>
テーブルタグ
テーブル表記も拡張してあり、旧来のMarkdownのテーブル記法と、PukiWiki由来のテーブル記法の両方をサポートしている。ただし、意味付けは異なる。
Markdownのテーブルはセル連結に関する仕様がないことを逆手に取って、Markdownのテーブル記法は、データを記載するためのテーブル、PukiWiki由来のテーブル記法はレイアウトのためのテーブルというように分けている。
前者の場合、ソータブルとする。
コードブロック/Marmaid
最後にコードブロックとMarmaid記法の扱いである。カラーリングを統一させるため、シンタックスハイライタや、MarmaidはRustでエンジンの中に組み込まれており、ポストプロセスでBootstrapのカラーリングをvar()で参照するようにしている。このため、Growiなどであったダークモードで閲覧したときに図が黒くなって見えなくなるという問題が発生しない。これらのタグも<figure>タグで括られており、セマンティック性は確保されている。
プラグイン仕様
UMDではHTMLを一切許可しない。これはセキュリティのためである。ただし、インライン要素とブロック要素をプラグインという形で文法を拡張できるようになっている。このエンジンではプラグインのHTMLは<template>タグと<data>タグで表現されプラグインから本体を操作することはできない。
これにより、拡張性は担保している。ライブラリ利用者が自己責任で文法を拡張する仕様だ。
フロントマターの事実上の必須化
Markdownの仕様にフロントマターというものがある。UMDではこれを必須とし、最低限タイトルは入力するようにする。ここではドキュメントのメタタグや、タグ機能を定義する。
他にも将来的な構想として、テンプレートエンジンのデータのバインディングとしても使う予定だ。
テンプレートエンジン展開
プラグインの書式の書き方を応用して@ifや@elseなどの表記をサポートし、テンプレートエンジンとしての展開も考えている。パフォーマンス的にメリットが有るか疑問だが・・・。
とざっと説明するとこんな感じである。もはや実装というより思想である。さて、作ったは良いけど実装をしている暇がない。どうしたものか?
「あれ、私の出番無し?」
そーです。次回、MVの記事を書く予定だからそれまで待ってくれ。

![FireShot Capture 003 - MainPage - Laravel - [127.0.0.1].png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F15020%2Fd79ceaad-366c-41bc-8b0a-22329a9dc2b7.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=eb7f85a1c07feaa33b1e130867c4553b)