Design Guidelines

Design DynamicLake extensions and plugins to be compact, glanceable, and clearly connected to the current task.

Overview

DynamicLake supports native SwiftUI extensions and JSON plugins. Both should follow the same principle: show the most useful current information with the least possible visual weight.

Use the compact live activity for the primary status. Use a sneak peek for a small amount of supporting detail.

Plugins use predefined JSON components instead of custom SwiftUI views, but the layout rules are the same: keep compact slots short, put secondary detail in the sneak peek, and let DynamicLake own the outer panel.

!Live activity and sneak peek regions shown in DynamicLake.

Best Practices

Compact Activity

The compact activity should communicate one idea quickly. A common layout is a symbol or small visual on the left and a status, progress, or duration value on the right.

Do not use descriptive text labels in compact live activity. Use text in the sneak peek; compact live activity text should be duration-style content such as a timer or countdown.

Use LiveActivitySlotLayout and LiveActivityGeometry instead of building the full panel with custom spacing. DynamicLake owns the outer shape and notch gap.

For provider-based extension or agent views, read sizing from context.geometry and use liveActivityLeftSlotSymbol(in:) for the leading symbol. Do not rebuild geometry inside compactView(context:); the host already passes the active-screen geometry.

Pill-shaped external displays use different compact and sneak-peek widths. Avoid deriving sneak-peek layout from a cached compact width; read the SneakPeekGeometry from DynamicLakeSneakPeekContext instead.

DynamicLake also applies the pill content scale to hosted extension live activity and sneak-peek scenes. Do not add a second outer scale in extension UI; build the content to fit the frame DynamicLake gives the scene.

For icon-only compact activities, such as a left symbol with a right progress or status circle, prefer .small and use enforcesMinimumSideSlots: false. This keeps pill/non-notch layouts aligned with the same geometry used by built-in compact activities like music, AirDrop, and TinyDrop.

let geometry = LiveActivityGeometry.currentOnActiveScreen(
    size: .small,
    enforcesMinimumSideSlots: false
)

If you choose .normal or .large, use the same size in the activity configuration and the compact view geometry. Mismatched sizes can make the live activity jump after a sneak peek closes.

Use LiveActivityGeometry/compactProgressAccessoryVisualWidth for progress and status circles instead of LiveActivityGeometry/compactAccessoryButtonVisualWidth. If the circle still feels large on non-notch displays, shrink only that visual, not the whole slot layout:

let progressSize = geometry.screenKind.isNonNotch
    ? max(14, (geometry.compactProgressAccessoryVisualWidth * 0.82).rounded())
    : geometry.compactProgressAccessoryVisualWidth

Sneak Peek

A sneak peek should extend the compact activity, not replace it. Use it for secondary information, short labels, or compact controls.

Do not draw a separate panel background, separator, or custom outer padding in sneak peek content. DynamicLake applies those around the view.

When side controls need more room, reserve layout space through SneakPeekSlotSizing instead of adding outer SwiftUI padding. For example, use .fixed(48).reservingTrailing(12) for a right control group that needs room after the controls without changing the rendered control width.

Extra Live Activity

Use DynamicLakeExtraLiveActivity as a small secondary capsule, not as another full compact live activity. It should usually show one element, most often one SF Symbol. Use a value or symbol-plus-value only when the symbol alone is not clear enough.

Do not use LiveActivitySlotLayout inside ELA content because the ELA has no notch gap. Do not draw a custom capsule background, shadow, or outer panel padding; DynamicLake owns the capsule. Keep ELA content passive and let tapping the capsule open the activity as the main lake.

Size and Priority

Use LiveActivitySize for layout and LiveActivityPriority for ordering.

Choose the size that fits the compact content clearly without adding labels. Use .small for tight icon-only, status, progress, or timer layouts, .normal when that content needs slightly more room, and .large when it needs the widest compact live activity.

Use .low for long-running background activities such as calendar events, .normal for active work such as music playback, and .high only for sensitive, time-critical activity such as calls and notifications.

Test Layouts

Preview activity UI with DynamicLakeLiveActivitySimulator. Test both .notch and .pill shapes before shipping. In pill mode, check the compact state and the sneak-peek state because the panel widens when the sneak peek opens.

Topics

Design APIs