台本
script.md が持つのは 3 つだけです。トークの順序、喋る言葉、そして持ち時間。レイアウトや装飾はスライドの HTML に、声は voice/ に属します。台本にはどちらも書きません。
3 つのルール
覚えるルールは 3 つです。## の見出しが 1 枚。その下に書いたものがその枚の台本。喋りになるのは段落だけ。
意味を持つ見出しは ## と ###(後述のビート)だけです。# や #### の見出しは台本の本文として読まれ、lint が DEK044 で警告します。コードフェンスや HTML コメントの中の見出しも本文です。Markdown についての発表でも、コードブロックの中に ## 見出し と書けます。
---
# yaml-language-server: $schema=../../.dek/schema.json
title: HTML スライドツールを作った話
event: Tokyo Frontend Meetup #42
date: 2026-04-18
duration: 20m
---
## intro
こんにちは。今日は、スライドツールを自分で作った話をします。
> 自己紹介は短く。時計を見ない。
## 発表の前日に何をしていますか {#problem}
みなさん、発表の前日に何をしていますか。
聴衆が「自分ごと」だと思うまで喋る。3 つ目が本命。
## architecture
さて、ここが今日いちばん覚えて帰ってほしいところです。
### script.md が親 {#script-parent}
まず script.md がいて、
### スライドがぶら下がる {#slides-hang}
その下にスライドがぶら下がっている。逆ではありません。見出しの文言は自由です。日本語でも、疑問文でも、句読点が入っても構いません。発表者ビューは各セクションの Markdown を、段落内の改行だけ詰めてそのまま表示します。
声になるのは段落だけです。引用、リスト、コードブロック、表は画面用かト書きで、合成の対象になりません。インラインの強調、リンク、code は合成の前に装飾を外してプレーンテキストになります。これらはライブの発表には一切影響せず、意味を持つのは dekc cues を叩くか声を付けたときだけです。リストはあるのに段落がないビートは、画面には出るのにナレーションでは一瞬で過ぎます。dekc cues と、voice/ のあるデッキの lint がそれを DEK042 で知らせます。
ト書きには引用を使ってください。ナレーションを付けたとき、これは守る価値のある規約になります。dekc build --public でビルドすると、発表者ビューから引用と HTML コメントが外されます(Web で公開する)。dek には「短い命令文を検出する」のような曖昧なト書き判定も、間を取るための特別な記法もありません。ナレーションのタイミング調整は voice/voice.toml に書きます。タイミングを参照してください。
見出しと id
slides/ のファイル名と CLI の <slug> 引数が使うのはセクションの id、発表者ビューが使うのは見出しの 文言 です。id は [a-z0-9-]+ にマッチし、英字を 1 文字以上含みます。数字だけの id は数値の data-step と衝突するので受け付けません。
表示と同一性は Pandoc 流の {#id} で分けます。
- 見出しがそのまま id として通るなら、それが id です。
## introはslides/intro.htmlになります。 - そうでなければ
{#id}が必須です。## 発表の前日に何をしていますか {#problem}はslides/problem.htmlになります。付け忘れは行番号付きのエラー(DEK027)になり、直し方も示されます。lint は、そうした見出しを 1 回の実行ですべて報告します。見出しに英数字の語があればそこから id を組み立てて## Why dek? {#why-dek}のように、なければ## まとめ {#your-id}のように示します。 - id として通る見出しにも
{#id}は付けられます。表示名とファイル名を分けたいときに使います。## intro {#opening}は「intro」と表示され、opening.htmlに保存されます。 - id だけの見出しには表示する文言がありません。生成される骨格の
<h2>は空になります。例外は先頭のセクションで、デッキのtitleが入ります。発表者ビューには id が出ます。
対応する属性は {#id} だけです。{.class} や key=value は拒否されます。セクションの id はデッキ内で一意、ビートの id はセクション内で一意でなければなりません。
改名と並べ替え
dekc sync はファイルをリネームしません。## problem を ## the-problem に書き換えると、サーバは the-problem の骨格を新しく生成します。古い problem.html が手付かずの骨格のままで、横に problem.css も problem.ts もなければ、台本から書き直せるものしか入っていないので sync が消します。dekc init の後に自分の台本を書くと、お手本のスライドが片付くのもこのためです。手を入れた problem.html は残り、孤児(DEK002)になります。紐付けが切れるだけで、中身は移りません。
同一性を付け替える操作はミスが起きやすいので、CLI に任せます。
dekc mv problem the-problem
dekc mv architecture --after intro前者は script.md の id を書き換え、slides/problem.html と、あれば problem.css と problem.ts をリネームし、data-slug と voice/voice.toml の該当キーも書き換えます。見出しの文言には触れず、宛先のファイルがひとつでもあれば実行を拒みます。すべてのファイルが変わるか、どれも変わらないかのどちらかです。後者は台本の中でセクションを動かします。HTML ファイルは順序を持たないので、その場に留まります。
見出しを先に書き換えても、ファイル名を先に変えても、あとから dekc mv を実行すればかまいません。どちらを先にしても、残りを済ませて改名を終えます。script.md がすでに新しい id になっていれば、dekc mv problem the-problem はファイルだけを動かします。ファイルがすでに新しい id になっていれば、見出しだけを書き換え、残ったファイルを動かします。開発サーバが保存時に生成した骨格がどちらの id にあっても、あなたが書いたスライドが優先されます。実行を拒むのは、あなたが書いたスライドが 2 つの id の両方にあるときだけで、その場合は一つにまとめるよう案内します。
lint が「セクションのない HTML(DEK002)」を 1 件と、自分の HTML を持たないセクションを 1 件だけ見つけたときは、改名だと推定します。後者は HTML がない(DEK001)か、生成された骨格のままのセクションです。見出しとファイルのどちらを改名したのかはあなたにしか分からないので、hint は両方を示します。台本の id にファイルを合わせる dekc mv problem the-problem と、ファイルの id にセクションを合わせる dekc mv the-problem problem です。どちらも書いてあるとおりに動きます。開発サーバを動かしたままセクションを足したときのように候補が 2 件以上あるときは、どれか 1 つを選びません。hint は dekc mv problem the-problem や dekc mv problem qa のように候補ごとの dekc mv を並べ、スライドの削除は勧めません。
ビート
## が 1 枚なら、### はその中の ビート です。喋りの区切りであり、画面が進んでもよい瞬間です。文言は自由で、発表者ビューの見出しになります。
本番で右矢印を押すと、まずいまの枚のビートが進み、使い切ると次の枚へ移ります。ビートに対応する要素が HTML になくても構いません。画面はそのまま、喋りだけが区切られる場所として使えます。
枚は、どのビートよりも先に出ます。## と最初の ### のあいだの段落は枚が出たところで喋り、このときビートに結んだ要素はまだ見えていません。そこから 1 回送るごとに次の ### に進むので、最初のビートも含め、どのビートも同じように自分に結ばれた要素を出します。### のない枚は、出たところだけの枚です。motion では、枚が出たところを 0、各ビートをその id か番号で呼びます。ビートがなければ data-step で結ぶ先はなく、そこに書いた data-step は DEK003 です。
いつ 出すかは喋りの決定なので台本が持ち、どう 出すかは見せ方の決定なので theme.css が持ちます。HTML 側の書き方はビートにあります。
尺
duration: 20m はこのトークの予算です。dek は本文から所要時間を見積もります。CJK は 300 字/分、それ以外は 130 語/分。引用はト書きなので数えません。どちらの速度も dek.toml で変えられます。
dekc ls は予算、見積もり、セクションごとの内訳を出します。各セクションの予算は、本文の字数比で duration を按分したものです。duration がなければ見積もりだけが出ます。声を合成して Timeline があるときは、実際のナレーションの長さが見積もりの隣に並びます。並べて見せますが、同一視はしません。
デモが長く台本が短い枚は、見積もりが短く出ます。デモの間に喋るつもりなら、その言葉を書いてください。書けば数に入ります。無音の時間を表す記法は、台本にも設定にもありません。
event と date は dekc ls に表示されます。スライドに自動で入ることはないので、見せたいならタイトルスライドの HTML に書いてください。