
iphone-duo-adaptive-layout
Build layouts that adapt to the iPhone Duo fold using reserved regions, division and occlusion regions, displacement patterns, and the split and overlay ArrangementView containers. Use when content or controls land in the fold, when building a split-like or overlay layout, or when custom manually-positioned UI must avoid the hinge or the under-display camera.
- Installs
- 664
- Last 24h
- +30
- Trending rank
- #4397
- Security
- Not audited
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/mirzaaghazadeh/iphone-duo-skills --skill iphone-duo-adaptive-layout- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads iphone-duo-adaptive-layout automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
SKILL.md
The instructions your agent reads when the skill is triggered.
Adaptive layouts around the fold
When iPhone Duo is partially folded the inner display curves through the middle. Anything sitting in that curve gets harder to read and much harder to tap. The same thing happens to a photo printed across the spine of a book: near the gutter it stops reading as one continuous image.
So the fold is not decoration. It is a real constraint on where content can go — and iOS models it as a reserved region you can query and design around.
Reserved regions
Reserved regions are areas of the view that hardware imposes on your layout. Treat them exactly like the window controls you already work around on iPadOS: not obstacles, just facts about the available space.
Two kinds, and the distinction matters:
Division regions split one area into several smaller usable areas. The fold is a division region. Content does not flow through it — it belongs on one side or the other.
Occlusion regions cover part of an area without splitting it. Think of them as frames sitting inside your bounds. The inner FaceTime camera is an occlusion region.
Concretely, iPhone Duo has three reserved regions, and it's worth knowing which is which because they behave differently:
| Region | Kind | When it's there |
|---|---|---|
| Outer front camera | occlusion | Always. Sits in the corner, aligned with the side controls, and expands into the Dynamic Island for Live Activities. |
| Inner front camera | occlusion | Only while that camera is active. It's under the display and invisible otherwise; when it activates, UI moves aside to reveal it. |
| The folding region | division | Only while the device is partially folded, dividing the inner display and excluding the curved centre. |
Regions are active or inactive:
- The fold's division region is active only while the device is partially folded; fully open, it is inactive. The Tech Talk adds that it then has zero width, but the later reference and Group Lab Day 3 both say an inactive region keeps a frame, and suggest reading it ahead of time so a layout already clears the fold and nothing moves when the device bends. Check that frame in the simulator before depending on its size.
- The camera's occlusion region is active only while that camera is streaming.
Note the asymmetry between the two cameras: the outer one is a permanent fact of your layout, while the inner one appears and disappears under you. Handle the second as a change you animate through, not a constant you read once.
You get only the active ones by default; the Tech Talks and the API reference
agree on that. Pass the includeInactive option to also see regions that exist
but aren't currently in play — which is what you want for stable, high-level
decisions. A grid, for instance, can prefer an even column count on any device
that has a fold, so the layout doesn't reshuffle every time the user bends the
device.
Querying them
In SwiftUI, get a GeometryProxy from GeometryReader or onGeometryChange,
then ask it for reserved regions. Note the two signatures differ — SwiftUI takes
a third parameter UIKit doesn't:
// SwiftUI, on GeometryProxy
func reservedRegions(
kind: ReservedRegion.Kind,
options: ReservedRegion.QueryOptions,
layoutDirectionBehavior: LayoutDirectionBehavior
) -> [ReservedRegion]
// UIKit, on UIView
func reservedRegions(
kind: UIView.ReservedRegion.Kind,
options: UIView.ReservedRegion.QueryOptions = []
) -> [UIView.ReservedRegion]
The layoutDirectionBehavior argument matters in right-to-left layouts: the fold
is fixed in hardware, so whether you want region positions mirrored with your
content or left in physical coordinates is a decision you have to make rather
than inherit.
Pass .includeInactive in options to also get regions that exist but aren't
currently active.
Each region gives you more than a rectangle:
frame— where it sits in the view's coordinate space.isActive(activein Objective-C) — whether it's currently in play.kind— division or occlusion.margins— the clearance the system keeps for interactive content. The reference is explicit thatframealready includes these margins, so keeping controls out offrameis enough; don't pad bymarginsa second time. Insetframebymarginsto get the bare hardware area — the limit for full-bleed media, which may run closer than controls.id— stable across queries, so you can tell the region you saw last time from a new one.ReservedRegionisIdentifiable, so regions can drive aForEachdirectly.
Frames are in the coordinate space of the view you queried, with (0, 0) at its
top-leading corner, and only regions that overlap that view come back. A region
that clips a corner can have a negative origin or run past your bounds, so don't
assume it lies inside them. Query in the view that does the positioning, so the
frames and the content share coordinates. Two places this bites:
- In a custom SwiftUI
Layout, theboundspassed toplaceSubviewsdon't always start at(0, 0). Compute positions from zero and addbounds.originonly when you place each subview. - In UIKit, read regions in
updateConstraints(). UIKit tracks what you read there and calls it again when the regions change, so you don't need an observer of your own.
In SwiftUI the query takes a third parameter, layoutDirectionBehavior
(default .mirrors), which flips region frames for right-to-left layouts so a
custom Layout doesn't have to. Pass .fixed for the physical frames.
Query reserved regions for custom, manually laid out controls. If you are using system containers, you already have this handled — see below.
Displacement: the design pattern
Most interfaces can simply flow around a reserved region. Some deserve a more deliberate response, and the pattern for that is displacement — adjusting an element's frame based on the available space so that important content stays visible, reachable and unobstructed while the device is folded.
The typical case: an element sits centered while the device is open, and once folded it moves into whichever region actually supports its purpose.
Choose the right scope. Displacement scales from a single button to an entire container. If an element can stand on its own, move it alone. If elements work as a unit, move them together — pulling a context menu away from the photo it belongs to breaks the relationship even though both are technically visible.
Don't move things far. Distance weakens the visual link between an element and its source. Aligning both around the fold usually beats banishing one to the far region.
Don't displace continuously scrolling content. Articles, feeds, documents, lists — these already adapt by scrolling. Relocating them between regions interrupts continuity and gains nothing. Scrollable content is also exempt from fold avoidance generally; it's fine for it to pass under the curve.
Where things should move
Let purpose decide, and note that purpose changes with pose:
- Folded like a book — send transient things such as alerts to the trailing side, near where they will continue to appear as the device closes onto the outer display.
- Propped on a table — the top region is for content that reads at a distance; the bottom region is the stable surface, so tappable controls belong there.
- When several regions would work — pick the contextual one. A focused search field should stay over the view it is searching, adapting its width and position as the device folds, exactly as it stays over the keyboard on iPhone.
How things should adapt once moved
Position and size are the usual changes, but not the only ones. A split view can keep both columns visible by rebalancing to an even 50/50 split. A grid can hold its outer margins and simply widen the gap at the hinge, keeping every cell whole and inside one region.
The through-line: you are moving, resizing and reorganizing what is already there — never removing it. Every piece of content, every function, every layout stays reachable no matter how the device is being held.
Containers that adapt for free
Before writing any of this yourself, check whether a system container already does it:
- Navigation —
NavigationStack,NavigationSplitView,TabView - Content —
List,ScrollView— with one caveat from Apple's reference: they don't split their rows around the fold, so a row can run across it. That's fine for continuously scrolling content (see displacement, above); where a row's controls end up in the curve, read the division and lay that row out yourself. - Presentations — action sheets, alerts, menus, popovers all reposition themselves around reserved regions automatically
Arrangements
Between navigation containers and content containers sits a third kind: a layout container that arranges exactly two views by rule. That's an arrangement, new in iOS 27.1.
The rule is a function. Inputs: horizontal and vertical size class, the view's width-over-height aspect ratio, and whether any division region is currently active. Outputs: whether each view is shown at all, and what frame it gets.
Building one
In SwiftUI, put an ArrangementView inside your NavigationStack and give it a
primary and a secondary view. In UIKit, use UIArrangementViewController as the
root of a UINavigationController and assign view controllers to the .primary
and .secondary placements.
The split style
The default. It divides the bounds between the two views, equally unless you say otherwise — side by side when the view is wider than tall, with the primary leading, and stacked when taller than wide, with the primary on top.
Constrain it when only one axis makes sense: apply .axes(.horizontal) to the
split style. In UIKit, configure UISplitArrangement the same way and pass it to
updateArrangement(_:animated:). That method and
setViewController(_:for:animated:) both default animated to false, so pass
true when the change should animate.
When the arrangement can't split along an axis — because you excluded it, or because a closed iPhone Duo is held in landscape — it shows only the primary view rather than producing a bad layout. Pick the primary with that in mind: it is the view that survives.
Size the panes when equal halves are wrong. In SwiftUI, put one of these on a
view: splitArrangementLayoutRatio(_:) for a fraction of the container,
splitArrangementLayoutSize(minWidth:idealWidth:maxWidth:…) for points, or
splitArrangementFixedLayoutSize() to prefer the view's ideal size. The view
with the higher layoutPriority gets what it asks for and the other takes the
rest. In UIKit, give a placement a DimensionRange:
var split = UISplitArrangement.split
var primary = split.defaultViewProperties
var width = UISplitArrangement.DimensionRange()
width.minimum = .absolute(250)
width.preferred = .fractional(0.3)
primary.width = width
split.setViewProperties(primary, for: .primary)
arrangementController.updateArrangement(split, animated: true)
The payoff on this device: when the secondary view is dismissed, the primary doesn't recenter across the whole display the way it would on iPad. It stays inside the region the fold defines, so its controls stay reachable and clear of the curve.
The overlay style
Where split prefers side-by-side, overlay prefers stacking one view above the other — and moves them side-by-side when the device folds, which is exactly when the stacked view would otherwise get cramped.
Precisely: with no active division region — closed, or fully open — the primary view sits on top of the secondary. Once partially folded, the primary moves to the trailing or bottom region relative to the fold, and the secondary to the leading or top. That ordering is worth internalising before you pick which view is primary: the primary is the one that ends up where the thumb is, not the one that gets the larger area.
If the default side is wrong for your content, set it: overlayArrangementEdge(_:)
on the view in SwiftUI, or edge on the overlay's view properties in UIKit,
chooses which horizontal edge that view takes in landscape.
Because the relationship changes with the pose, you often want to change the
subordinate view's presentation to match. Read the stacking state and adapt: in
SwiftUI, the overlayArrangementZIndex environment value; in UIKit, state(for:)
on the arrangement view controller and then its zIndex. A list that is
collapsed while stacked can expand once it's given its own region.
Choosing between them
Follow the pattern the app already uses. Something built from HStack/VStack
maps to split; something built from ZStack maps to overlay. Both
translate directly and bring iPhone Duo support with them.
With no existing pattern to follow, ask what the relationship between the two views is:
- Foreground over background, where partial obscuring is acceptable — overlay. Controls floating over readable content that scrolls beneath them is the canonical case.
- Main and detail, where neither may ever be obscured — split. A player and its transcript is the canonical case.
When not to use one
- Arrangements provide no navigation infrastructure. Don't put a
NavigationSplitViewor aTabViewinside one — in UIKit, a split view or tab bar controller. - Don't nest an arrangement inside anything that lays out views itself:
List,ScrollView, a grid, a collection view, or a split view. - If you need expanding and collapsing column behavior, you want a real split view, not an arrangement.
A working order
- Audit centered layouts. Would a two-column layout be better? If not, which displacement pattern applies?
- Prefer system containers and presentations — most adaptation is free.
- Where the app has a custom horizontal split or overlay, replace it with
ArrangementView. You gain iPhone Duo behavior across every supported device, not just this one. - Only then, for the highest-priority manually positioned controls, adopt the reserved-region APIs and implement displacement by hand.
For hinge-driven interaction rather than layout, see
../iphone-duo-hinge-and-scenes/SKILL.md — live hinge angle is the wrong tool
for laying out views, and the right one for driving effects.
FAQ
What does the iphone-duo-adaptive-layout skill do?
Build layouts that adapt to the iPhone Duo fold using reserved regions, division and occlusion regions, displacement patterns, and the split and overlay ArrangementView containers. Use when content or controls land in the fold, when building a split-like or overlay layout, or when custom manually-positioned UI must avoid the hinge or the under-display camera.
How do I install iphone-duo-adaptive-layout?
Run npx skills add https://github.com/mirzaaghazadeh/iphone-duo-skills --skill iphone-duo-adaptive-layout in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/iphone-duo-adaptive-layout/ (personal) or .claude/skills/iphone-duo-adaptive-layout/ (project).
Which AI agents can use iphone-duo-adaptive-layout?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is iphone-duo-adaptive-layout safe to install?
No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.
Who maintains iphone-duo-adaptive-layout?
It is published by mirzaaghazadeh in mirzaaghazadeh/iphone-duo-skills. It has 664 recorded installs.
More from mirzaaghazadeh/iphone-duo-skills
iphone-duo-readiness
mirzaaghazadeh/iphone-duo-skills
Audit and port an iOS app to iPhone Duo, Apple's first foldable iPhone. Use when asked to support, adapt, prepare, test, or review an app for iPhone Duo, foldable iPhone, the inner/outer display, device poses, or the fold. Entry point that routes to the layout, bars, hinge/scenes, camera, and design skills.
iphone-duo-design-review
mirzaaghazadeh/iphone-duo-skills
Review or design an iOS interface for iPhone Duo's poses — closed, open, book-folded, tabletop and tent — covering side-mounted controls, asymmetric layouts, fold avoidance, sheets, and how to use the inner display well. Use for design critique, mockup review, or deciding what a screen should look like on a foldable iPhone rather than how to code it.
iphone-duo-vertical-bars
mirzaaghazadeh/iphone-duo-skills
Adapt toolbars, navigation bars and tab bars for the vertical axis on iPhone Duo — item ordering, symbol vs text representations, axis behavior, overflow menus, visibility priority, and when to opt out. Use when toolbar items look wrong, overflow too early, or need to move to the side on the outer display.
iphone-duo-hinge-and-scenes
mirzaaghazadeh/iphone-duo-skills
Use the iPhone Duo hinge angle for interactions and effects, support Split View multitasking and multiple app scenes, and pair UI across both displays with scene accessories including CameraCaptureAccessory. Use when building fold-driven effects, multi-window support, or dual-display experiences.
iphone-duo-camera
mirzaaghazadeh/iphone-duo-skills
Build camera capture for iPhone Duo's two front cameras — the virtual front camera, the inner under-display and outer ultra-wide devices, AVCaptureDeviceDirectionCoordinator, preview mirroring and video gravity, and dual-display capture. Use when an app captures photo or video and must handle the device opening, closing or flipping.
iphone-duo-react-native
mirzaaghazadeh/iphone-duo-skills
Open the skill to read its SKILL.md instructions.
Popular frontend & design skills
setup-matt-pocock-skills
mattpocock/skills
Configure this repo for the engineering skills: set up its issue tracker, triage label vocabulary, and domain doc layout. Run once before first use of the other engineering skills.
frontend-design
anthropics/skills
Guidance for distinctive, intentional visual design when building new UI or reshaping an existing one. Helps with aesthetic direction, typography, and making choices that don't read as templated defaults.
hyperframes-animation
heygen-com/hyperframes
All animation knowledge for HyperFrames — atomic motion rules, multi-phase scene blueprints, scene transitions, broader motion-design techniques, AND the seven runtime adapters (GSAP default, plus Lottie, Three.js, Anime.js, CSS keyframes, Web Animations API, TypeGPU). Use for any motion or animation task: pick 2-4 rules and compose, or load a blueprint, or look up runtime-specific API (e.g. GSAP eases / Lottie player / Three.js mixer). Also covers auditing an existing composition's choreography (animation map) and 24 named text-animation effects. HyperFrames-native: single paused timeline, seek-safe, deterministic.
prototype
mattpocock/skills
Build a throwaway prototype to answer a design question. Use when the user wants to sanity-check whether a state model or logic feels right, or explore what a UI should look like.
hyperframes-core
heygen-com/hyperframes
The HyperFrames composition contract — build one renderable project. Use for composition structure, the data- timing attributes, class="clip", tracks, sub-compositions, variables, framework-owned media playback, deterministic-render rules, and validation. Read before writing composition HTML.
vercel-react-best-practices
vercel-labs/agent-skills
React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.