# 3. Subtitle Scale and Captions
Part of [[Accessibility]]. Prev: [[2. Colorblind-Safe Palettes]]. Next: [[4. Reduced Motion]].
## 3.1 In-game scale (all platforms)
Subtitles and prompts are UI Toolkit Labels (or a dedicated subtitle view). Drive size from a float you own (for example 0.8-1.6), applied as `label.style.fontSize` or a USS class you swap. Persist it ([[High Scores, Saves and Player Stats]] / [[PlayerPrefs Advanced]]).
Keep a **minimum readable size**. Do not scale the whole HUD until buttons fall off a Quest panel - scale the subtitle / dialogue / prompt text first ([[3. Glyph Prompts in UI Toolkit]], [[2. Localizing UI Toolkit and uGUI Text]]). Localized strings can grow: test German and a long Smart String ([[3. Smart Strings Plurals and Variables]]) at the largest scale.
A captions **on/off** toggle is separate from scale. If a cutscene or a radio line has speech, offer captions ([[Timeline Basics]], [[Localization]] asset tables for voice).
## 3.2 System settings (Android and iPhonePlayer only)
Official 6000.5 `UnityEngine.Accessibility.AccessibilitySettings` (read-only, updated from system settings):
| API | Meaning |
|---|---|
| `fontScale` | User font scale in system settings |
| `isBoldTextEnabled` | Bold text in system settings |
| `isClosedCaptioningEnabled` | Closed captioning in system settings |
| `fontScaleChanged` | Main-thread event when font scale changes |
| `boldTextStatusChanged` | Bold text changed |
| `closedCaptioningStatusChanged` | Captions changed |
Supported platforms in the 6000.5 Scripting API remarks: **`RuntimePlatform.Android`** and **`RuntimePlatform.IPhonePlayer`**. On Editor, desktop, and Quest, treat these as **unavailable or undefined** unless you have tested them there - still use the in-game slider.
```csharp
using UnityEngine;
using UnityEngine.Accessibility;
/// <summary>
/// Combines an in-game scale with mobile system fontScale when present.
/// NOT compiled in Unity.
/// </summary>
public sealed class SubtitleScaler : MonoBehaviour
{
[SerializeField] float userScale = 1f;
[SerializeField] float min = 0.8f;
[SerializeField] float max = 1.6f;
public event System.Action<float> Changed;
public float UserScale
{
get => userScale;
set
{
userScale = Mathf.Clamp(value, min, max);
Changed?.Invoke(EffectiveScale);
}
}
public float EffectiveScale
{
get
{
float system = 1f;
if (Application.platform == RuntimePlatform.Android ||
Application.platform == RuntimePlatform.IPhonePlayer)
system = AccessibilitySettings.fontScale;
return Mathf.Clamp(userScale * system, min, max * 1.25f);
}
}
void OnEnable()
{
AccessibilitySettings.fontScaleChanged += OnFontScaleChanged;
AccessibilitySettings.closedCaptioningStatusChanged += OnCaptionsChanged;
}
void OnDisable()
{
AccessibilitySettings.fontScaleChanged -= OnFontScaleChanged;
AccessibilitySettings.closedCaptioningStatusChanged -= OnCaptionsChanged;
}
void OnFontScaleChanged() => Changed?.Invoke(EffectiveScale);
void OnCaptionsChanged()
{
if (Application.platform != RuntimePlatform.Android &&
Application.platform != RuntimePlatform.IPhonePlayer) return;
// If system captions are on, prefer showing your subtitle view.
if (AccessibilitySettings.isClosedCaptioningEnabled)
Changed?.Invoke(EffectiveScale);
}
}
```
Subscribe in the view; do not poll. On platforms where the events never fire, the in-game slider still works. I did not find a 6000.5 guarantee of default `fontScale` values in the Editor - clamp everything.
## 3.3 Exercise
A subtitle Label, a slider 0.8-1.6, and a long localized line. At 1.6 the text must still wrap inside the panel, not off the Quest-safe area. On an Android/iOS device (if you have one), change system font size and confirm the event fires.
## Sources
- `AccessibilitySettings` (6000.5): https://docs.unity3d.com/6000.5/Documentation/ScriptReference/Accessibility.AccessibilitySettings.html
- Accessibility module intro (6000.5): https://docs.unity.com/en-us/engine/6000.5/manual/accessibility/module-intro