WWDC Quick Look 💓 By SwiftGGTeam
Create accessible spatial experiences

Create accessible spatial experiences

元の動画を見る

ハイライト

visionOS は空間コンピューティングに完全なアクセシビリティ体系をもたらしました。VoiceOver はピンチジェスチャーの組み合わせで 3D 空間をナビゲートし、RealityKit の AccessibilityComponent で 3D エンティティをスクリーンリーダーが認識でき、Dwell Control で視線だけの操作が可能になり、head anchor の代替案と Reduce Motion 対応で動きに敏感なユーザーも快適に使えます。

主要内容

課題: 3D 空間のアクセシビリティは未開拓の領域

従来の画面では、VoiceOver は UI 要素を 1 次元の順序で走査します — 上から下、左から右。開発者はボタンに accessibilityLabel、画像に accessibilityDescription を付ければ、ほぼ十分です。

空間コンピューティングはこれをすべて覆します。visionOS では UI 要素が 3 次元空間に分布します。ボタンが前方 2 メートルにあり、別のボタンが左 45 度、3 メートル先にあるかもしれません。VoiceOver は単純に「上から下」では走査できず、空間関係を理解する必要があります。

さらに厄介なのは、3D シーンのオブジェクトが UIButton や UILabel ではなく、3D モデル、マテリアル、アニメーションで構成される RealityKit エンティティであることです。これらは VoiceOver から完全に見えません。追加対応をしなければ、3D シーンの雲、木、キャラクターは視覚障害のあるユーザーには何もない空間です。

操作方式も変わりました。visionOS にタッチスクリーンはなく、目の視線と指のピンチで操作します。運動障害のあるユーザーにとって新たな課題です — ピンチができない人、視線を一点に安定させられない人がいます。

Apple のアプローチ: アクセシビリティ体系を 3D に持ち込む

visionOS はシステムレベルでアクセシビリティ体系全体を再設計しました。VoiceOver は画面座標の走査ではなく空間認識ナビゲーション — 空間オーディオでオブジェクトの方位を示し、ユーザーが空間内の位置を「聞いて」把握できます。

3D コンテンツには AccessibilityComponent を導入 — 任意のエンティティをアクセシビリティシステムが認識できる RealityKit コンポーネントです。エンティティにラベル、値、特性、カスタム操作を設定できます。UIKit/SwiftUI のアクセシビリティ API と同じ設計思想で、3D シーン向けに適応されています。

運動アクセシビリティでは、visionOS が Dwell Control(視線滞留制御)と Switch Control(外部スイッチ制御)を提供します。前者は対象を見つめ一定時間保つだけで操作をトリガー — 指のピンチは不要。後者は Bluetooth スイッチデバイスでシステム全体を制御できます。

詳細

RealityKit エンティティを VoiceOver に認識させる

visionOS では RealityKit エンティティはデフォルトでアクセシビリティシステムから見えません。AccessibilityComponent を明示的に作成してエンティティに付与する必要があります(05:28):

var accessibilityComponent = AccessibilityComponent()
accessibilityComponent.isAccessibilityElement = true
accessibilityComponent.traits = [.button, .playsSound]
accessibilityComponent.label = "Cloud"
accessibilityComponent.value = "Grumpy"
cloud.components[AccessibilityComponent.self] = accessibilityComponent

// ...

var isHappy: Bool {
    didSet {
        cloudEntities[id].accessibilityValue = isHappy ? "Happy" : "Grumpy"
    }
}

キーポイント:

  • AccessibilityComponent() は RealityKit エンティティのアクセシビリティ属性を記述するコンポーネントインスタンスを作成
  • isAccessibilityElement = true で VoiceOver がこのエンティティを発見可能に
  • traits.button.playsSound に設定すると VoiceOver はボタンで音を鳴らす要素と認識 — 「ボタン」と聞いたユーザーはアクティベートできると分かる
  • label は VoiceOver が読み上げる名前、value は現在の状態
  • cloud.components[AccessibilityComponent.self] = accessibilityComponent で RealityKit エンティティにコンポーネントを付与
  • 状態変化時は didSetaccessibilityValue を更新 — VoiceOver が自動で状態変化を読み上げ

RealityKit エンティティにアクティベーション操作を追加

VoiceOver で読み上げるだけでは不十分 — ユーザーは操作できる必要があります。systemActions で VoiceOver ユーザーがジェスチャーで 3D オブジェクトをアクティベートできます(08:04):

var accessibilityComponent = AccessibilityComponent()
accessibilityComponent.isAccessibilityElement = true
accessibilityComponent.traits = [.button, .playsSound]
accessibilityComponent.label = "Cloud"
accessibilityComponent.value = "Grumpy"
accessibilityComponent.systemActions = [.activate]
cloud.components[AccessibilityComponent.self] = accessibilityComponent

// ...

content.subscribe(to: AccessibilityEvents.Activate.self, componentType: nil) { activation in
    handleCloudCollision(for: activation.entity, gameModel: gameModel)
}

キーポイント:

  • systemActions = [.activate] でアクティベート操作を登録 — VoiceOver ユーザーはピンチジェスチャーでトリガー
  • content.subscribe(to: AccessibilityEvents.Activate.self, ...) でアクセシビリティアクティベーションイベントを監視
  • コールバックは activation を受け取り、activation.entity からアクティベートされたエンティティを取得
  • handleCloudCollision はカスタムハンドラ — 例: 雲に音を鳴らす、表情を変える
  • componentType: nil はすべてのエンティティタイプのアクティベーションをフィルタなしで監視

コンテキスト内の重要イベントをアナウンス

空間 App では、シーンの変化がユーザーの視野外で起こることがあります。背後からオブジェクトが現れたり、遠くで注意が必要な出来事が起きたりします。VoiceOver ユーザーに能動的に通知する必要があります(09:23):

AccessibilityNotification.Announcement("8 clouds in front of you").post()

キーポイント:

  • AccessibilityNotification.Announcement でアクセシビリティアナウンス通知を作成
  • .post() でシステムに送信 — VoiceOver が括弧内のテキストを読み上げ
  • ユーザーが見えない可能性のある重要な変化に使う — ゲームスコア、新しい敵、カウントダウン
  • アナウンスは簡潔で情報密度が高く、「何が」「どこで」を直接記述

head anchor コンテンツの代替案を提供

空間 App では UI 要素を head anchor(頭部追従)にできます — 常にユーザーの視線に追従します。しかし乗り物酔いしやすい人や前庭障害のある人には不快感を与えることがあります。visionOS はユーザー設定を検出する API を提供します(13:15):

// SwiftUI
@Environment(\.accessibilityPrefersHeadAnchorAlternative)
private var accessibilityPrefersHeadAnchorAlternative

// UIKit
AXPrefersHeadAnchorAlternative()
NSNotification.Name.AXPrefersHeadAnchorAlternativeDidChange

キーポイント:

  • SwiftUI では @EnvironmentaccessibilityPrefersHeadAnchorAlternative を読み取り — ブール値は head anchor の代替が必要かを示す
  • UIKit では AXPrefersHeadAnchorAlternative() で現在の設定を取得
  • AXPrefersHeadAnchorAlternativeDidChange で UIKit 開発者が設定変化を監視
  • true のとき、head anchor の UI を world anchor(空間の固定位置)またはウィンドウ内に変更
  • この設定はアクセシビリティ設定でシステムが一元管理 — App 側のスイッチは不要

Reduce Motion 設定への適応

visionOS も Reduce Motion(動きの削減)をサポートします。大量のアニメーション、パーティクル効果、空間移動を含む App では、この設定を確認して敏感なユーザーの不快感を避けます(15:04):

// SwiftUI
@Environment(\.accessibilityReduceMotion)
private var accessibilityReduceMotion

// UIKit
UIAccessibility.isReduceMotionEnabled
UIAccessibility.reduceMotionStatusDidChangeNotification

キーポイント:

  • accessibilityReduceMotion はシステムの Reduce Motion 設定を反映
  • 有効時は以下を削減または無効化: 大きなオブジェクトアニメーション、パーティクルシステム、視差スクロール、激しいカメラ移動
  • isReduceMotionEnabled は UIKit の読み取り専用プロパティ — 起動時と設定変化時に確認
  • reduceMotionStatusDidChangeNotification で設定変化にリアルタイム対応
  • 一般的な適応: バネアニメーションをシンプルなフェードに、3D 回転効果を除去

字幕設定の確認

空間コンピューティングでも聴覚アクセシビリティは重要です。visionOS はシステムレベルのクローズドキャプション設定をサポート — App はこの設定を確認して字幕表示を決めます(23:35):

UIAccessibility.isClosedCaptioningEnabled
UIAccessibility.closedCaptioningStatusDidChangeNotification

キーポイント:

  • isClosedCaptioningEnabled はユーザーがシステム設定でクローズドキャプションを有効にしているかを返す
  • 音声コンテンツ(会話、ナレーション、効果音)を含む App はこの値に基づき文字字幕を表示
  • closedCaptioningStatusDidChangeNotification でユーザーが設定を切り替えたときにリアルタイム更新
  • 字幕は聴覚障害ユーザーだけでなく、騒がしい環境やサイレントモードのユーザーも助ける

重要ポイント

  1. RealityKit ゲームに完全な VoiceOver サポートを追加: visionOS App に 3D インタラクティブオブジェクトがある場合、各インタラクティブエンティティに AccessibilityComponent を付与し、.label.value.traits.systemActions を設定。なぜやるか: visionOS にタッチスクリーンはなく、VoiceOver は視覚障害ユーザーの唯一の操作手段。アクセシビリティ未対応なら完全に使えない。始め方: App 内のすべてのインタラクティブ RealityKit エンティティを洗い出し、上記 AccessibilityComponent スニペットで設定し、シミュレータで VoiceOver テスト。

  2. 空間認識のイベントアナウンスを実装: 重要なシーン変化で AccessibilityNotification.Announcement を使い能動的に通知 — 例:「3 体の敵が後ろにいます」「右側のドアが開きました」。なぜやるか: 空間 App では多くの出来事が視野外で起こる。視覚障害ユーザーには追加の聴覚キューが必要。始め方:「起きたがユーザーが見えない」すべてのイベントを洗い出し、トリガー点に .post() を追加し、アナウンス文に方位情報を含める。

  3. Head Anchor 設定を検出して適応: 起動時に accessibilityPrefersHeadAnchorAlternative を読み取り、true なら頭部追従の HUD、メニュー、プロンプトを world anchor またはウィンドウ内表示に変更。なぜやるか: head anchor コンテンツは視野端を常に占め、前庭に敏感なユーザーに不快感を与える可能性。代替案で利用のハードルを大きく下げられる。始め方: App 内のすべての head anchor UI を監査し、各 UI の非 head anchor フォールバックレイアウトを用意、@Environment 値で切り替え。

  4. 動き効果の Reduce Motion 適応を構築: accessibilityReduceMotion を読み取り、true なら大きなアニメーションをすべてシンプルな遷移に置き換え。なぜやるか: visionOS の空間アニメーションは平面画面より強烈 — オブジェクトが 3D で移動・回転・拡大縮小。動きに敏感なユーザーには App が使えなくなる。始め方: 主要アニメーションに完全版と簡略版の 2 バージョンを作り、環境変数で選択、reduceMotionStatusDidChangeNotification 発火時に動的切り替え。

  5. すべての音声コンテンツに字幕サポートを追加: isClosedCaptioningEnabled を確認し、字幕有効時に音声の文字説明を表示。なぜやるか: visionOS の空間オーディオは没入感があるが、聴覚障害ユーザーは情報にアクセスできない。字幕は情報の平等な取得の鍵。始め方: 会話、ナレーション、重要な効果音の文字説明を用意し、音声再生時に字幕設定を確認。

関連セッション

コメント

GitHub Issues · utterances