TV & cinema
PrismDS targets the living room as a first-class context, not an afterthought. This guide covers the cinema scale, the TV safe-area / focus tokens, the spatial focus engine, and the behavioural rules every TV surface must follow. The reference implementation is MediaOS (ui_kits/mediaos/) — an in-room entertainment home screen built to tvOS-grade polish.
Two products live here: MediaOS (entertainment) and HospitalityOS's in-room TV. Both share this tier.
1. Cinema scale
Set the tier explicitly with data-scale="cinema" (alias data-scale="tv") on the surface root; it also activates automatically at viewport widths ≥ 1920px. Everything scales up proportionately — type, spacing, control height and icons — for distance viewing and remote navigation (see tokens/scales.css).
- Type floor jumps: body is
--text-xl, headings climb to--text-7xl/--text-9xlfor hero titles. - Controls use
--control-xl; icons step up to 28–44px. - Layout gutters and stack gaps widen to
--space-16.
Author in container units for true any-size scaling. MediaOS sizes every value in cqw (1% of the stage width) inside a container-type: size stage with aspect-ratio: 16/9. The whole UI then scales to any screen — a 1280-px preview or a 4K panel — with no JS layout math and no cropping. Prefer this over fixed px for full-screen TV surfaces.
2. TV safe-area & focus tokens
Defined in the cinema block of tokens/scales.css:
| Token | Purpose | Default |
|---|---|---|
--tv-safe-x | title-safe horizontal inset (TVs overscan-crop edges) | 5.5% |
--tv-safe-y | title-safe vertical inset | 6.5% |
--tv-focus-ring | focus-ring thickness | 3px |
--tv-focus-color | focus-ring colour | oklch(1 0 0 / 0.95) |
--tv-focus-lift | scale applied to a focused card | 1.08 |
--tv-focus-shadow | drop shadow under a focused card | soft 4cqw black |
Always pad content to the title-safe area. Never place text, controls or anything tappable in the outer ~5–6% — it may be cropped by the panel.
3. The focus engine
TVs have no pointer. Navigation is spatial: arrow keys / D-pad move focus to the nearest element in the pressed direction; OK/Enter activates; Back exits. MediaOS ships a compact, dependency-free implementation you can lift:
- Geometry-based movement — on each arrow press, score every focusable by
primary-axis distance + cross-axis distance × 2.2and move to the lowest score. This gives natural, alignment-aware jumps and focus memory for free (returning to a row lands near the column you left). - Rail auto-scroll — focusing a card horizontally translates its rail so the focused card slides toward the start, exactly like tvOS.
- Vertical page-pan — focusing a lower row pans the whole content body so the focused row sits ~40% down the viewport (the page scrolls under a pinned top bar).
- Cinematic backdrop crossfade — the focused item's artwork fades in behind everything (two stacked, blurred layers), giving the screen depth.
- Focus signature — the focused card lifts (
--tv-focus-lift), gains a high-contrast ring (--tv-focus-ring/--tv-focus-color), a drop shadow, and a subtle specular sheen. Posters reveal their title caption only when focused.
Focus rules
- Visible focus is mandatory — the ring must read from across a room; never rely on colour or scale alone.
- One focus owner — exactly one element is focused at all times; default focus to the primary action (e.g. Play) on entry.
- No hover assumptions — every hover affordance must have a focus equivalent. (Mouse hover may additionally move focus, as MediaOS does, for desktop preview.)
- Large targets — focusable cards are big; spacing between them is generous (≥ the focus ring + lift won't collide).
- Honour reduced-motion — gate the lift/pan/crossfade transitions behind
@media (prefers-reduced-motion: no-preference); keep the ring.
4. TV primitive vocabulary
These are patterns demonstrated by MediaOS rather than separate exported components (the 10-foot tier is composed, not bolted on). When a TV surface needs one, build it from these recipes:
| Primitive | Recipe |
|---|---|
| TV app shell | container-type: size 16:9 stage + pinned glass top bar + scrolling content body |
| TV safe area | padding via --tv-safe-x/y; rails bleed to the right edge, inset on the left |
| TV focus ring | ::after ring using --tv-focus-ring / --tv-focus-color, shown on .is-focused |
| TV focusable card | poster/thumbnail with lift + ring + caption-on-focus |
| TV rail | horizontally-scrolling track of cards with a title + "See All" |
| TV hero | full-bleed featured item: kicker, oversized title, metadata row, glass actions |
| TV menu / nav | frosted Liquid Glass pill of tabs with a light selected pill |
| TV media controls | glass transport bar (play/pause, scrubber, skip) — same focus signature |
| TV QR handoff | show a QR for any complex text entry (login, search, payment) — never force on-screen keyboards |
| TV language selector | large-target list, flag + endonym, on first run |
| TV idle / screensaver | after inactivity, dim to ambient art + clock |
| TV remote-help overlay | a persistent hint chip (↑↓←→ Navigate · ⏎ Select) — MediaOS shows one |
| TV network-failure state | use EmptyState variant="offline" scaled to cinema |
| TV guest-privacy reset | on hotel checkout, wipe watch history / accounts (see COMPLIANCE) |
Liquid Glass material: background: oklch(1 0 0 / 0.08–0.14) + backdrop-filter: blur() saturate(1.6) + a 1px oklch(1 0 0 / 0.2) border + an inset top highlight. Use for the nav, glass buttons, badges and hint chip.
5. Remote interaction matrix
| Input | Action |
|---|---|
| ▲ ▼ ◀ ▶ | Move focus spatially |
| OK / Enter | Activate focused element |
| Back / Esc | Up one level; from home, do nothing (never exit to black) |
| Home / Menu | Return to the home screen, restoring last focus |
| Play/Pause | Toggle transport when media is active |
| Long-press OK | Context actions (where relevant), e.g. remove from Continue Watching |
| Inactivity | Idle screen after timeout; guest reset on hospitality checkout |
6. TV accessibility & QA checklist
- Focus ring visible at 3 m on every focusable, in light and dark content.
- All content inside the title-safe area.
- Reaches every actionable element with the D-pad alone; no pointer required.
- Focus order is logical; focus memory works returning to a row.
- OK activates; Back never dead-ends to a black screen.
- Reduced-motion disables lift/pan/crossfade but keeps the ring.
- Text ≥ the cinema type floor; contrast ≥ 4.5:1 over busy artwork (use scrims).
- Complex input offers a QR handoff.
- Network-failure and idle states defined.
- (Hospitality) guest data resets on checkout.