コンテンツにスキップ

Playground

ブラウザーでスライドデッキを書くと、スライドがすぐに追従します。WebAssembly にコンパイルされた go-slides で、補完、ヘルプ、サンプル付きです。

Playground を開く →

Playground は go-slides v0.20.2 そのものを WebAssembly にコンパイルし、 ブラウザー内で動かしたものです。左側にスライドデッキを入力すると、右側にスライドが追従して表示されます。 スライドデッキも共有リンクも、サーバーには何も送信されません。

Playground 自体の画面(リボン、ヘルプ、メッセージ)は、ページの言語で表示されます。 日本語なら /ja/playground/ を開いてください。このサイトの 12 言語すべて同じです。 ページの言語セレクターで切り替えられ、選択はこのブラウザーに保存されます。言語を指定したリンクが 常に優先されます。サンプルのデッキは英語のままです。ウクライナ語、ロシア語、中国語、日本語、韓国語は、 その言語のときだけページがダウンロードする Noto Sans のサブセット(0.06〜2.3 MiB)で描画されます。

主な機能

  • 各スライドの ライブプレビュー。ページのスレッドとは別(Web Worker)でレンダリングされるので、入力が待たされることはありません。スライドをクリックすると、エディターが その行に移動します。キャレットを動かすと、プレビューがそのスライドまでスクロールします。

  • スライドショー:キーボード操作、画面上のコントローラー、トランジションを備えた、 プレゼンテーションそのものです。

  • 発表者ビュー:Present(スライドショーでは p)を押すと、2 つ目のウィンドウで開きます。 現在のスライド、次のステップ、スピーカーノート(スライドデッキの <!-- comments -->)、時計、タイマーが表示されます。矢印キー、Space、 Home、End はどちらのウィンドウでも使え、互いに連動します。スライドデッキを編集したときも 連動します。ウィンドウが開かない場合は、このサイトのポップアップを許可してください。 一覧表示(o)は、ダウンロードしたページでのみ使えます。

  • 入力中の 補完:ディレクティブのキー(コメント内ではスポットディレクティブの _ 付きのものも)、 kind、theme、size、paginate の値、そして {{ }} 内のテンプレート関数と データのフィールド。

  • キャレット位置にあるものの ヘルプ:ディレクティブ、kind(スライドの種類。何を設定するか)、 テンプレート関数。ヘルプペインからは、このドキュメントの各ページにもリンクしています。 v0.16.0 以降、ディレクティブのヘルプは画面の言語に従い、11 言語に対応しています。

  • 該当行に表示される 問題:テンプレート、YAML、HCL のエラーはエディター内でハイライトされ、 エディターの下に一覧表示されます。プレビューには、最後に正しくレンダリングできたスライドデッキが 表示されたままになります。

  • サンプル:ウェルカム用のスライドデッキ、スライドを生成するテンプレート、スライドの kind、 HCL のフロントマター、テーマとスポットディレクティブ、そして数式、画像、 背景(![bg]、分割背景の ![bg left:40%]、フィルター)。

  • ファイル:エディターの左にあるパネルはスライドデッキのプロジェクトで、 コマンド や VS Code 拡張機能 が読み込むのと同じ構成になっています:deck.md、 slides.yaml、themes/、kinds/、media/。

    • ファイルをクリックすると編集できます。エディターは言語 (Markdown、YAML、HCL、JSON、CSS)に応じて色付けし、問題箇所に印を付けます。
    • 右クリック(または Shift+F10)で、New File、New Folder、Rename(F2)、 Delete(確認あり)、New theme / New kind を使えます。ファイルをフォルダーにドラッグすると 移動できます。キーボード操作は WAI-ARIA のツリーパターンに従い、先行入力による検索にも 対応しています。
    • Project ▸ New theme は themes/my-gaia.css(または default、 uncover をもとにしたもの)を作成します。内容は組み込みテーマの @import と、追加したルールです。 作成したテーマは Theme の一覧に加わります。New kind と New data file も テンプレートから始まります。いずれも slides.yaml に登録されるので、slides build deck.md で見つかります。
    • Project ▸ Download project (.zip) ですべてを保存できます。展開すれば、 slides build deck.md でビルドできます。Open project では .zip または フォルダーを読み込めます。フォルダーの外に出るアーカイブ(..、絶対パス)、 256 個を超えるファイルや 8 MiB を超えるファイルを含むアーカイブ、展開後のサイズが 100 倍を超えるアーカイブは拒否されます。
    • すべては下書きと一緒に、このブラウザー内に保存されます。プロジェクトの容量は 最大 64 MiB で、ファイル一覧の下の行に使用量が表示されます。
  • メディア:画像、動画、音声をエディターにドロップまたは貼り付けると、 media/ に保存され、スライドデッキにその参照が書き込まれます:![](media/photo.png)。パネルのフォルダーに ファイルをドロップすると、そのフォルダーに保存されます。スライドデッキは小さく読みやすいままで、 何もアップロードされません。プレビューのサンドボックスは、制限を緩めることなくメディアを読み込みます (ページがバイト列を渡します)。Save as ▸ HTML page では、メディアがページに埋め込まれます。https: の画像も使えますが、ブラウザーが そのサーバーから取得するため、サーバー側にはあなたのアドレスが伝わります。 プレビューはリファラーを送信しません。

  • サイズ変更可能なペイン:ファイルパネル、エディター、スライドのサムネイル、 プレビュー、ヘルプは、ドラッグできるバーで区切られています(バーの上ではポインターが サイズ変更カーソルになります)。バーの隣のペインが広さを取り、 ほかのペインはサイズを保ちます。バーをダブルクリックするか、バー上で Enter を押すと、 ペインを閉じたり元に戻したりできます。キーボードでは、F6 でバー間を移動し、 矢印キーで 16 px ずつ動かし、Home と End でバーの前のペインを最小・最大にし、Escape でエディターに戻ります。 View タブではこれまでどおりペインを非表示にできます。設定したサイズは下書きと一緒に このブラウザーに保存されます。デフォルトのサイズ(190、168、280 px で、残りをエディターと プレビューが 6 対 5 で分け合う)は保存されません。

  • ペインを閉じる:各ペインのヘッダーには、ツールチップ付きの小さな × ボタンが あります。ほかのペインがその場所を分け合い、ペインは元の幅で戻ります。再び開くには、 View タブにあるそのペインのトグル(すべてのペインにあります)を使います。 エディターとプレビューは それぞれ閉じられますが、両方同時には閉じられません。最後の 1 つは閉じるのを拒み、 ボタンは無効表示になり、ツールチップが理由を説明します。キーボードでは、F6 を押してから Tab または Shift+Tab で × ボタンへ移動し、Enter または Space でペインを閉じると、 キーボードはエディターに戻ります。開いているペインはサイズと一緒にこのブラウザーに 保存されます(作業のために開く Versions、GitHub、テーマエディターは閉じた状態で始まります)。

  • 書式:Format タブで Markdown を編集でき、1 回押すごとに 元に戻す(Undo)の 1 ステップになります。

    • テキスト:Bold、Italic、Strikethrough、Inline code は、選択範囲 またはキャレット位置の単語に適用され、オン・オフが切り替わります(Ctrl+B、Ctrl+I、Ctrl+Shift+X、 Ctrl+E。Mac では Cmd)。キャレットが書式の記号の内側にあると、ボタンが押された状態で表示されます。 Markdown には下線がないため、Underline(Ctrl+U)はテキストを <u>…</u> で囲みます。このタグは Marp のデフォルトの HTML 許可リストで残されるので、 生の HTML がオフでも機能します。
    • 段落:見出し 1〜3(Ctrl+Alt+1..3)、箇条書き(Ctrl+Shift+8)、 番号付きリスト(Ctrl+Shift+7)、引用は、選択した行に適用され、オン・オフが切り替わります。 水平線は <hr> タグです:---、***、___ は、Marp ではいずれも 新しいスライドの開始になってしまうためです。
    • 表:グリッドで列数と行数を選びます。表の中にキャレットがあるときは、 行や列を追加・削除したり、列の配置(:--、:-:、 --:)を設定したりできます。編集のたびに、表は整形し直されます。
    • スライドのテキスト の左揃え、中央揃え、右揃えは、現在のスライドに <style scoped> ブロックを 書き込みます。Marp には配置の構文がなく、style 属性はデフォルトの HTML 許可リストを 通りませんが、scoped ブロックは通ります。そのため、生の HTML がオフでも機能し、 プレビュー、HTML ページ、PDF に反映されます。
    • リンク(Ctrl+K)は、url を選択した状態で [text](url) を書き込みます。
  • フロントマターのキーを、どの深さでも ハイライト します。YAML( {a: 1} 形式のマッピングも含む)と HCL に対応しています。

  • テーマ の選択:default、gaia、uncover、プロジェクトのテーマ (themes/*.css)、スライドデッキ内で定義したテーマ(<style> 内の /* @theme name */)から選べます。選択すると、YAML または HCL のフロントマターに theme: が 書き込まれるので、共有リンクにも反映されます。フロントマターを編集すると、 選択もそれに追従します。

  • 入力中もプレビューは 表示位置を保ちます:変更されたスライドだけが置き換えられ、 テーマを変更してもプレビューは同じスライドで開き直されます。

  • 共有リンク:スライドデッキはリンク自体(# 以降の部分に 圧縮して)に含まれるので、リンクを開けばスライドデッキが開きます。リンクで運べるのは 圧縮後 64 KiB までで、スライドデッキだけです。プロジェクトにほかのもの (テーマ、kind、メディア)が含まれる場合は、Share がその旨を伝え、.zip を提案します。

  • Save as:

    • HTML ページ(slides deck.md が書き出すものと同じ)
    • PDF(ベクター、テキスト選択可、アウトライン付き)
    • 編集可能な PowerPoint または OpenDocument のスライドデッキ

    これらは、slides --pdf、 --pptx、--odp と同じコードによってブラウザー内で作成されます。100 枚のベンチマーク用スライドデッキの PDF は、 コマンドで作成したものとバイト単位で同一です。最初のエクスポート時には、エクスポート エンジン(約 5 MiB。一度だけで、次の更新までブラウザーに保持されます)が、 進捗表示付きでダウンロードされ、届きながらコンパイルされます。その後は、スライドが使うフォントだけを ダウンロードします。3 MB/s の回線では、ウェルカムデッキの最初の PDF が 3 秒未満で仕上がります。その後、100 枚のスライドデッキは約 3 秒で書き出せます。 https: の画像は、そのサーバーが許可している場合(CORS)にだけ含まれます。data: の 画像は常に含まれます。

  • 下書きは保持されます:

    • スライドデッキは入力に合わせてこのブラウザーに保存され(IndexedDB、このサイト専用)、 再読み込みしても戻ってきます。どこにも何も送信されません。 プロジェクトのテキストファイル(テーマ、kind、データ、slides.yaml)も同じように保存され、 入力直後にタブを閉じても失われません。メディアはドロップした時点で保存されます。
    • 共有リンクを開くとそのスライドデッキが開きますが、あなたの下書きは保持されます:Draft ▸ Restore my draft で元に戻せます。
    • サンプルを開いても、Draft ▸ Reset to the example(確認あり)を実行しても、 別のタブで作業しても、下書きは消えません:Draft ▸ Restore replaced で 元に戻せます。
    • Draft ▸ Forget my drafts は、保存されているものをすべて消去します。

どのエクスポートも、プレビューに表示されているプロジェクト(slides.yaml、 テーマ、kind、データファイル、メディア)をレンダリングし、メディアはドキュメント内に埋め込まれます。

ファイルとしての画像(slides の --images)はブラウザーでは作成できません。 コマンド または VS Code 拡張機能 を使ってください。

テーマエディター

ホーム ▸ 外観 ▸ テーマエディターは、プロジェクトのテーマの 1 つをコントロールで編集するペインを開き、プレビューが追従します。テーマはパッケージのフォルダー theme-src/<name>/ として保持され、プレビューとエクスポートが読むシート themes/<name>.css はそこからコンパイルされます。そのため、見えているものがそのままエクスポートされます。インポートしたテーマパッケージ(ペインのインポート…、メディアを追加…、またはドロップ)はファイルをそこに保持するので、編集できます。

  • パレット: 背景、テキスト、見出し、アクセント、リンクの色。色を選ぶか、入力します(#1a2b3c、rgb()、hsl()、または名前)。
  • タイポグラフィ: 本文、見出し、コードのフォントと、そのサイズと太さ。フォントは汎用のものと一般的なもの、そして追加したものです(フォントを追加…: .woff2、.woff、.ttf、.otf)。
  • ロゴ: 画像(.svg、.png)、置く場所(隅、または背景全体)、サイズ。ページ番号とフッター: ページ番号の位置、サイズ、配置。
  • 詳細: theme.hcl に書かれる内容。バージョン、説明、作者、ライセンス、ホームページ、ベースのテーマ(extends)、必要な go-slides のバージョン。
  • コントラスト(WCAG): 背景の上の各テキストについて、比率とそのレベル(AA または AAA、または「不適合」)をリアルタイムで表示します。見出しは大きな文字として扱います(AA は 3:1 で足り、通常の文字は 4.5:1 が必要です)。

CSS を編集は、テーマのシートをエディターに表示します。コントロールは 2 つの gsta:visual コメントで囲まれたブロックの中にだけ書き込み、その値を手で編集すると読み直します。ブロックの外に書いたものには一切触れません。コントロールが表示できないものをブロックの中に加えると、コントロールは書き込みをやめ、ペインがそれを知らせます。ブロックを復元は、ブロックに含まれる値だけからブロックを書き直し、それ以外には何もしません。

**インポート…**は .gsta.xz または単独の .css を開きます。パッケージは slides theme verify が検査するのと同じ方法、同じ上限で検査されます。安全でないパッケージ(パッケージの外に出るパス、リンク、SVG 内のスクリプト、リモートの url()、一致しないチェックサム)は theme.* コードとともに問題に表示されて拒否され、何も変わりません。単独のシートでは @import "gaia"; がベースのテーマ(extends)になります。パッケージはそこでベースを指定するためです。追加したフォントは、詳細でライセンスを指定するまで LicenseRef-unspecified というライセンスになります。

.gsta.xz をエクスポートは、ブラウザーでパッケージを作り、slides theme verify と同じように読み直すので、そのファイルは検査を通ります。CSS をエクスポートは、コンパイル済みのシートをダウンロードします。何もアップロードされません。編集はどれも元に戻すの 1 ステップで(同じコントロールの連続した編集は 1 ステップ)、置き換えられた内容はバージョンとして保持されます。**バージョンを保存…**は、テーマとそのバージョンを名前付きでバージョンのペインに保持します。

元に戻す、やり直し、バージョン

Undo(元に戻す)と Redo(やり直し)は Home タブにあり、Ctrl+Z、 Ctrl+Shift+Z、Ctrl+Y(Mac では Cmd)でも使えます。まず表示中のファイルの直前の編集を取り消し (ファイルごとに独自の履歴があります)、その後はプロジェクト全体への直前の操作を取り消します。 選んだサンプル、Reset、開いた .zip やフォルダー、復元した下書き、削除または名前変更した ファイルやフォルダー、復元したバージョンが対象です。Redo は、Undo を押した時点の状態にすべてを戻します。

バージョンは、プロジェクト全体をこのブラウザーに保存します。どこにも送信されません。 バージョンは、入力をやめてから少し後(最短 2 分間隔)、プロジェクト全体への各操作の前、 エクスポートと共有リンクのたびに保存されます。Save version… は名前を付けて 1 つ保存します。 Home ▸ Versions で Versions ペインが開きます。

  • Preview はバージョンをプレビューに表示します。
  • Compare with now は各ファイルの変更を行単位で、インラインまたは左右に並べて表示します。 F7 と Shift+F7 で変更箇所の間を移動できます。
  • Restore はバージョンを元に戻します。Undo で復元を取り消せます。
  • Delete はバージョンを削除します。

保存される内容:最新の自動バージョン 20 件、その後は 1 日分を 1 時間に 1 件、1 か月分を 1 日に 1 件。 名前付きバージョンは削除するまで残ります(最大 50 件)。すべてのバージョンの合計は最大 96 MiB で、 変更のないファイルは 1 回だけ保存されます。ブラウザーのストレージがいっぱいになると、 古い自動バージョンから消えます。

GitHub

Home ▸ History ▸ GitHub で、GitHub リポジトリからスライドのフォルダーを読み込み、 変更をプルリクエストとして提案するペインが開きます。次を入力します。

  • リポジトリ(所有者/名前)
  • ブランチ(空欄:既定)
  • フォルダー(空欄:ルート):フォルダーに deck.md が必要です

これらの欄の上に、ペインは git フレーム を表示します。forge を選び、トークン(マスク表示)を 入力し、このデバイスに記憶する にチェックを入れ、接続(または GitLab でサインイン)か 切断 を押す小さなパネルです。フレームは別のサイト go-slides-usercontent.github.io のページで、 playground に埋め込まれています。playground のページがトークンを見ることはありません。

トークンはきめ細かい個人用アクセストークン (作成はこちら)で、 選んだリポジトリに限定し、権限は Contents の読み取りと書き込み、Pull requests の 読み取りと書き込みです(Metadata の読み取りは暗黙に含まれます)。続けて次の操作ができます。

  • 読み込む はプロジェクトを GitHub のフォルダーに置き換えます。Undo で元に戻せ、 元のプロジェクトは「GitHub から」のバージョンとして残ります。
  • 変更を提案… はタイトルを尋ね、新しいブランチ slides/<タイトル>-<日付-時刻> を作成してプルリクエストを開きます。既存のブランチにも既定のブランチにも 書き込みません。プルリクエストを開く でそこへ移動します。
  • 変更を確認 は GitHub 上の新しいバージョンを自分のものと Compare ビューで比較します。 向こうを採用 で読み込みます。

GitHub にはプロキシを使いません。フレームが直接通信します。

トークンはフレームに入力し、そのサイトにとどまります。playground のページはトークンを読めず (フレームは別のオリジンで、独自のストレージを持ちます)、ページが送れるどのコマンドもトークンを返さず、 ページの Content Security Policy は GitHub や GitLab へのいかなる接続も許可しません。フレームは トークンを api.github.com(または gitlab.com)にだけ送ります。下書き、バージョン、共有リンク、 エクスポートには保存されず、スライドのプレビューやレンダリング worker にも届きません。 このデバイスに記憶する を選ぶと、切断(または Forget my drafts)まで、playground のストレージではなく go-slides-usercontent.github.io 上のフレーム自身の localStorage に保存されます。

以前のバージョンを使っていた場合: 以前のバージョンが playground ページ自身のストレージに 保存していたトークンは、このバージョンを最初に開いたときに削除され、ペインがそのことを知らせます。 フレームでもう一度入力してください(保存したい場合は「記憶する」にチェックを入れます)。

変更を提案… は書き込みなので、フレームが先に確認します。タイトル、リポジトリ、ファイル数を表示し、 フレーム自身の 許可 ボタンをあなたがクリックするのを待ちます(最長 2 分、同時に 1 件の提案のみ)。 クリックするまで何も書き込まれません。

リスクが二つ残ります。これらはフレームを埋め込むページに本質的に伴うものです。playground ページに 注入されたスクリプトは、フレームの nonce を読み取り、フレームのコマンドを送れます。読み込んだ フォルダーを読むことや、提案を求めることです(提案はフレームであなたが許可する必要があります)。 また、フレームの上に偽のパネルを描き、自らトークンを尋ねることもできます。フレームの見た目がおかしい、 または本来の場所にない場合は、トークンを入力しないでください。どちらの場合も、フレームが保持する トークンを読むことはできません。必要なリポジトリに限定したトークンを使ってください。チームには、トークンをサーバー側に置く セルフホストのサーバーモード(近日公開)があります。

GitLab.com

ペインには forge の一覧があり、GitHub と GitLab.com から選べます。GitLab では、 スコープ api の個人アクセストークンを入力するか、GitLab でサインイン (PKCE 付き OAuth 認可コード、シークレットなし)を押します。サインインではフレームのサイトの 小さなウィンドウが開き、そこへ戻ります。作業中の playground ページから移動することはありません。 そのトークンはフレームのメモリーにだけ置かれ(このデバイスに記憶する を選んでも記憶されません)、 期限前に自動で更新され、切断 で GitLab 側で取り消されます。フレームが始めていないサインインや 再利用されたリンクは拒否されます。サインインはサイトの GitLab アプリケーションが 登録されてから使えます。それまでは個人アクセストークンを使ってください。

リクエストの送信先は api.github.com と gitlab.com だけで、送るのはフレームだけです。 playground のページはリクエストを送らず、referrer も送りません。

なぜ api が必要か。GitLab のスコープ表は write_repository を “Does not support API authentication” としています。これは HTTP 経由の git 専用で、GitLab は CORS なしで提供するため、ブラウザーからは使えません。変更の提案は REST API を 使い、そこでは api(“complete read and write access to the API”)が必要です。盗まれた api トークンは、そのユーザーが API でできることをすべて、そのユーザーが届くすべてのプロジェクトで 行えます。スライドのリポジトリに限定したプロジェクトまたはグループのアクセストークン、 あるいはスライドのプロジェクトのメンバーにだけなっている専用の GitLab アカウントを使ってください。

セキュリティ

スライドデッキは、ページのオリジンを持たないサンドボックス化された iframe に表示されます。 iframe からは Playground にもそのストレージにもアクセスできず、フォームの送信もナビゲーションもできません。 そのページには、自身のスクリプトだけを実行する Content Security Policy が設定されています。 スライドデッキ内の生の HTML は、slides のデフォルトと同じく Marp の許可リストに従います。 5 秒を超えて実行されるレンダリング(ループするテンプレートなど)は 停止されます。

発表者ウィンドウも同じサンドボックスを保ちます。このウィンドウは Playground 自身が開き、 同じようにサンドボックス化された iframe にスライドデッキを表示します。2 つの iframe はストレージを共有できないので、Playground がメッセージでスライド番号を 中継します。スライドデッキを実行するフレームが Playground の オリジンを得ることはありません。

プロジェクトのメディアは、メッセージ内のバイト列としてサンドボックス化されたフレームに渡され、 各フレームは自身のオリジンで、それぞれ独自の blob: URL を作成します。Playground が作成した blob: URL はそこでは読み込まれず、フレームのポリシーに追加されるのは、メディアとフォント向けの blob: だけです。

Playground は、サインインを必須にしたうえで、自分のマシンから配信することもできます。詳しくは セルフホスティングを参照してください。

サイズと速度

モジュールは、GitHub Pages が配信する状態で 8.8 MiB です(gzip。Pages は brotli で配信しません)。進捗バー付きで一度だけダウンロードされ、その後は次のデプロイまで ブラウザーにキャッシュされます。Apple M4 Max と Chrome 155 で公開中のページを 計測したところ、エディターはページを開いてから 2.1 s で使えるようになり、そのうち 1.5 s はダウンロードで、最初のスライドは 2.4 s で表示されました。100 枚のベンチマーク用スライドデッキへの変更は、 約 30 ms でプレビューに反映されます:go-slides は変更されたスライドだけを レンダリングし、プレビューでもそのスライドだけが置き換えられます。

Created on by tannevaled

Modified on by tannevaled