Presentation Mode
Build a gesture-driven section deck with the public SDK and understand the Builder-generated presentation output.
Presentation Mode is a Motion.page Builder feature that exports a section navigator composed from public SDK primitives. In hand-written SDK code, build the same experience with ordinary Motion() timelines, Motion.set(), and .onGesture().
Public SDK Boundary
The public GestureConfig does not include a presentation property. Its required fields are types and events; optional fields include target, tolerance, dragMinimum, wheelSpeed, preventDefault, each, and the other options documented in Observer & Gesture.
// The navigator below patches this timeline's play() and reverse() methods.
Motion("deck-gesture").onGesture({
target: ".deck",
types: ["wheel", "touch", "pointer"],
events: { Down: "play", Up: "reverse" },
preventDefault: true,
});The SDK generator has a separate internal GestureOptions type that temporarily adds presentation. The Builder stores its Presentation Mode controls there, then consumes them to generate normal SDK code. That generator-only metadata is never passed to .onGesture().
How Builder Output Works
The generated presentation script:
- Queries the configured section selector and stacks every section absolutely.
- Creates an independent timeline for each section’s configured animations.
- Tracks
currentIndexand ananimatingguard insidegotoSection(index, direction). - Builds reusable outgoing and incoming transition timelines.
- Registers a public
.onGesture()trigger whoseplayandreverseactions callgotoSection(). - Exposes the generated navigator on
windowfor absolute-index navigation.
The emitted gesture wiring uses play and reverse. It does not use playNext or playPrevious, because those actions require SDK each-mode sibling instances; the generator manages its own section array instead.
const gesture = Motion("deck-gesture");
gesture.onGesture({
types: ["wheel", "touch", "pointer"],
events: { Down: "play", Up: "reverse" },
preventDefault: true,
});
// The generated navigator owns currentIndex and gotoSection().
gesture.play = function () {
gotoSection(currentIndex + 1, 1);
return gesture;
};
gesture.reverse = function () {
gotoSection(currentIndex - 1, -1);
return gesture;
}; Complete Hand-Written Example
The preview below implements the same architecture directly with the public SDK. Scroll or drag inside it, or use the Previous and Next buttons.
Builder Generator Settings
These settings belong to the Builder and SDK generator, not to public GestureConfig:
| Generator setting | Type | Default | Generated behavior |
|---|---|---|---|
sectionSelector |
string |
'.section' |
Selects the sections to stack. The Builder derives it from the Observer target. |
direction |
'vertical' | 'horizontal' |
'vertical' |
Selects the y or x transition axis. |
duration |
number |
1 |
Sets each incoming/outgoing transition duration in seconds. The Builder constrains it to 0.1–5. |
cooldown |
number |
0.5 |
Keeps navigation locked for this many additional seconds after the transition. The Builder constrains it to 0.1–5. |
effects |
('opacity' | 'translate')[] |
both | Chooses whether generated transitions fade, translate, or do both. |
infiniteRepeat |
boolean |
false |
Wraps out-of-range indices to the opposite end. |
reverseGesture |
boolean |
false |
Reverses the generated forward/backward event mapping. |
useVerticalWheel |
boolean |
false |
Adds Down/Up mappings to a horizontal deck. |
initialSection |
number |
0 |
Chooses the initially visible zero-based section. This currently remains generator data rather than a visible Builder control. |
Do not copy these keys into .onGesture(). In hand-written code they become ordinary variables and branches inside your own navigator.
Direction and Gesture Mapping
The Builder generator maps direction settings to public gesture events:
| Builder setting | Forward action | Backward action |
|---|---|---|
| Vertical | Down → play |
Up → reverse |
| Horizontal | Right → play |
Left → reverse |
| Horizontal + Vertical Wheel | Also Down → play |
Also Up → reverse |
Reverse Gesture swaps every forward/backward pair. A hand-written implementation can use the same event map or choose its own.
Transition Effects
The Builder’s Opacity and Translate selections decide which properties the generator puts into its transition timelines:
| Builder selection | Outgoing section | Incoming section |
|---|---|---|
| Opacity + Translate | Fades and moves off-screen | Fades and moves in from off-screen |
| Translate only | Moves off-screen | Moves in from off-screen |
| Opacity only | Fades out in place | Fades in place |
If no effects are selected in the Builder, the adapter restores both defaults. In hand-written SDK code, omit whichever properties you do not want to animate:
// Fade-only transition inside your gotoSection() function
Motion.get("deck-out")?.kill(false);
Motion.get("deck-in")?.kill(false);
Motion.set(incoming, { opacity: 0, visibility: "visible" });
Motion("deck-out", outgoing, {
to: { opacity: 0 },
duration: 0.8,
}).play();
Motion("deck-in", incoming, {
from: { opacity: 0 },
to: { opacity: 1 },
duration: 0.8,
}).play();Hand-Written Variants
Horizontal Deck
Animate x instead of y, then map horizontal events. Add Down and Up only when you want a vertical mouse wheel to control the horizontal deck:
gesture.onGesture({
target: ".deck",
types: ["wheel", "touch", "pointer"],
events: {
Right: "play",
Left: "reverse",
Down: "play",
Up: "reverse",
},
preventDefault: true,
});Infinite Loop
Normalize the requested absolute index before checking it:
index = ((index % sections.length) + sections.length) % sections.length;Without that line, return early when index < 0 || index >= sections.length.
Per-Section Animations
The Builder generator scopes each animation target to the current section. Reproduce that explicitly by resolving descendants from each section element:
const sectionTimelines = sections.map((section, index) =>
Motion("deck-section-" + index, section.querySelectorAll("[data-reveal]"), {
from: { opacity: 0, y: 40 },
duration: 0.7,
stagger: 0.08,
ease: "power2.out",
})
);
// Inside gotoSection():
sectionTimelines[currentIndex]?.reverse();
sectionTimelines[index]?.play(); When the configured animation target equals the section selector itself, the generator targets the section element directly. Otherwise it uses section.querySelectorAll(animationTarget).
Builder-Generated External Navigation
Generated presentation code exposes its navigator as window.__mp_presentation_NAME. This is a generator convenience, not a public SDK method. The name is derived from the Builder timeline name and sanitized for use as a property.
gotoSection(index, direction) expects an absolute zero-based index and a transition direction (1 for forward, -1 for backward):
// Timeline name: "deck"
window.__mp_presentation_deck?.gotoSection(2, 1);
window.__mp_presentation_deck?.gotoSection(0, -1);The function uses the same animating guard as gesture navigation, so calls made during the transition or cooldown are ignored. It is not a relative next/previous API.
Builder Usage
In the Motion.page Builder, open Left Panel → Trigger → Observer, enable Trigger each iteration individually, then enable Presentation mode (full page sections). The first toggle is a UI prerequisite that reveals Presentation Mode; generated .onGesture() code still uses the generator-owned section array rather than public each mode.
| Builder control | What the generator changes |
|---|---|
| Presentation Mode | Selects the standalone section-navigator generator path. |
| Observer target | Becomes the section selector. |
| Direction | Chooses x or y transitions and directional event mappings. |
| Transition Duration | Sets incoming and outgoing timeline durations. |
| Gesture Cooldown | Extends the navigation lock after each transition. |
| Effects | Includes opacity, translation, or both in generated timelines. |
| Infinite Repeat | Enables modulo wrapping. |
| Reverse Gesture | Swaps forward and backward event mappings. |
| Trigger on Vertical Scroll | Adds vertical-wheel mappings in horizontal mode. |
Tips and Gotchas
Give the container an explicit height. Generated sections use absolute positioning with width: 100% and height: 100%; their containing block must establish a height, commonly 100vh.
Cooldown starts after the transition. Navigation remains locked for the transition duration and then for the configured cooldown.
Builder timing settings are generator metadata. duration and cooldown here are not fields on public GestureConfig; public stopDelay is a separate gesture option.
Vertical wheel mapping is horizontal-only. A vertical deck already maps Down and Up.
Clean up hand-written decks explicitly. Kill the transition, section, and gesture timelines and restore the inline section styles when unmounting a component or leaving an SPA route.
Related
- Observer & Gesture — public
GestureConfigand gesture actions - Timeline Control — manually play and reverse section timelines
- SPA Integration — scope and clean up hand-written navigators
- Presentation Mode — Builder — configure the generator visually