window-management について
macOS 15以降で、用途に応じたSwiftUIウィンドウを設計する開発者向けスキルです。シーンの選択、外観、動作、配置を案内し、SwiftUIの修飾子で足りない場合に限ってAppKit連携を検討します。
主な機能
- 01用途に応じたシーンの分類
- 02ツールバーとタイトルの調整
- 03ドラッグ領域とマテリアルの設定
- 04復元と起動動作の設定
- 05初期配置と拡大配置の制御
- 06ウィンドウの使いやすさの確認
活用シーン
- 01ユーティリティやAboutウィンドウの設計
- 02メディアプレーヤーウィンドウの設計
- 03ウィンドウの復元動作の選択
- 04ディスプレイに合わせたサイズ調整
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ openai/ plugins --skill window-managementインストール後、Claude Code で/window-managementを入力して読み込まれたか確認します。
同梱ファイルagents/openai.yamlreferences/api-snippets.md
詳細
ウィンドウ管理
概要
このスキルを使って、それぞれの SwiftUI ウィンドウを用途に合わせて調整します。まず、どのシーン(Window、WindowGroup、専用のユーティリティシーン)がウィンドウを所有しているかを特定し、ツールバーやタイトル領域、背景マテリアル、サイズ変更と復元の動作、初期配置や拡大時の配置をカスタマイズします。
SwiftUI で直接実現できる動作には、その場しのぎの AppKit ブリッジではなく、シーンやウィンドウの修飾子を優先します。各ウィンドウは用途に合わせて設計してください。メインのブラウザーウィンドウ、About ウィンドウ、メディアプレーヤーウィンドウでは通常、異なるウィンドウ装飾、サイズ変更の可否、復元、配置のルールが必要です。
これらの API は macOS 15 以降の SwiftUI によるウィンドウ/シーンのカスタマイズ機能です。これより古いデプロイメントターゲットでは、AppKit とのブリッジや利用可能性チェックが必要になることがあります。
ワークフロー
- 関連するシーンの宣言を確認し、ウィンドウの役割を分類します。 アプリのメインナビゲーション、インスペクター/詳細ユーティリティ、About/サポートウィンドウ、メディア再生ウィンドウ、ウェルカムウィンドウ、または枠のないカスタムサーフェスです。
- コンテンツに合わせて、ツールバーとタイトルの表示を調整します。
- ツールバーの背景またはツールバー全体を非表示にする場合は、ウィンドウに使いやすいドラッグ領域が残るようにします。
- その役割に合わせてウィンドウの動作を調整します。最小化の可否、復元、サイズ変更の要件、起動時にウィンドウを表示するかどうかを設定します。
- 新しく開くウィンドウのデフォルトの配置と、コンテンツやディスプレイのサイズが重要な場合の拡大時の理想的な配置を設定します。
build-run-debugを使ってアプリをビルドし、起動して、実際のフォアグラウンド.appバンドルで結果を確認します。- SwiftUI のシーン/ウィンドウ修飾子で不十分な場合は、AppKit をビュー階層全体に広げるのではなく、
appkit-interopを使って限定的なNSWindowブリッジを実装します。
ツールバーとタイトル
- ウィンドウタイトルをアクセシビリティやメニュー向けに維持しつつ、タイトルバーには表示しない場合は、
.toolbar(removing: .title)を使います。 - 大きなメディアコンテンツやヒーローコンテンツをウィンドウの上端まで視覚的に広げる場合は、
.toolbarBackgroundVisibility(.hidden, for: .windowToolbar)を使います。 - ウィンドウに閉じる/最小化/フルスクリーンのコントロールが引き続き必要な場合は、タイトルとツールバーの背景だけを削除します。ツールバー全体を非表示にする場合は、代わりに
.toolbarVisibility(.hidden, for: .windowToolbar)を使います。 - 新しい SwiftUI のツールバー API を重ねる前に、カスタムのツールバー背景や、手動で描画したタイトルバーの塗りつぶしを削除します。
- 非表示にする場合でも、ウィンドウの論理的なタイトルは意味のあるものにしてください。システムは引き続き、アクセシビリティやメニュー項目にそのタイトルを使えます。これらは見た目だけの変更です。
ドラッグ領域
- ツールバーの背景を非表示にする場合や、ツールバー全体を削除する場合は、
WindowDragGesture()を使ってコンテンツ内にもドラッグ可能な領域を広げます。 - ジェスチャーは、実際のコントロールの操作を妨げない透明なオーバーレイ、または操作要素のないヘッダー領域に設定します。
- カスタム再生コントロールを備えたメディアプレーヤーでは、ビデオコンテンツとコントロールの間にドラッグ用オーバーレイを挿入し、AVKit やトランスポートコントロールが引き続き入力を受け取れるようにします。
.allowsWindowActivationEvents(true)とドラッグジェスチャーを組み合わせると、背面にあるウィンドウをクリックしてすぐにドラッグした場合でも、そのウィンドウがアクティブになって移動します。
背景とマテリアル
- ユーティリティウィンドウや About ウィンドウで、デフォルトのウィンドウ背景を控えめなすりガラス風のマテリアルに置き換える場合は、
.containerBackground(.thickMaterial, for: .window)を使います。 - スタイルを施したウィンドウでは、ハードコードした半透明色ではなく、システムマテリアルを優先します。
- 柔らかな背景がデザインの一部となる、コンテンツが固定されたユーティリティウィンドウでは特に有効です。
ウインドウの動作
- カスタムの「このアプリについて」ウインドウのように、最小化してもほとんど利点がない常にすぐアクセスできるユーティリティウインドウには、
.windowMinimizeBehavior(.disabled)を使用します。 - ウインドウのコンテンツに想定されるサイズが1つだけの場合は、サイズを固定するかウインドウに制約を設定して、緑色のズームコントロールを無効にします。
- 「このアプリについて」パネル、一時的なサポート/情報ウインドウ、初回起動時のウェルカム画面など、次回起動時に再表示しないウインドウには、
.restorationBehavior(.disabled)を使用します。 - 前回のサイズと位置で再度開くことが望ましい場合は、メインの書類ウインドウやナビゲーションウインドウの状態復元を有効にします。
- デフォルトでは、SwiftUI は macOS 全体に適用されるユーザーの状態復元設定に従います。特定のウインドウでこのシステムの動作を意図的に有効または無効にする場合にのみ、
restorationBehavior(...)を使用します。 - ウェルカムウインドウなど、起動時に最初に表示するウインドウには
.defaultLaunchBehavior(.presented)を使用し、シーンの作成順による副作用に頼らず、この動作を意図的に選択します。
ウインドウの配置
.defaultWindowPlacement { content, context in ... }を使用して、新しく開くウインドウの初期サイズと、必要に応じて位置を制御します。- 配置のクロージャ内で
content.sizeThatFits(.unspecified)を呼び出し、コンテンツの最適なサイズを取得します。 context.defaultDisplay.visibleRectを読み取り、メニューバーと Dock を考慮したディスプレイの使用可能領域を取得します。- メディアや書類のコンテンツがディスプレイより大きくなる可能性がある場合は、可視領域に収まるようサイズを制限したうえで
WindowPlacement(size: size)を返します。位置を指定しない場合、ウインドウはデフォルトで中央に配置されます。 - ユーザーが「ウインドウ」メニューから「ズーム」を選択するか、緑色のツールバーボタンを Option キーを押しながらクリックしたときの動作は、
.windowIdealPlacement { content, context in ... }を使用して制御します。メディアウインドウでは、アスペクト比を維持し、ディスプレイに収まる最大サイズまで拡大します。 - デフォルトの配置と最適な配置は、別々のポリシーとして扱います。
- デフォルトの配置は、新しいウインドウを最初に表示する位置を制御します。
- 最適な配置は、ズームしたウインドウのサイズを制御します。
- コンテンツのサイズに基づいてプレーヤーウインドウや書類ウインドウのサイズを決めるときは、外部ディスプレイや縦向き/横幅の狭い画面も必ず考慮します。
ボーダーレスウインドウと特殊なウインドウ
- ボーダーレス、または外観を高度にカスタマイズしたウインドウには
.windowStyle(.plain)を使用します。ただし、コンテンツに明確なドラッグ/移動の手がかりと、視覚的な文脈が残るようにしてください。 - ボーダーレスのプレーヤー、HUD、ウェルカムウインドウでは、標準のタイトルバーの操作手段を失うことが、カスタム表示に見合うかどうかを事前に判断します。
- plain スタイルによってウインドウが見えにくくなったり、動かしにくくなったりする場合に備えて、通常のウインドウ管理に戻る明確な方法を用意します。
具体的なウインドウ修飾子の例については、references/api-snippets.md を参照してください。
レビューチェックリスト
- シーンの種類が、ウインドウの役割とライフサイクルに合っています。
- タイトルを非表示にしても、アクセシビリティやメニューで意味のある論理タイトルが残ります。
- ツールバーの背景を削除する意図が明確で、タイトルバーの視認性やウインドウコントロールの配置に悪影響がありません。
- ツールバーを非表示または削除したウインドウにも、確実にドラッグできる領域があり、背景からクリックしてそのままドラッグしてアクティブにする操作をサポートしています。
- ユーティリティウインドウの復元/最小化の動作が、その用途に合っています。
- 復元動作の上書きは、ユーザーのシステム全体の設定と意図的に異なる動作をするシーンにのみ使用されています。
- コンテンツとディスプレイのサイズが重要な場合、デフォルトの配置と最適な配置に
content.sizeThatFits(.unspecified)とcontext.defaultDisplay.visibleRectを使用しています。 - メディアウインドウはアスペクト比を維持し、小型ディスプレイや回転したディスプレイに収まります。
- ボーダーレスウインドウにも、実用的な移動/ドラッグの手段があります。
ガードレール
- 設定し忘れたタイトルを隠すためだけに
.toolbar(removing: .title)を使わないでください。 ウィンドウタイトルは、意味のある内容にしてください。 - ツールバーの背景やツールバー全体を隠す場合は、失われるドラッグ操作の手段を別途用意してください。
- ユーザーが起動のたびにアプリを初期状態にすることを明示的に希望していない限り、メインのドキュメント/ナビゲーションウィンドウの状態復元を無効にしないでください。
- プレーヤーウィンドウのサイズを決める際、モニターのサイズを一つに固定したり、ディスプレイが一台だけの構成を前提にしたりしないでください。
NSWindowの変更に着手する前に、.windowMinimizeBehavior、.restorationBehavior、.defaultWindowPlacement、.windowIdealPlacement、.windowStyle、.defaultLaunchBehaviorですでに問題を解決できないか確認してください。- 明確なドラッグ操作や閉じる手段のない、シンプルなボーダーレスウィンドウを残さないでください。
他のスキルを使う場面
- シーン、コマンド、設定、サイドバー、インスペクターのアーキテクチャ全般については、
swiftui-patternsを使ってください。 - 主な課題が最新の macOS のビジュアル表現、Liquid Glass、またはシステムマテリアルの採用である場合は、
liquid-glassを使ってください。 - カスタムのウィンドウ動作に
NSWindow、NSPanel、またはレスポンダーチェーンの制御が本当に必要な場合は、appkit-interopを使ってください。 - 作成されたウィンドウを起動して検証するには、
build-run-debugを使ってください。
コメント
Markdown 対応