Skip to content

チュートリアル ​

このチュートリアルでは、短いトークを一本、ゼロから作ります。題材は「バグだと思ったら設計の問題だった」という 10 分のライトニングトーク。終わるころには、ビート付きの台本、喋りに合わせて要素が現れる手書きのスライド、2 枚をまたいで移動する図、ルールの内側で済ませたテーマ変更、そして USB メモリから発表できる HTML ファイルが手元にあります。

どの手順の終わりでも、そこで止めて発表できます。これは意図した設計です。dek は台本だけで足りるように作られていて、そのあとの手順はどれも、やってもやらなくてもよい仕上げです。

必要なのは Bun 1.4 以上だけ。声、動画、Playwright はここでは使いません。

1. プロジェクトを作る ​

bash
bunx @hajimism/dek init lightning --deck postmortem
cd lightning
bun add -d @hajimism/dek
cd decks/postmortem

これは init が終わりに表示する手順そのものです。以降、dekc と書いたら bunx dekc、つまりプロジェクトに入れた dek のことです。

2. 台本を書く ​

script.md の中身をトークで置き換えます。声に出して言うとおりに書いてください。スライドのことはまだ考えません。

markdown
---
# yaml-language-server: $schema=../../.dek/schema.json
title: バグだと思ったら設計だった
event: Lightning Talks
date: 2026-05-14
duration: 10m
---

## intro

先月、見つけるのに 3 日かかったバグを出しました。
なぜ 3 日かかったのかを話します。理由はコードではなかったからです。

> ゆっくり。最初の一文を落ち着かせる。

## 何が見えたか {#symptom}

ある地域のユーザーだけ、古い価格が見えていました。間違った価格ではなく、古い価格。
毎回 5 分遅れで、そこだけ。

## どこを見たか {#search}

当然の場所を、当然の順番で見ました。

### キャッシュ {#cache}

まずキャッシュ。問題なし。

### キュー {#queue}

次にキュー。これも問題なし。

### 時計 {#clock}

そして、あるホストの時計。5 分遅れていました。

## なぜ 3 日かかったか {#cause}

時計がバグでした。でも 3 日かかった理由は、
どのホストがそのリクエストを処理したのかを、システムのどこも教えてくれなかったことです。
それはバグではありません。設計です。

## 何を変えたか {#fix}

時計を先に直しませんでした。すべてのレスポンスに「どこから来たか」を書かせました。
時計はそのあと 10 分で直りました。

## 持ち帰ってほしいこと {#close}

バグが見つからないとき、システムが何を言わないでいるかを問いましょう。

いくつか見てほしいところがあります。

  • ## intro はそのまま id として通るので {#...} が要りません。他の見出しには日本語が入るので、それぞれ明示的な {#id} を付けています。id は HTML のファイル名になり、見出しの文言は観客と発表者ビューが見るものです。
  • ## どこを見たか の下の ### が ビート です。喋りを 3 つの瞬間に区切ります。いまはまだ画面には何も起きません。それで構いません。
  • 引用は自分へのト書きです。声にならず、尺に数えられず、観客にも見えません。

3. 開発サーバを起動する ​

bash
dekc

URL が表示されるので開きます。スライドは 6 枚。どれも見出しから生成されたもので、1 枚目はデッキのタイトル、他は見出しの文言、search は 3 つのビートを列挙しています。

右矢印を押してください。search では 3 つのビートがひとつずつ現れてから、次の枚に進みます。p を押すと発表者ビューになり、いまのセクションの台本が表示され、いまのビートがハイライトされ、最初に送った瞬間から時計が動きます。

slides/search.html を見てみましょう。サーバがあなたの代わりに書いたものです。

html
<section class="slide" data-layout="default">
  <h2 class="slide-title">どこを見たか</h2>
  <ul>
    <li data-step="cache">キャッシュ</li>
    <li data-step="queue">キュー</li>
    <li data-step="clock">時計</li>
  </ul>
</section>

各項目は data-step でビートを id で指しています。あるビートまで進むと、プレイヤーはそのビートとそれ以前に紐づく要素すべてを「表示済み」としてマークします。表示済みがどう見えるかはテーマが決めます。

ここで止めてもいい

dekc build を叩けば発表できるデッキがあります。ここから先は、台本に書いた以上のことを画面で伝えるための作業です。

4. 尺を確かめる ​

別の端末で、デッキの中から次を実行します。

bash
dekc ls

duration から来る予算、字数から来る見積もり、セクションごとの按分が出ます。dek は CJK を 300 字/分、それ以外を 130 語/分で見積もります。引用は数えません。このチュートリアルの台本は 1 分ほどで読み終わるので、dekc ls の最後に 1 diagnostic と出ます。中身は dekc lint や開発サーバが示す「10 分の予算に足りない」という DEK041 の警告です。それがこの警告の役目で、スライドではなく台本を書き足す合図です。エラーではなく警告なので、lint は通ります。声に出して言うつもりのことは、ファイルに書いてはじめて数に入ります。

5. 1 枚を手で書く ​

cause はこのトークでいちばん大事な枚です。ちゃんとしたレイアウトにしましょう。slides/cause.html を開いて骨格を置き換えます。

html
<section class="slide" data-layout="two-col">
  <h2 class="slide-title">時計がバグで、沈黙が設計だった。</h2>
  <div class="col">
    <p class="node">cache</p>
    <p class="node">queue</p>
    <p class="node node-parent">clock: −5 min</p>
  </div>
  <div class="col">
    <p class="node">response</p>
    <p class="node node-parent">served-by: ???</p>
  </div>
</section>

保存します。ブラウザはこの 1 枚だけを差し替えます。使ったクラスはすべて同梱テーマにあるものです。slide-title、col、node、node-parent。試しにテーマにないクラス、たとえば class="node highlight" を足して保存してみてください。端末とブラウザのオーバーレイの両方が DEK010 を報告します。theme.css にそのクラスがない、と。消せば診断も消えます。

これがループです。書く、保存する、診断を読む、直す。開発サーバは保存のたびに lint を走らせ、「診断なし」は測れる問題が残っていないことを意味します。

6. 喋りに合わせて現す ​

cause にはまだビートがないので、両カラムが同時に出ます。「システムのどこも教えてくれなかった」と言う瞬間に右カラムが現れるよう、台本にビートを足します。

script.md の cause セクションを編集します。

markdown
## なぜ 3 日かかったか {#cause}

時計がバグでした。でも 3 日かかった理由は、別のところにあります。

### システムが知っていたこと {#knew}

キャッシュは問題なし、キューも問題なし、ひとつの時計が遅い。それは知っていました。

### システムが言わなかったこと {#silent}

でも、どのホストがそのリクエストを処理したのかは、どこも教えてくれなかった。
それはバグではありません。設計です。

次に slides/cause.html でカラムをビートに結びます。

html
<section class="slide" data-layout="two-col">
  <h2 class="slide-title">時計がバグで、沈黙が設計だった。</h2>
  <div class="col" data-step="knew">
    <p class="node">cache</p>
    <p class="node">queue</p>
    <p class="node node-parent">clock: −5 min</p>
  </div>
  <div class="col" data-step="silent">
    <p class="node">response</p>
    <p class="node node-parent">served-by: ???</p>
  </div>
</section>

この枚を送ってみてください。最初のビートで左カラム、次のビートで右カラムが現れます。いつ 出すかは台本が、どう 出すかはテーマが決めます。同梱テーマは要素をフェードしながら少し持ち上げて置き、display: none ではなく opacity で隠すので、ビートが進んでもレイアウトは動きません。

ビートは番号ではなく id で指しました。あとで途中にビートを挿しても、ここの対応はずれません。dekc sync の骨格も同じ id を使うので、HTML を書き始める前にビートへ {#id} を付けておく価値があります。

7. 図を次の枚へ連れていく ​

fix の枚では、cause の served-by のノードを引き継いで、答えに変えたい。両方の枚で同じ data-morph 名を要素に付けると、遷移の間にブラウザが位置とサイズを補間します。

slides/cause.html の最後のノードを変えます。

html
<p class="node node-parent" data-morph="served-by">served-by: ???</p>

slides/fix.html を置き換えます。

html
<section class="slide" data-layout="default">
  <h2 class="slide-title">すべてのレスポンスに出自を書かせる</h2>
  <p class="node node-parent" data-morph="served-by">served-by: host-07</p>
  <p class="node">そのあとで時計を直す。10 分。</p>
</section>

cause から fix へ送ってください。served-by の箱がフェードアウトして再登場するのではなく、右カラムから新しい位置へ滑っていきます。アニメーションのコードは一行も書いていません。data-morph が view-transition-name になり、残りはブラウザの View Transitions API が処理します。

Playwright が入っていれば、遷移を途中で止めて動きを確かめられます。

bash
dekc shot cause --to fix --at 0.5

8. ルールの内側で見た目を変える ​

既定のテーマは暗い配色です。このデッキは暖色にしましょう。デッキの中の theme.css(プロジェクト直下のものではありません)を開き、.slide ブロックのトークンを 3 つ変えます。

css
.slide {
  --fg: #2b1d12;
  --bg: #f6efe6;
  --accent: #b5471f;
  /* 他のトークンはそのまま */
}

保存すると、全スライドが新しい配色で描き直されます。ファイルの他の場所は一切触っていません。テーマの中の色がすべて var(--fg)、var(--accent) のように書かれているからです。

今度はずるをしてみます。ルールに生の色を書いてください。

css
.slide .node-parent {
  border-color: #ff0000;
}

保存すると lint が DEK014 を報告します。トークンへの代入の外に生の値がある、と。生の色、フォント名、絶対単位は --* カスタムプロパティへの代入にだけ書けます。それ以外はすべて var() を通します。var(--accent) に戻せば、デッキは再びクリーンです。

このデッキのテーマは、このデッキだけのコピーです。プロジェクト直下の theme.css も、他のデッキも変わっていません。結果が気に入ったら、プロジェクト直下へ昇格させます。

bash
cp theme.css ../../theme.css

次の dekc new は暖色の配色から始まります。

9. 発表に使うファイルを作る ​

bash
dekc build

dist/postmortem.html ができます。全スライド、テーマ、プレイヤーのランタイム、画像がすべて minify された 1 ファイルにまとめられています。ブラウザで開いてください。矢印キーでビートとスライドを進めます。p で発表者ビュー。同じファイルを別ウィンドウでも開くと、2 つは BroadcastChannel で追従します。観客ビューをプロジェクタに、発表者ビューを手元のノート PC に。サーバもネットワークも要りません。

その 1 ファイルを USB メモリにコピーする。それがトークです。

この先 ​

dek の中心になる機能をすべて使いました。順序と尺を持つ台本、1 スライド 1 HTML、id で結んだビート、枚をまたぐモーフ、トークンだけのテーマ、測れるものをすべて測る lint、単一ファイルのビルド。

MIT License