Use Slides when one explanation should work both as a document and as a short presentation. Each page remains ordinary Markdown content rendered by Web Device. Slides only paginate that content at explicit boundaries and add a player to the page; they do not introduce a separate canvas, component set, or content type.
This page is a live feature guide (how to author, mount, and embed a deck, with working samples below). Atomic structure contracts live under the Markdown unit pages: slides: true front matter, thematic break / HR, and ::embed. Those unit pages are reference; this page is the runnable how-to.
This feature requires an ARC build that contains the Web Device slides widget. The segment reading form on this page — slide cards with narration, divider section titles, and slidesLayout — additionally requires a build that includes the article-segment transcript; on an older build those decks still render as the earlier linear transcript. The target runtime is the ARC service that will serve your site. Do not infer support from version labels on older documentation pages; verify that runtime before publishing a deck. See Version compatibility for the evidence boundary.
Sample contract
| Field | Value |
|---|---|
| Purpose | One Markdown record as readable transcript + optional 16 player |
| Boundaries | No presenter view, PDF export skill, free-form canvas, or bundled slide theme; no document write from player controls |
| Author entry | Front matter slides: true + layout: slides (+ optional slidesLayout) · named layouts/slides.aup · same-site ::embed |
| Surface | slides / document transcript; embed player on document pages |
| Public status | released when the serving ARC includes the slides widget |
| Fallback / failure | Without widget: server-rendered transcript only; without slides: true: ordinary article; bad --- underlining fails build; unknown slidesLayout fails build |
| Verification | Demo routes below · authoring CLI arc --version = 2.0.0-beta.32; serving runtime must still include the slides widget |
Write a deck record
In the YAML front matter at the start of the Markdown content file you want to turn into a deck, set slides: true. That field makes top-level thematic breaks into slide boundaries. Set layout: slides separately to choose the named layout that mounts the player.
Source:
---
title: A short technical explanation
slides: true
layout: slides
---
## Start with one idea
The first slide is an ordinary Markdown body.
---
## Continue on a new slide
- A list
- a table
- a code blockslides: true and layout: slides answer different questions. The first turns the body into a deck. The second selects layouts/slides.aup. A deck without the widget remains server-rendered, readable transcript content; it does not gain player controls. If the record has its own layout.aup, do not also set layout: slides: one record must choose one object layout.
Mount the player once
Add the named layout at the site root. It supplies the player to any record that selects layout: slides.
Source: layouts/slides.aup
page slides {
view root {
detail-content body slot=content
widget deck name=slides target=".aup-deck"
}
}detail-content keeps the transcript inside the normal readable content area. The slides widget inserts a 16 player above that transcript. It uses the site's existing visual tokens — such as colors, type, and spacing — rather than a bundled slide theme, so you do not add separate deck styling to this record.
Allow same-site embeds (required for in-page players)
ARC’s default security headers set Content-Security-Policy: frame-ancestors 'none'. That blocks every iframe, including same-origin deck embeds. A site that uses ::embed for decks must override framing for itself.
Source: .web/security
# Allow this site to frame its own pages (Markdown Slides embeds, internal frames).
frame-ancestors: "'self'"Without this file, top-level deck pages still work, but article/doc embeds render as a blank frame. This site ships the override; copy the same shape when you enable Slides on another site.
Inspect a live deck
In the Markdown file for a page that should show a deck, add this directive and replace its url with the site-absolute path of your published deck. The following same-site record is this guide's demo source.
Source:
::embed{url="/en/docs/web-device/slides-demo/"}Rendered:
Before the Slides widget initializes, the server-rendered transcript remains part of the frame. After initialization, the fixed 16 frame presents the player as its visible surface. Open the demo as its own page to inspect the default player plus readable transcript. The document and its source remain read-only; player controls only change browser-local presentation state and never write the document or its source.
Put two decks on one page
A page is not limited to one embedded deck. Add one directive for each same-site route. This guide uses a short interaction demo and a separate overview deck, so the two players have different content and different slide counts.
Source:
::embed{url="/en/docs/web-device/slides-demo/"}
::embed{url="/en/docs/web-device/slides-overview/"}Rendered:
Each directive creates its own same-site frame. Moving the first player does not move the second one. Its slide fragment and ?full presentation mode belong to that deck's frame, so either player can be used or opened fullscreen without advancing or opening the other player. The directive has no one-deck-per-page limit. Keep every route intentional, because every embedded player still loads a real page.
Add speaker notes and page breaks
An HTML comment that occupies its own Markdown block becomes a speaker note. In the reading form the notes are the article: each slide renders as a scaled slide card, and its notes render beside or below that card as narration prose. Blank lines inside a note become paragraph breaks. Notes never appear on the projected slide. Write them as the sentences you would say over that slide, and the transcript reads the way a talk write-up reads.
Source:
## Explain the boundary
<!--
Pause before the example.
A second paragraph, split on the blank line.
-->
---
## Show the exampleYou can use ---, ***, ___, or - - - as a slide boundary. A deck cannot use these top-level thematic breaks as decorative horizontal rules. Put a blank line before ---: without it, Markdown can read the dashes as a heading underline and the build rejects the deck. A ruler inside a fenced code block remains code, not a boundary.
Break a long deck into sections
A page whose content is exactly one # (level-1) heading is a divider. In the player it is a normal title page; in the reading form it renders as a section title between segments instead of a slide card. Use # only for dividers and ## for ordinary slide titles, and a long deck stops reading as one uniform list. A # heading with anything else on the page — a subtitle paragraph, an image — remains an ordinary slide. A divider may still carry a speaker note; that note renders full-width under the section title.
Source:
# Part one: why
---
## The problemChoose a reading-form layout
slidesLayout front matter picks how each segment arranges the slide card and its notes. One value per deck. Every card is the same size whether or not its slide has notes, so the page stays even.
slidesLayout | Arrangement |
|---|---|
side (default) | card left · notes right |
side-reverse | notes left · card right |
stacked | full-width card · notes under it |
stacked-reverse | notes first · full-width card under them |
Source:
---
title: A short technical explanation
slides: true
layout: slides
slidesLayout: stacked
---On a narrow screen both side modes collapse to the vertical arrangement and keep the author's order: side shows the card first, side-reverse shows the notes first. An unknown slidesLayout value fails the build and lists the valid values; it never falls back silently.
Read, present, and share
The default page keeps an inline player above the transcript. Use the previous and next controls to move the player without changing the page mode. Each transcript card is a control: click it — or the Play from here button revealed when the pointer is over the card, or when the button has keyboard focus — to move the player to that slide and scroll it into view without switching the page to presentation mode. In inline reading mode, the player accepts arrow keys, PageUp/PageDown, Space, Home, and End only while it has focus; reading the transcript does not hijack those keys. In presentation mode, the deck owns those keys until you leave that mode. On a touch device, swipe the stage to move between slides.
Use the fullscreen control, f while the player has focus, or ?full in the URL to enter presentation mode. A slide fragment uses its first heading when there is one; a heading-less slide falls back to its one-based page number, and repeated headings receive a stable numeric suffix. For example, the heading ## Keep the player in the page in the demo becomes #slide-keep-the-player-in-the-page, so /en/docs/web-device/slides-demo/?full#slide-keep-the-player-in-the-page opens that page in presentation mode. You can also navigate to a slide and copy the browser address. On an initial page load, an unknown fragment starts at the first slide; changing an already-open player to an unknown fragment leaves its current slide in place.
This guide documents the current player and transcript contract. It does not provide a presenter view, PDF export workflow, authoring skill, free-form positioned canvas, or a bundled presentation theme.
Failure and limits
| Situation | Expected result |
|---|---|
slides: true without slides widget in serving ARC | Readable transcript; no player chrome |
layout: slides missing while slides: true | Deck semantics may exist without the named player mount |
slidesLayout with an unknown value | Build rejects the deck, listing the valid values |
--- without a blank line after a heading | Treated as setext underline; build rejects the deck |
| Thematic break inside a fenced code block | Remains code, not a slide boundary |
External ::embed URL | Not a same-site deck player; follow embeds refusal rules |
Same-site embed with default frame-ancestors 'none' | Blank iframe; set .web/security frame-ancestors: "'self'" |
Unit contracts (reference)
| Topic | Unit page |
|---|---|
slides: true | slides front matter |
Page breaks (---) | thematic break / HR |
::embed directive | embed |
| Full Markdown index | Markdown units hub |
Verification evidence
| Item | Value |
|---|---|
| Baseline (authoring CLI) | 2026-08-12 · arc --version → 2.0.0-beta.32 |
| Capability row | docs/aup/capability-matrix.md (internal, non-routed) · slides: true · deck widget |
| Implementation | providers/runtime/web-device/src/slides.ts; widgets/slides/; site layouts/slides.aup |
| Site framing | .web/security → frame-ancestors: "'self'" (required for embeds) |
| Guide routes | /en/docs/web-device/markdown-slides/ · /zh/docs/web-device/markdown-slides/ |
| Live deck routes | /en/docs/web-device/slides-demo/ · /en/docs/web-device/slides-overview/ · AUP capability tour (and zh counterparts) |
| Local run | arc service start --blocklet blocklets/arcblock --port 4900 · open guide embeds + demo page; try narrow width and ?full |
| Accept | Embed shows player when widget loads (not a blank frame); controls stay browser-local; no document write |
For a full document-surface AUP walk that uses this slides host (18 primitives, Markdown surface, deck media host): AUP capability tour. For the exact boundary on the embed directive, see Embed external and internal content. For the named-layout convention beyond Slides, see Compose pages and layouts and the directory reference.