フレーム
フレームを使うと、ひとつの図に複数のマージビューを同居 させられ ます。icon / connector / region / note や doc { … } の設定 ブロックに frames セレクタを付けておくと、レンダリング時にフレーム 番号を指定するだけで、そのフレームに該当するすべての宣言を 1 枚の フラットな図にまとめて描画します。
フレームは「タイムステップ」ではなく タグ として捉えてください。 フレーム 2 は「時刻 t=2 のキーフレーム」ではなく「2 というタグが 付いたスライス(+タグなしのすべて)」です。小さな違いですが重要 で、描画パイプライン自体は無変更のまま、「どの宣言をパイプライン に流すか」だけをフレームが決めている、という構造になっています。
3 フレームのストーリー
図にホバーすると ◀ / ▶ ボタンが現れ、3 フレームを行き来できます。 右側のソースは常に同じで、コンポーネントが選ばれたフレームのマージ 結果を再描画しているだけです。
左から右に読むと:
- フレーム 1(ベースレイヤーのみ)—
user/api/dbの 3 アイコンが静かに並ぶだけ。コネクタもノートも無し。 - フレーム 2 では色替えされた
api、user → apiのログイン コネクタ、API ノードを指す "Stateless" ノートが追加される。 - フレーム 3 では
userアイコンが塗りつぶし/アクセント版に 差し替わり、api → dbのクエリコネクタと解説ノートが追加される。
どのフレームでも共通のベースノードはそのまま残り、[2] / [3] タグで追加情報を重ねていく形です。
構文
[frame-spec] は 行頭(コマンド語の前)または インライン (通常の引数として)どちらにも書けます。意味は同じで、同じ文の 両方に書くとパースエラーになります。
icon :user @A1 tabler/user "User" # すべてのフレーム — ベースレイヤー
# 行頭形式 — 関連する複数の文で frame タグを列揃えしたいとき推奨:
[2] icon :user tabler/user "User login"
[2] user --> api "login"
[2] note @B1 (api) "Stateless,\nauto-scaled"
# インライン形式 — 単発でタグを付け加えたいときに:
icon [3-5] :user tabler/filled/user "Session"
region [3] @B1:B2 "spotlight"
note @A2 (user) "explained from f=2" [2-]
# doc 設定の上書き — こちらも行頭 / インラインどちらでも:
[2] doc { theme: { primary: '#ff0000' } }
doc [3-] { theme: { primary: '#0d9488' } }行頭形式は、あるフレーム番号の追加宣言がいくつも並んだときに特に 読みやすくなります([2] が列 1 で揃うので、フレームごとの構造が 一目で把握できます)。
TS API も同等 — frames? は各 def に対して任意に指定できます:
import type { DiagramDef } from 'gridgram'
export const def: DiagramDef = {
nodes: [
{ id: 'user', pos: 'A1', src: t('user'), label: 'User' },
// 単一フレーム(数値形式)
{ id: 'user', src: t('user'), label: 'User login', frames: 2 },
// リスト形式 — 個別の 2 フレーム
{ id: 'user', src: t('user'), label: 'Again', frames: [4, 6] },
// 範囲 — ネストしたタプル
{ id: 'user', src: tf('user'), label: 'Session', frames: [[3, 5]] },
// 無限範囲
{ id: 'late', pos: 'B1', src: t('bell'), frames: [[5, Infinity]] },
],
}frame-spec の文法早見表:
| 形式 | 意味 |
|---|---|
| (省略) | すべてのフレームに存在(ベース) |
[2] / 2 | 単一フレーム |
[2, 3, 5] | フレーム 2・3・5(3 つの単独) |
[[2, 5]] / [2-5] | 範囲 2..5 閉区間 |
[5-] / [[5, ∞]] | フレーム 5 以降すべて |
[2, 4-6, 9-] | 上記の混在 |
マージ規則
frame=N が指定されたとき、gridgram はすべての宣言について次の 処理を順に行います:
- フィルタ —
framesが N に該当するか、framesフィールド のない宣言だけを残す。それ以外は当該フレームから除外。 - id でマージ — 残った宣言のうち id を共有するものは、宣言 順に deep-merge(フィールド単位で後勝ち)。これにより
icon [2] :user label="login"のように、posやsrcを 再宣言せずにラベルだけ上書きできる。 - 匿名宣言はそのまま — note や region は id を持たないので、
framesが該当すれば独立したエントリとして追加される。
doc [N] { … } ブロックは、マッチすればベース設定(theme・columns など)へ deep-merge されます。たとえば「フレーム 2 だけプライマリ 色を差し替える」といった用途に使えます。
オートポジションは フレームごとに再評価 されます。そのフレーム での宣言順で再計算されるので、フレーム 3 にだけ現れるノードは そのフレーム内で空いているセルに割り当てられ、フレーム 2 で省略 されたノードはそのフレーム内で詰めて配置されます。
フレーム対応の整合性チェック
フレームに依存するチェック(未解決参照・セル重複・リージョンの 4 連結性)は フレーム単位 で実行されます。パーサはドキュメント に登場するすべてのフレーム番号を走査するので、たとえばフレーム 3 でのみ発生する衝突もパース時に検出され、(frame 3) の注釈付きで 報告されます:
Duplicate cell B2: icon "a" and icon "b" (frame 3)同一 id が エラーとなるのは両方の宣言に frames が無い場合のみ です。片方にでも [N] が付いていれば、マージ扱いとして許容され ます。
特定フレームの描画
gg diagram.gg --frame 2 -o diagram-f2.svg…TS API でも同様:
import { renderDiagram } from 'gridgram'
const { svg } = renderDiagram(def, { frame: 2 })frame を省略すると gridgram は フレーム 1 を描画します。 これにより、フレームを知らないツールでもフレームを使った図を そのまま描画できます。
どんなときにフレームが便利か
同じアーキテクチャ図を、書き直さずに複数スライドや複数段落に渡って ナレーションしたいときに真価を発揮します:
- フローのステップ解説(ログイン → セッション → ログアウト)
- インシデントの発生前・発生中・復旧後
- 同じ図の異なるサブシステムをハイライト
- ノート群を丸ごと差し替えて、同じ図に別の注釈を載せる
フレームは レイアウトアニメーションの仕組みではありません — gridgram はフレーム間の補間を行いません。必要な場合は各フレームを 書き出してお好みのアニメーションツールへ渡してください。