Skip to main content

Live guide · ARC 2.0.0-beta.32

Write and embed Markdown slides

Turn one Markdown content record into a readable deck, mount its player with a named layout, and embed it as a same-site 16:9 player — source and live player on this page.

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

FieldValue
PurposeOne Markdown record as readable transcript + optional 16 player
BoundariesNo presenter view, PDF export skill, free-form canvas, or bundled slide theme; no document write from player controls
Author entryFront matter slides: true + layout: slides (+ optional slidesLayout) · named layouts/slides.aup · same-site ::embed
Surfaceslides / document transcript; embed player on document pages
Public statusreleased when the serving ARC includes the slides widget
Fallback / failureWithout widget: server-rendered transcript only; without slides: true: ordinary article; bad --- underlining fails build; unknown slidesLayout fails build
VerificationDemo 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:

markdown
---
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 block

slides: 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

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

yaml
# 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:

markdown
::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:

markdown
::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:

markdown
## Explain the boundary

<!--
Pause before the example.

A second paragraph, split on the blank line.
-->

---

## Show the example

You 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:

markdown
# Part one: why

---

## The problem

Choose 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.

slidesLayoutArrangement
side (default)card left · notes right
side-reversenotes left · card right
stackedfull-width card · notes under it
stacked-reversenotes first · full-width card under them

Source:

markdown
---
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

SituationExpected result
slides: true without slides widget in serving ARCReadable transcript; no player chrome
layout: slides missing while slides: trueDeck semantics may exist without the named player mount
slidesLayout with an unknown valueBuild rejects the deck, listing the valid values
--- without a blank line after a headingTreated as setext underline; build rejects the deck
Thematic break inside a fenced code blockRemains code, not a slide boundary
External ::embed URLNot 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)

TopicUnit page
slides: trueslides front matter
Page breaks (---)thematic break / HR
::embed directiveembed
Full Markdown indexMarkdown units hub

Verification evidence

ItemValue
Baseline (authoring CLI)2026-08-12 · arc --version → 2.0.0-beta.32
Capability rowdocs/aup/capability-matrix.md (internal, non-routed) · slides: true · deck widget
Implementationproviders/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 runarc service start --blocklet blocklets/arcblock --port 4900 · open guide embeds + demo page; try narrow width and ?full
AcceptEmbed 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.