スライド
スライドは slides/ の中の 1 ファイルです。名前はセクションの id、ルート要素は <section class="slide"> ひとつ。スタイルはテーマが定義するクラスだけで付けます。
<section class="slide" data-layout="two-col">
<h2 class="slide-title">script.md が親</h2>
<div class="col">
<p class="node">script.md</p>
<p class="node node-parent" data-step="script-parent">script.md ← 親</p>
</div>
<div class="col" data-step="slides-hang">
<p class="node">intro.html</p>
<p class="node">architecture.html</p>
</div>
</section>ルール
- ルートはひとつ。 ファイルは
<section class="slide">のフラグメントです。ひとつもなければ何も描かれず(DEK007)、2 つ目以降は捨てられます(DEK009)。id はファイル名から決まり、data-slugはdekc buildが注入します。自分で書く場合はセクション id と一致させてください(DEK006)。 - 書き方は自由。 終了タグを閉じても省いても、属性を引用符で囲んでも囲まなくても、正しい HTML5 なら受け付けます。
<html>と<body>で包んだ完全な文書でも構いません。minify はビルド時に一括で行います。 - レイアウトは
data-layoutで選ぶ。 同梱テーマにはtitle、default、two-col、full-bleed、quoteがあります。テーマにもそのスライドの CSS にも定義のないレイアウトはDEK019です。defaultは上詰めなので、ビートで要素が増えても見出しの位置が動きません。動画にしたとき、見出しが枚ごとに上下しないようにするためです。 - キャンバスは 1280 × 720。
4:3のデッキは 1024 × 768 です。プレイヤーがスライド全体をtransform: scale()でビューポートに合わせます。 - クラスはテーマのものか、その枚のものだけ。 テーマにも、その枚の
slides/<id>.cssにもないクラスはDEK010。スライド内の<style>、style=属性、<script>、onclick=などのイベントハンドラ、スクリプトが動く URL(javascript:、vbscript:、HTML を入れたdata:)はDEK011です。 - 見た目はトークンで変える。 色、書体、余白、動きは、テーマかその枚のスタイルシートの
var(--*)から取ります。生の値は書きません。 - スクリプトはスライドの横に置く。中には書かない。 CSS で表せない動きは
slides/<id>.tsに書きます。スクリプトで動かすを参照してください。 - デッキの中で完結する。 画像は
assets/name.pngの形で参照し、../は使いません。リモート URL はDEK020、存在しないファイルはDEK021、デッキの外に出るパスはDEK022、assets/で始まらないローカルのファイルはDEK023です。srcset、poster、<video>・<audio>・<source>・<track>・<iframe>の参照先も<img src>と同じように検査します。
文書の殻、台本の frontmatter から来る lang 属性、プレイヤーはレンダラが付け足します。確認は開発サーバか、次のコマンドで行います。
dekc check architecture --shot骨格
dekc sync と、保存のたびに動く開発サーバは、HTML のないセクションに骨格を生成します。骨格は空ファイルではありません。見出しの文言を <h2> に入れ、ビートを data-step で結んだリストにしたものです。
<section class="slide" data-layout="default">
<h2 class="slide-title"></h2>
<ul>
<li data-step="script-parent">script.md が親</li>
<li data-step="slides-hang">スライドがぶら下がる</li>
<li data-step="3">id のないビート</li>
</ul>
</section>ビートのないセクションは data-layout="title"、あれば default です。どちらも、デッキの theme.css がそのレイアウトを持つときだけ使います。持たなければ骨格はレイアウトを指定しないので、新しいデッキはどのテーマでも lint を通ります。id のあるビートは id で、ないビートは 1 始まりの位置で結ばれます。
## recap のように id だけの見出しには表示する文言がないので、骨格の <h2> は空です。例外は先頭のセクションで、デッキの title が入ります。英語のスラッグが、投影するスライドにうっかり出てしまうのを防ぐためです。空の見出しは lint が DEK024 で警告します。文言を出したいなら ## まとめ {#recap} と書いてください。
sync は、あなたが手を入れたスライドには一切触れません。台本にビートを足しても、すでに書いた HTML は更新されません。紐付けは data-step が受け持ちます。骨格はビートの id を使うので、HTML を手で書き始める前にビートへ {#id} を付けておけば、あとからビートを挿入しても、スライドとの対応がずれることはありません。id のあるビートを手書きの数字で指すと DEK025 の警告になり、hint がその id を示します。
まだ誰も手を入れていない骨格は別です。それは sync が書いたままのファイルなので、台本が変われば sync が書き直します。デッキの title を変えたりビートを足したりすると、手つかずの骨格はそれに追従します。ファイルに一度でも手を入れれば、見出しを打ち直しただけでも、それ以降は書き直しません。dekc sync はこうしたファイルを (updated) として表示します。
骨格に手が入っていないことを sync が知っているのは、自分が書いたバイト列を、デッキの .cache/skeletons にハッシュとして覚えているからです。ファイルの形からは判断できません。見出しを打ち直しても形は変わらないからです。この記録は .cache/ のほかのものと同じくキャッシュです。消えても、sync がいま書くはずの骨格とバイト単位で同じスライドは sync のものとみなし、それ以外はすべてあなたのものとして残します。失うのは自動の書き直しだけで、あなたの編集は失われません。
スライドごとの CSS
1 枚でしか使わない装飾は、共有の語彙に入れません。HTML の横の slides/<id>.css に置きます。
/* slides/usb.css */
.slide { --mark-size: 96px; }
.usb-mark { width: var(--mark-size); color: var(--accent); }
.slide.is-current .usb-mark { animation: pop var(--step-transition); }
@keyframes pop { from { transform: scale(0.9); } }レンダラは、すべてのルールをその枚だけに効くように書き換えます。.usb-mark は .slide:where([data-slug="usb"]) .usb-mark に、先頭の .slide は .slide:where([data-slug="usb"]) になります。pop も改名されるので、別の枚の pop とは衝突しません。スコープが足す詳細度は .slide ひとつ分だけなので、ここに書いたルールは theme.css の末尾に書いたのと同じ強さで効きます。テーマの .slide .x には勝ち、レイアウトの .slide[data-layout="split"] .x やビートの状態 .slide.is-current [data-step] のような、より詳細なテーマのルールには負けます。それらを上書きしたいときは、同じセレクタをここに書いてください。
pop には from しか書いていません。.usb-mark のルールが終わりの状態で、アニメーションは別の状態から始まってそこへ着きます。入りのアニメーションをこう書けば、アニメーションが走らない場所では完成したスライドが見えます。スライド一覧のサムネイルと発表者ビューのプレビューは .is-current を付けた複製なので、そこでも一度再生されて同じ状態に落ち着きます。逆に to に完成形を書くと、forwards に頼ることになり、アニメーションが走らなければ完成形になりません。
テーマと同じ規則も適用されます。値はトークンから取ります(DEK014)。この枚でしか使わない値は、上の --mark-size のように、この枚のトークンにして構いません。スライドのスタイルシートで出た DEK014 の hint も、その書き方を案内します。ここで定義したクラスは、この枚でだけ定義済みとみなされ(DEK010)、max_classes には数えません(DEK013)。スライドの外まで届くルールは theme.css に置きます(DEK012)。::view-transition-*、@font-face、@import、それにスライドの中では決して当たらない :root・html・body です。url() はスライドの HTML と同じ規則に従い、デッキからの相対で assets/... と書き、リモートは使えません(DEK020、DEK023)。dekc mv はスタイルシートも HTML と一緒に動かします。対応するセクションのないスタイルシートは DEK002 です。同じクラスが何枚にも出てきたら、theme.css に移してください。
密度はテーマが決める
1 枚にどれだけ載せられるかは、theme.css のフォントサイズと余白が決めます。字数の上限のようなルールはありません。文字を大きく取っておけば、詰め込めばすぐにキャンバスからはみ出し、dekc lint --visual がそれを測って DEK030 として報告します。判定は幾何で決まるので、好みの問題になりません。もっと詰めたいなら、テーマの文字を小さくしてください。その判断は差分に残り、レビューできます。
次
喋りに合わせて要素を現し、要素を次の枚へ連れていく → ビート