@honeydeck/honeydeck 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/DEVELOPMENT.md +4 -1
  2. package/Readme.md +2 -2
  3. package/SPEC.md +3 -3
  4. package/docs/components-browser-frame.md +34 -0
  5. package/docs/components-keyboard.md +31 -0
  6. package/docs/components-list-style.md +49 -0
  7. package/docs/components-notes.md +36 -0
  8. package/docs/components-reveal-group.md +58 -0
  9. package/docs/components-reveal-with.md +37 -0
  10. package/docs/components-reveal.md +33 -0
  11. package/docs/components-timeline-steps.md +48 -0
  12. package/docs/components.md +13 -54
  13. package/docs/configuration.md +11 -0
  14. package/docs/deeper-dive.md +30 -7
  15. package/docs/getting-started.md +2 -2
  16. package/docs/navigation.md +1 -1
  17. package/docs/pdf-export.md +4 -2
  18. package/docs/presenter-mode.md +6 -3
  19. package/docs/skills.md +3 -3
  20. package/docs/slidev-migration.md +3 -0
  21. package/docs/steps-and-reveals.md +143 -8
  22. package/package.json +4 -1
  23. package/skills/SPEC.md +2 -2
  24. package/skills/honeydeck/SKILL.md +2 -2
  25. package/skills/slidev-migration/SKILL.md +1 -0
  26. package/src/SPEC.md +8 -3
  27. package/src/cli/SPEC.md +3 -2
  28. package/src/cli/pdf.ts +11 -4
  29. package/src/layouts/SPEC.md +1 -1
  30. package/src/remark/SPEC.md +102 -2
  31. package/src/remark/code-utils.ts +151 -0
  32. package/src/remark/shiki-code-blocks.ts +329 -136
  33. package/src/remark/step-numbering.ts +408 -103
  34. package/src/runtime/Deck.tsx +133 -116
  35. package/src/runtime/EffectiveColorModeContext.tsx +37 -0
  36. package/src/runtime/SPEC.md +21 -8
  37. package/src/runtime/SlideCanvas.tsx +19 -16
  38. package/src/runtime/SlideScaleContext.tsx +23 -0
  39. package/src/runtime/components/CodeBlock.tsx +19 -202
  40. package/src/runtime/components/CodeBlockCopyButton.tsx +64 -0
  41. package/src/runtime/components/CodeBlockShared.ts +17 -0
  42. package/src/runtime/components/Fade.tsx +51 -0
  43. package/src/runtime/components/FadeGroup.tsx +175 -0
  44. package/src/runtime/components/FadeWith.tsx +54 -0
  45. package/src/runtime/components/MagicCodeBlock.tsx +223 -0
  46. package/src/runtime/components/NavBar.tsx +1 -1
  47. package/src/runtime/components/NormalCodeBlock.tsx +128 -0
  48. package/src/runtime/components/Reveal.tsx +27 -27
  49. package/src/runtime/components/RevealGroup.tsx +143 -41
  50. package/src/runtime/components/RevealWith.tsx +63 -0
  51. package/src/runtime/components/SPEC.md +112 -7
  52. package/src/runtime/components/TimelineReveal.tsx +81 -0
  53. package/src/runtime/components/index.ts +13 -5
  54. package/src/runtime/components/timelineVisibility.ts +45 -0
  55. package/src/runtime/index.ts +9 -1
  56. package/src/runtime/navigation.ts +6 -4
  57. package/src/runtime/presentationApi.ts +449 -0
  58. package/src/runtime/views/PresenterCastButton.tsx +39 -0
  59. package/src/runtime/views/PresenterView.tsx +21 -4
  60. package/src/runtime/views/SPEC.md +7 -5
  61. package/src/theme/base.css +67 -2
  62. package/src/vite-plugin/SPEC.md +20 -2
  63. package/src/vite-plugin/index.ts +16 -2
  64. package/src/vite-plugin/layout-demo-crawler.ts +304 -33
  65. package/src/vite-plugin/splitter.ts +1 -0
  66. package/src/vite-plugin/virtual-modules.ts +16 -6
package/DEVELOPMENT.md CHANGED
@@ -211,7 +211,10 @@ honeydeck
211
211
  │ └── bee/ → src/layouts/bee/*
212
212
  └── ./components/
213
213
  ├── . → src/runtime/components/index.ts
214
- └── code-block → src/runtime/components/CodeBlock.tsx
214
+ ├── code-block → src/runtime/components/CodeBlock.tsx
215
+ └── code-block/
216
+ ├── normal → src/runtime/components/NormalCodeBlock.tsx
217
+ └── magic → src/runtime/components/MagicCodeBlock.tsx
215
218
  ```
216
219
 
217
220
  ---
package/Readme.md CHANGED
@@ -22,8 +22,8 @@ Decks are plain MDX files separated into slides with `---`; see the first deck e
22
22
  - [Deeper dive](docs/deeper-dive.md) - CLI options, authoring patterns, imports, themes, architecture, and agent skills
23
23
  - [Slides](docs/slides.md) - separators, multiple files, layouts, and assets
24
24
  - [Configuration](docs/configuration.md) - deck-level and slide-level frontmatter
25
- - [Steps and reveals](docs/steps-and-reveals.md) - timeline, reveal groups, code steps, and PDF behavior
26
- - [Components](docs/components.md) - core Honeydeck components such as `BrowserFrame` and `Keyboard`
25
+ - [Steps and reveals](docs/steps-and-reveals.md) - timeline, reveal groups, code steps, Magic Code, and PDF behavior
26
+ - [Components](docs/components.md) - core Honeydeck components such as `Reveal`, `RevealWith`, `BrowserFrame`, and `Keyboard`
27
27
  - [Customization](docs/customization.md) - themes, layout sets, Tailwind tokens, custom layouts, and layout demos
28
28
  - [Navigation](docs/navigation.md) - keyboard, touch, overview mode, and URL state
29
29
  - [Mobile and touch](docs/mobile.md) - mobile controls, touch gestures, and pinch zoom
package/SPEC.md CHANGED
@@ -33,7 +33,7 @@ The Honeydeck specification is distributed:
33
33
  | Styling | Explicit CSS imports, Tailwind-compatible utilities, and CSS custom properties | [`src/theme/SPEC.md`](src/theme/SPEC.md) |
34
34
  | Markdown | MDX with GitHub-flavored Markdown tables; canonical docs use `docs/*.md` | [`src/vite-plugin/SPEC.md`](src/vite-plugin/SPEC.md), [`src/remark/SPEC.md`](src/remark/SPEC.md) |
35
35
  | PDF | Rasterized slide pages matching browser rendering | [`src/cli/SPEC.md`](src/cli/SPEC.md) |
36
- | Syntax highlighting | Built-in code highlighting with runtime step dimming | [`src/remark/SPEC.md`](src/remark/SPEC.md) |
36
+ | Syntax highlighting | Built-in code highlighting, runtime step dimming, and Magic Code transitions | [`src/remark/SPEC.md`](src/remark/SPEC.md) |
37
37
  | Icons | `lucide-react` suffixed `...Icon` component imports | [`src/SPEC.md`](src/SPEC.md) |
38
38
  | Public imports | Explicit import subpaths for components, layouts, themes, and types | [`src/SPEC.md`](src/SPEC.md) |
39
39
 
@@ -55,9 +55,9 @@ The Honeydeck specification is distributed:
55
55
  | Starter templates | [`src/cli/templates/SPEC.md`](src/cli/templates/SPEC.md) | generated project tree, starter `deck.mdx`, `styles.css`, demo component |
56
56
  | Agent skills | [`skills/SPEC.md`](skills/SPEC.md) | bundled installable skills and installer expectations |
57
57
  | Deck loading / frontmatter | [`src/vite-plugin/SPEC.md`](src/vite-plugin/SPEC.md) | deck entry, slide separators, MDX imports, assets, Markdown features, frontmatter |
58
- | Remark transforms | [`src/remark/SPEC.md`](src/remark/SPEC.md) | code highlighting and step-through code metadata |
58
+ | Remark transforms | [`src/remark/SPEC.md`](src/remark/SPEC.md) | timeline annotation, code highlighting, step-through code metadata, and Magic Code syntax |
59
59
  | Runtime | [`src/runtime/SPEC.md`](src/runtime/SPEC.md) | timeline semantics, keyboard/touch navigation, SPA/build behavior, runtime errors |
60
- | Runtime components | [`src/runtime/components/SPEC.md`](src/runtime/components/SPEC.md) | `Reveal`, `RevealGroup`, `TimelineSteps`, `ListStyle`, `Keyboard`, `BrowserFrame`, `Notes` |
60
+ | Runtime components | [`src/runtime/components/SPEC.md`](src/runtime/components/SPEC.md) | `Reveal`, `RevealWith`, `RevealGroup`, `Fade`, `FadeWith`, `FadeGroup`, `TimelineSteps`, `ListStyle`, `Keyboard`, `BrowserFrame`, `Notes` |
61
61
  | Runtime views | [`src/runtime/views/SPEC.md`](src/runtime/views/SPEC.md) | presenter mode, overview mode, theme/layout/component reference pages |
62
62
  | Layouts and customization | [`src/layouts/SPEC.md`](src/layouts/SPEC.md) | custom theme/layout/component model, built-in layouts, layout props, demos, layout resolution |
63
63
  | Theme | [`src/theme/SPEC.md`](src/theme/SPEC.md) | design tokens, base theme CSS, Tailwind mapping, color mode behavior |
@@ -0,0 +1,34 @@
1
+ # BrowserFrame
2
+
3
+ Use `<BrowserFrame>` to show a live iframe inside a macOS-style browser window.
4
+
5
+ ```mdx
6
+ import { BrowserFrame } from '@honeydeck/honeydeck'
7
+
8
+ <BrowserFrame
9
+ src="https://example.com"
10
+ addressBar="example.com"
11
+ fallbackImage="/example-fallback-light.png"
12
+ fallbackDarkImage="/example-fallback-dark.png"
13
+ />
14
+ ```
15
+
16
+ The component renders browser chrome with macOS traffic-light controls and an optional address bar. It can show a light or dark fallback screenshot when the iframe cannot be loaded. It uses Honeydeck theme tokens for the frame, border, typography, and iframe surface.
17
+
18
+ ## Props
19
+
20
+ | Prop | Type | Default | Description |
21
+ | --- | --- | --- | --- |
22
+ | `src` | `string` | Required | URL loaded by the iframe. Use an external `https://` URL or a local Vite-served route like `/demo.html`. |
23
+ | `addressBar` | `ReactNode` | — | Optional content shown in the address-bar field. Omit it to hide the input-like address field. |
24
+ | `fallbackImage` | `string` | — | Light/default screenshot shown when iframe loading fails or fallback mode is toggled on. |
25
+ | `fallbackDarkImage` | `string` | — | Dark-mode screenshot shown when fallback mode is active. Falls back to `fallbackImage` when omitted. |
26
+ | `fallbackAlt` | `string` | `Fallback preview` | Accessible alt text for fallback images. |
27
+ | `defaultFallback` | `boolean` | `false` | Starts in fallback mode instead of loading the iframe. Useful for deterministic demos, final-state screenshots, and PDF-friendly decks. |
28
+ | `aspectRatio` | `CSSProperties["aspectRatio"]` | `16 / 9` | Aspect ratio for the full browser window, including chrome. Accepts values such as `16 / 9`, `"4 / 3"`, or `1.6`. |
29
+ | `className` | `string` | — | Additional CSS class for the outer browser frame. |
30
+ | `iframeClassName` | `string` | — | Additional CSS class for the iframe element. Only applies while live iframe content is rendered. |
31
+
32
+ Standard iframe attributes such as `allow`, `sandbox`, `loading`, and `referrerPolicy` are forwarded.
33
+
34
+ When fallback mode is active, the browser frame shows a badge in the top chrome, visually aligned with the address bar. A fourth round control sits beside the macOS traffic-light controls and only becomes visible when the control itself is hovered or keyboard-focused; it toggles fallback mode.
@@ -0,0 +1,31 @@
1
+ # Keyboard
2
+
3
+ Use `<Keyboard>` to show one key or a shortcut in slide prose.
4
+
5
+ ```mdx
6
+ import { Keyboard } from '@honeydeck/honeydeck'
7
+
8
+ Press <Keyboard>Esc</Keyboard> to close overview.
9
+
10
+ Advance with <Keyboard keys="Space" />.
11
+
12
+ Open command palette with <Keyboard keys={["Ctrl", "Shift", "P"]} />.
13
+ ```
14
+
15
+ `keys` accepts a single value or an ordered array. When `keys` is omitted, `children` is rendered as one key. Array values render one `<kbd>` per key, separated by `+` by default:
16
+
17
+ ```mdx
18
+ <Keyboard keys={["⌘", "K"]} />
19
+ <Keyboard keys={["Ctrl", "Alt", "Delete"]} separator=" " />
20
+ ```
21
+
22
+ ## Props
23
+
24
+ | Prop | Type | Default | Description |
25
+ | --- | --- | --- | --- |
26
+ | `keys` | `ReactNode \| ReactNode[]` | — | Key label or ordered shortcut key labels. |
27
+ | `children` | `ReactNode` | — | Single key label when `keys` is omitted. |
28
+ | `separator` | `ReactNode` | `+` | Separator rendered between array entries. |
29
+ | `className` | `string` | — | Custom class for the outer wrapper. |
30
+
31
+ The component uses semantic `<kbd>` markup, is inline by default, uses Honeydeck theme styling, and does not add timeline steps.
@@ -0,0 +1,49 @@
1
+ # ListStyle
2
+
3
+ Use `<ListStyle>` to style Markdown, HTML, or JSX lists inside a wrapper.
4
+
5
+ By default it removes native markers:
6
+
7
+ ```mdx
8
+ import { ListStyle } from '@honeydeck/honeydeck'
9
+
10
+ <ListStyle>
11
+ - No marker
12
+ - Still aligned
13
+ </ListStyle>
14
+ ```
15
+
16
+ Pass `bullets` to render custom markers:
17
+
18
+ ```mdx
19
+ import { ListStyle } from '@honeydeck/honeydeck'
20
+ import { CheckIcon, CircleIcon } from 'lucide-react'
21
+
22
+ <ListStyle bullets={[<CheckIcon />, <CircleIcon />]}>
23
+ - Level one uses a check icon
24
+ - Level two uses a circle icon
25
+ </ListStyle>
26
+
27
+ <ListStyle bullets={["→", "–", "·"]}>
28
+ - Level one
29
+ - Level two
30
+ - Level three
31
+ </ListStyle>
32
+ ```
33
+
34
+ ## Props
35
+
36
+ | Prop | Type | Default | Description |
37
+ | --- | --- | --- | --- |
38
+ | `children` | `ReactNode` | — | List content to style. |
39
+ | `bullets` | `ReactNode \| ReactNode[] \| false \| "none" \| null` | `undefined` | Marker config. Omit it, pass `false`, `"none"`, or `null` for markerless lists. |
40
+ | `className` | `string` | — | Custom class for the wrapper. |
41
+ | `style` | `CSSProperties` | — | Inline style for the wrapper. |
42
+
43
+ ## Behavior
44
+
45
+ - Native list markers are removed for all nested lists in the wrapper.
46
+ - A single `bullets` value is reused for every nesting level.
47
+ - An array uses one marker per nesting level.
48
+ - Deeper levels reuse the last configured marker.
49
+ - Custom markers apply to authored list elements passed as children.
@@ -0,0 +1,36 @@
1
+ # Notes
2
+
3
+ Use `<Notes>` to add presenter-only speaker notes to a slide.
4
+
5
+ ```mdx
6
+ import { Notes } from '@honeydeck/honeydeck'
7
+
8
+ # Launch plan
9
+
10
+ - What changed
11
+ - Why it matters
12
+
13
+ <Notes>
14
+ # Demo cue
15
+
16
+ - Demo the interactive component.
17
+ - Mention PDF export.
18
+ </Notes>
19
+ ```
20
+
21
+ Notes render nothing in audience view, overview thumbnails, and normal PDF output. In presenter mode, Markdown inside `<Notes>` renders as formatted speaker notes, including headings, paragraphs, lists, links, inline code, code blocks, and block quotes.
22
+
23
+ ## Props
24
+
25
+ | Prop | Type | Default | Description |
26
+ | --- | --- | --- | --- |
27
+ | `children` | `ReactNode` | — | Speaker-note content collected by presenter mode. |
28
+
29
+ ## Behavior
30
+
31
+ - `<Notes>` is a no-op outside presenter mode.
32
+ - Notes are collected from the current slide preview in presenter mode.
33
+ - Updating the slide notes updates the presenter notes panel.
34
+ - You can use Markdown inside Notes.
35
+
36
+ See [Presenter mode](presenter-mode.md) for the full presenter workflow.
@@ -0,0 +1,58 @@
1
+ # RevealGroup
2
+
3
+ Use `<RevealGroup>` when a short sequence should appear one item at a time.
4
+
5
+ ```mdx
6
+ import { RevealGroup } from '@honeydeck/honeydeck'
7
+
8
+ <RevealGroup>
9
+ - First point
10
+ - Second point
11
+ - Third point
12
+ </RevealGroup>
13
+ ```
14
+
15
+ Each meaningful direct child becomes one timeline step. Whitespace-only text children are ignored. Markdown, HTML, and JSX lists are special: each top-level list item is revealed one after another while preserving the list container.
16
+
17
+ Use `listRevealMode="nested"` when nested list items should also become individual steps:
18
+
19
+ ```mdx
20
+ <RevealGroup listRevealMode="nested">
21
+ - Parent
22
+ - Child A
23
+ - Child B
24
+ - Sibling
25
+ </RevealGroup>
26
+ ```
27
+
28
+ Timeline: parent → child A → child B → sibling. The default mode is `"direct"`, which keeps nested items grouped with their parent.
29
+
30
+ To reveal multiple elements together, wrap them in one direct child:
31
+
32
+ ```mdx
33
+ <RevealGroup>
34
+ <div>
35
+ <h3>One idea</h3>
36
+ <p>Supporting context appears with it.</p>
37
+ </div>
38
+ <div>Next idea</div>
39
+ </RevealGroup>
40
+ ```
41
+
42
+ Nested timeline entries inside a group target are flattened after that target and before the following group target:
43
+
44
+ ```mdx
45
+ <RevealGroup>
46
+ <div>
47
+ Parent item
48
+ <Reveal>Nested detail</Reveal>
49
+ </div>
50
+ <div>Sibling item</div>
51
+ </RevealGroup>
52
+ ```
53
+
54
+ **Timeline:**
55
+
56
+ 1. Parent item appears
57
+ 2. Nested detail appears
58
+ 3. Sibling item appears
@@ -0,0 +1,37 @@
1
+ # RevealWith
2
+
3
+ Use `<RevealWith>` when content should appear at the same timeline step as a named `<Reveal>` or any existing numeric slide step. It never adds a new step.
4
+
5
+ ````mdx
6
+ import { Reveal, RevealWith } from '@honeydeck/honeydeck'
7
+
8
+ <Reveal name="intro">Intro appears first</Reveal>
9
+ <RevealWith target="intro">This appears with the intro reveal</RevealWith>
10
+
11
+ ```ts {1|2|3}
12
+ const answer = 42
13
+ console.log(answer)
14
+ ```
15
+
16
+ <RevealWith at={2}>This appears with step 2</RevealWith>
17
+ ````
18
+
19
+ ## Props
20
+
21
+ | Prop | Type | Default | Description |
22
+ | --- | --- | --- | --- |
23
+ | `target` | `string` | — | Same-slide `<Reveal name="...">` target. Must be a literal non-empty string. Use exactly one of `target` or `at`. |
24
+ | `at` | `number` | resolved/injected | Existing 1-based slide-local timeline step. Must be a literal positive integer when authored. Use exactly one of `target` or `at`. |
25
+ | `children` | `ReactNode` | — | Content to reveal with the target step. |
26
+ | `className` | `string` | — | Custom class for styling or transitions. |
27
+ | `as` | `"div" | "span"` | injected | Wrapper element. Honeydeck injects this to keep valid MDX/HTML around block or inline content. |
28
+
29
+ ## Behavior
30
+
31
+ - `RevealWith` is cumulative like `Reveal`: once visible, it stays visible.
32
+ - `target` supports forward references to named reveals later on the same slide.
33
+ - `at` can target any existing slide step, including a `RevealGroup` item, code highlight, Magic Code state, or `TimelineSteps` state.
34
+ - Hidden content reserves layout space and uses the same fade/future-preview behavior as `Reveal`.
35
+ - Invalid targets, duplicate reveal names, non-literal values, and out-of-range numeric steps are build errors.
36
+
37
+ See [Steps and reveals](steps-and-reveals.md#revealwith) for timeline ordering examples.
@@ -0,0 +1,33 @@
1
+ # Reveal
2
+
3
+ Use `<Reveal>` when content should appear at the next timeline step.
4
+
5
+ ```mdx
6
+ import { Reveal } from '@honeydeck/honeydeck'
7
+
8
+ <Reveal>Start with Markdown</Reveal>
9
+ <Reveal>Enhance with React</Reveal>
10
+ <Reveal>Export to PDF</Reveal>
11
+ ```
12
+
13
+ Reveals are cumulative: once visible, they stay visible while you advance through the slide. Hidden reveal content reserves layout space, so the slide does not jump when the content appears.
14
+
15
+ ## Props
16
+
17
+ | Prop | Type | Default | Description |
18
+ | --- | --- | --- | --- |
19
+ | `children` | `ReactNode` | — | Content to reveal. |
20
+ | `name` | `string` | — | Optional slide-local target for [`RevealWith target="..."`](components-reveal-with.md). Must be a literal non-empty string. |
21
+ | `className` | `string` | — | Custom class for styling or transitions. |
22
+ | `at` | `number` | injected | Timeline step. Honeydeck injects this during compilation; author-authored values are build errors. Use [`RevealWith`](components-reveal-with.md) to sync with an existing step. |
23
+ | `as` | `"div" \| "span"` | injected | Wrapper element. Honeydeck injects this to keep valid MDX/HTML around block or inline content. |
24
+
25
+ ## Behavior
26
+
27
+ - Reveals fade in.
28
+ - Hidden content uses `visibility: hidden` plus `opacity: 0`, not `display: none`.
29
+ - Nested reveals are supported.
30
+ - Inline reveals inside paragraphs render inline wrappers.
31
+ - Optional `name="..."` creates a slide-local target for [`RevealWith`](components-reveal-with.md).
32
+
33
+ See [Steps and reveals](steps-and-reveals.md) for timeline ordering examples.
@@ -0,0 +1,48 @@
1
+ # TimelineSteps
2
+
3
+ Use `<TimelineSteps>` when an imported React component should control part of a slide timeline.
4
+
5
+ ```mdx
6
+ import { Reveal, TimelineSteps } from '@honeydeck/honeydeck'
7
+ import { AccordionDemo } from './AccordionDemo'
8
+
9
+ <Reveal>Before the custom component</Reveal>
10
+
11
+ <TimelineSteps steps={3}>
12
+ <AccordionDemo />
13
+ </TimelineSteps>
14
+
15
+ <Reveal>After the custom component</Reveal>
16
+ ```
17
+
18
+ Inside the custom component, read local step state with `useTimelineSteps()`:
19
+
20
+ ```tsx
21
+ import { useTimelineSteps } from '@honeydeck/honeydeck'
22
+
23
+ export function AccordionDemo() {
24
+ const { phase, stepIndex, stepCount, isPdfFinalRender } = useTimelineSteps()
25
+
26
+ return <div>Step {stepIndex} of {stepCount}</div>
27
+ }
28
+ ```
29
+
30
+ ## Props
31
+
32
+ | Prop | Type | Default | Description |
33
+ | --- | --- | --- | --- |
34
+ | `steps` | `number` | Required | Literal positive integer number of reserved timeline steps. |
35
+ | `children` | `ReactNode` | — | Custom component content. |
36
+
37
+ `useTimelineSteps()` returns `{ phase, stepIndex, stepCount, startAt, endAt, isPdfFinalRender }`.
38
+
39
+ - `phase` is `"before"`, `"active"`, or `"after"`.
40
+ - `stepIndex` is `0` before start, `1..stepCount` while active, and `stepCount` after end.
41
+ - `isPdfFinalRender` is `true` only for one-page final-state PDF export.
42
+
43
+ ## Rules
44
+
45
+ - `steps` must be a literal positive integer in slide MDX, for example `steps={3}`.
46
+ - `<TimelineSteps>` must appear at the usage site in slide MDX. Imported TSX components cannot register steps by rendering `<TimelineSteps>` internally.
47
+ - Nested Honeydeck timeline producers inside `<TimelineSteps>` are not supported.
48
+ - In `isPdfFinalRender`, allows custom components to controll how they appear in PDFs.
@@ -3,61 +3,20 @@
3
3
  Honeydeck core components are explicit imports from `@honeydeck/honeydeck`. They are also exported from `@honeydeck/honeydeck/components`.
4
4
 
5
5
  ```mdx
6
- import { Keyboard } from '@honeydeck/honeydeck'
6
+ import { Reveal, RevealWith, RevealGroup, TimelineSteps, ListStyle, Keyboard, BrowserFrame, Notes } from '@honeydeck/honeydeck'
7
7
  ```
8
8
 
9
- ## BrowserFrame
9
+ Use these pages as the component reference:
10
10
 
11
- Use `<BrowserFrame>` to show a live iframe inside a macOS-style browser window.
11
+ | Component | Use it for |
12
+ | --- | --- |
13
+ | [`Reveal`](components-reveal.md) | Show content at a specific slide timeline step. |
14
+ | [`RevealWith`](components-reveal-with.md) | Show content with an existing reveal or numeric slide step without adding another step. |
15
+ | [`RevealGroup`](components-reveal-group.md) | Reveal each direct child or list item one after another, with optional nested-list reveals. |
16
+ | [`TimelineSteps`](components-timeline-steps.md) | Reserve timeline steps for an imported custom React component. |
17
+ | [`ListStyle`](components-list-style.md) | Style Markdown, HTML, or JSX lists with no markers or custom markers. |
18
+ | [`Keyboard`](components-keyboard.md) | Render semantic inline keyboard keys and shortcuts. |
19
+ | [`BrowserFrame`](components-browser-frame.md) | Show a live iframe or fallback screenshot inside browser chrome. |
20
+ | [`Notes`](components-notes.md) | Add formatted speaker notes for presenter mode. |
12
21
 
13
- ```mdx
14
- import { BrowserFrame } from '@honeydeck/honeydeck'
15
-
16
- <BrowserFrame
17
- src="https://example.com"
18
- addressBar="example.com"
19
- fallbackImage="/example-fallback-light.png"
20
- fallbackDarkImage="/example-fallback-dark.png"
21
- />
22
- ```
23
-
24
- The component renders browser chrome with macOS traffic-light controls and an optional address bar. It can show a light or dark fallback screenshot when the iframe cannot be loaded. It uses Honeydeck theme tokens for the frame, border, typography, and iframe surface.
25
-
26
- Props:
27
-
28
- | Prop | Type | Default | Description |
29
- | --- | --- | --- | --- |
30
- | `src` | `string` | Required | URL loaded by the iframe. Use an external `https://` URL or a local Vite-served route like `/demo.html`. |
31
- | `addressBar` | `ReactNode` | — | Optional content shown in the address-bar field. Omit it to hide the input-like address field. |
32
- | `fallbackImage` | `string` | — | Light/default screenshot shown when iframe loading fails or fallback mode is toggled on. |
33
- | `fallbackDarkImage` | `string` | — | Dark-mode screenshot shown when fallback mode is active. Falls back to `fallbackImage` when omitted. |
34
- | `fallbackAlt` | `string` | `Fallback preview` | Accessible alt text for fallback images. |
35
- | `defaultFallback` | `boolean` | `false` | Starts in fallback mode instead of loading the iframe. Useful for deterministic demos, final-state screenshots, and PDF-friendly decks. |
36
- | `aspectRatio` | `CSSProperties["aspectRatio"]` | `16 / 9` | Aspect ratio for the full browser window, including chrome. Accepts values such as `16 / 9`, `"4 / 3"`, or `1.6`. |
37
- | `className` | `string` | — | Additional CSS class for the outer browser frame. |
38
- | `iframeClassName` | `string` | — | Additional CSS class for the iframe element. Only applies while live iframe content is rendered. |
39
-
40
- Standard iframe attributes such as `allow`, `sandbox`, `loading`, and `referrerPolicy` are forwarded.
41
-
42
- When fallback mode is active, the browser frame shows a badge in the top chrome, visually aligned with the address bar. A fourth round control sits beside the macOS traffic-light controls and only becomes visible when the control itself is hovered or keyboard-focused; it toggles fallback mode.
43
-
44
- ## Keyboard
45
-
46
- Use `<Keyboard>` to show one key or a shortcut in slide prose.
47
-
48
- ```mdx
49
- Press <Keyboard>Esc</Keyboard> to close overview.
50
-
51
- Advance with <Keyboard keys="Space" />.
52
-
53
- Open command palette with <Keyboard keys={["Ctrl", "Shift", "P"]} />.
54
- ```
55
-
56
- `keys` accepts a single value or an ordered array. When `keys` is omitted, `children` is rendered as one key. Array values render one `<kbd>` per key, separated by `+` by default:
57
-
58
- ```mdx
59
- <Keyboard keys={["⌘", "K"]} />
60
- <Keyboard keys={["Ctrl", "Alt", "Delete"]} separator=" " />
61
- ```
62
-
63
- The component is inline by default, uses Honeydeck theme styling, supports `className`, and does not add timeline steps.
22
+ For broader timing concepts, see [Steps and reveals](steps-and-reveals.md). For custom components and layouts, see [Customization](customization.md).
@@ -15,6 +15,7 @@ Defined in the first frontmatter block of the deck entry file (before any slide
15
15
  | `pdfColorMode` | `"light" \| "dark"` | unset | Optional PDF color mode; when unset, falls back to pinned `colorMode`, then `light` |
16
16
  | `pdfSteps` | `"final" \| "all"` | `"final"` | PDF includes all steps or final state |
17
17
  | `transition` | `boolean` | `true` | Enable crossfade between slides |
18
+ | `magicCodeDuration` | `number` | `800` | Default Magic Code animation duration in milliseconds |
18
19
  | `layouts` | `string` | `""` (built-in) | Layout map module path |
19
20
  | `defaultLayout` | `string` | `"Default"` | Layout used when slide has no `layout:` |
20
21
  | `showSlideNumbers` | `boolean` | `false` | Show the current slide number in the bottom-right corner of slides |
@@ -50,6 +51,16 @@ transition: true # default
50
51
  transition: false # disable
51
52
  ```
52
53
 
54
+ ### Magic Code Duration
55
+
56
+ Magic Code animations default to 800ms. Set a deck-wide default with `magicCodeDuration`:
57
+
58
+ ```yaml
59
+ magicCodeDuration: 500
60
+ ```
61
+
62
+ A Magic Code block can override this locally with `{duration:500}`. Slide-level frontmatter does not configure Magic Code; the same key in slide frontmatter is treated as a layout prop.
63
+
53
64
  ## Slide-Level Settings
54
65
 
55
66
  Per-slide frontmatter (after `---`):
@@ -128,7 +128,7 @@ For the full reference, see [Configuration](configuration.md).
128
128
  Core runtime components are explicit imports from `honeydeck`.
129
129
 
130
130
  ```mdx
131
- import { Reveal, RevealGroup, TimelineSteps, BrowserFrame, Notes } from '@honeydeck/honeydeck'
131
+ import { Reveal, RevealWith, RevealGroup, TimelineSteps, BrowserFrame, Notes } from '@honeydeck/honeydeck'
132
132
  ```
133
133
 
134
134
  ### Reveal steps
@@ -136,11 +136,18 @@ import { Reveal, RevealGroup, TimelineSteps, BrowserFrame, Notes } from '@honeyd
136
136
  `<Reveal>` reveals content at the next timeline step. Hidden content keeps its layout space so the slide does not jump.
137
137
 
138
138
  ```mdx
139
- <Reveal>Appears at step 1</Reveal>
139
+ <Reveal name="first">Appears at step 1</Reveal>
140
140
  <Reveal>Appears at step 2</Reveal>
141
141
  ```
142
142
 
143
- `<RevealGroup>` wraps each direct child in a reveal step. Markdown and HTML lists are special: each list item reveals one after another.
143
+ `<RevealWith>` syncs extra content to an existing step without adding a step:
144
+
145
+ ```mdx
146
+ <RevealWith target="first">Appears with step 1</RevealWith>
147
+ <RevealWith at={2}>Appears with step 2</RevealWith>
148
+ ```
149
+
150
+ `<RevealGroup>` wraps each direct child in a reveal step. Markdown and HTML lists are special: each top-level list item reveals one after another. Use `listRevealMode="nested"` to reveal nested list items depth-first.
144
151
 
145
152
  ```mdx
146
153
  <RevealGroup>
@@ -202,6 +209,22 @@ console.log(b)
202
209
  - `{2-3|5|all}` starts with lines 2-3 active, then steps to line 5, then all lines.
203
210
  - Highlight groups after the first interleave with `<Reveal>` in document order.
204
211
 
212
+ Magic Code animates between multiple code states. It builds on Shiki Magic Code / Shiki Magic Move while keeping Honeydeck's build-time highlighting and timeline behavior:
213
+
214
+ `````mdx
215
+ ````md magic-code {duration:500}
216
+ ```ts
217
+ const count = 1
218
+ ```
219
+
220
+ ```ts
221
+ const count = 2
222
+ ```
223
+ ````
224
+ `````
225
+
226
+ Each inner code fence is a state. Inner code fence line metadata still works, so Honeydeck advances through a state's highlight groups before morphing to the next code state. Content inside a Magic Code block that is not a fenced code block is ignored. `md magic-move` is accepted as a Slidev compatibility alias, but Honeydeck docs and examples use `md magic-code`.
227
+
205
228
  ## Navigation, presenting, and PDF
206
229
 
207
230
  Keyboard shortcuts:
@@ -213,7 +236,7 @@ Keyboard shortcuts:
213
236
  | `down` / `s` | Next slide |
214
237
  | `up` / `w` | Previous slide |
215
238
  | `o` | Toggle overview mode |
216
- | `p` | Open presenter mode |
239
+ | `p` | Open presenter mode in the current tab |
217
240
  | `f` | Toggle fullscreen |
218
241
  | `Escape` | Exit overview or fullscreen |
219
242
 
@@ -236,7 +259,7 @@ Presenter mode opens with `p` and includes:
236
259
  - speaker notes from `<Notes>`
237
260
  - slide/step counter and wall clock
238
261
  - an "Open audience view" button
239
- - audience sync through `BroadcastChannel`
262
+ - audience sync through `BroadcastChannel`, with Presentation API casting when supported
240
263
 
241
264
  See [Navigation](navigation.md), [Mobile and touch](mobile.md), [Presenter mode](presenter-mode.md), and [PDF export](pdf-export.md).
242
265
 
@@ -328,7 +351,7 @@ Package Markdown guides live on the Honeydeck docs site and in the package `docs
328
351
  | Layouts | Runtime dynamic import of the layout map |
329
352
  | Tailwind | v4 CSS-first; Honeydeck adds the Vite plugin internally |
330
353
  | Shiki | Dual-theme CSS variables with build-time highlighting |
331
- | Presenter sync | `BroadcastChannel`, unidirectional, no server needed |
354
+ | Presenter sync | `BroadcastChannel` fallback + Presentation API casting, no server needed |
332
355
  | Scaling | `transform: scale()` from the configured aspect ratio |
333
356
  | Build | `tsc` only, ESM, no bundler |
334
357
  | Testing | `node:test` plus fixture files |
@@ -336,7 +359,7 @@ Package Markdown guides live on the Honeydeck docs site and in the package `docs
336
359
  ## Types and exports
337
360
 
338
361
  ```ts
339
- import { Reveal, RevealGroup, Notes } from '@honeydeck/honeydeck'
362
+ import { Reveal, RevealWith, RevealGroup, Notes } from '@honeydeck/honeydeck'
340
363
  import type { LayoutProps, LayoutMap, LayoutDemo } from '@honeydeck/honeydeck/types'
341
364
 
342
365
  import defaultLayouts from '@honeydeck/honeydeck/layouts'
@@ -70,7 +70,7 @@ Use `layout:` to choose a slide layout. Built-in layouts include `Blank`, `Defau
70
70
  - Vite dev/build with hot reload
71
71
  - Built-in layouts and theme tokens
72
72
  - Tailwind v4-friendly styling
73
- - Reveal steps and code step-through
73
+ - Reveal steps, code step-through, and Magic Code transitions
74
74
  - Presenter mode with speaker notes
75
75
  - Overview mode, keyboard/touch navigation, and URL state
76
76
  - PDF export through headless Chromium
@@ -102,7 +102,7 @@ honeydeck skill # install optional Honeydeck agent skills
102
102
  - [Slides](slides.md) - separators, multiple files, layouts, and assets
103
103
  - [Configuration](configuration.md) - deck-level and slide-level frontmatter
104
104
  - [Steps and reveals](steps-and-reveals.md) - timeline, reveal groups, code steps, and PDF behavior
105
- - [Components](components.md) - core Honeydeck components such as `BrowserFrame` and `Keyboard`
105
+ - [Components](components.md) - core Honeydeck components such as `Reveal`, `RevealWith`, `TimelineSteps`, `BrowserFrame`, and `Keyboard`
106
106
  - [Customization](customization.md) - themes, layout sets, Tailwind tokens, custom layouts, and layout demos
107
107
  - [Navigation](navigation.md) - keyboard, touch, overview mode, and URL state
108
108
  - [Mobile and touch](mobile.md) - mobile controls, touch gestures, and pinch zoom
@@ -9,7 +9,7 @@
9
9
  | `↓` / `s` | Next slide |
10
10
  | `↑` / `w` | Previous slide |
11
11
  | `o` | Toggle overview mode |
12
- | `p` | Open presenter mode (new window) |
12
+ | `p` | Open presenter mode (same tab) |
13
13
  | `f` | Toggle fullscreen |
14
14
  | `Escape` | Exit overview / exit fullscreen |
15
15
 
@@ -51,14 +51,16 @@ Honeydeck builds an ordered capture plan before taking screenshots. The final PD
51
51
 
52
52
  When `pdfSteps: all`:
53
53
 
54
- - Each `Reveal`/`RevealGroup` step becomes a separate page.
54
+ - Each `Reveal`/`RevealGroup` step becomes a separate page. `RevealWith` appears on the page for its target step and adds no extra page.
55
55
  - Stepped code blocks show their first highlight group on the baseline page; each later code highlight group becomes a separate page.
56
- - Both use the same underlying timeline.
56
+ - Magic Code blocks show their first inner code fence on the baseline page; later line-highlight states and code morph states become separate pages according to the same timeline.
57
+ - Reveals, stepped code blocks, Magic Code, and custom `TimelineSteps` blocks use the same underlying timeline.
57
58
 
58
59
  When `pdfSteps: final` (default):
59
60
 
60
61
  - All reveals shown in final (visible) state.
61
62
  - Code blocks shown with final highlight applied.
63
+ - Magic Code blocks shown at their final code state with final highlight applied.
62
64
  - `useTimeline()` and `useTimelineSteps()` expose `isPdfFinalRender: true`, so
63
65
  custom step-driven components can render an all-open/all-visible PDF state.
64
66
 
@@ -29,6 +29,7 @@ Includes:
29
29
  - Slide number / step counter
30
30
  - Wall clock
31
31
  - Button to open audience view in a new tab/window
32
+ - Button to cast the audience view to a secondary display when supported; the same control becomes a stop button while casting and is disabled with a hint when unsupported
32
33
  - Navigation buttons that move through the timeline while staying in presenter mode
33
34
 
34
35
  ## Speaker Notes
@@ -58,11 +59,11 @@ Content here.
58
59
 
59
60
  ## Opening Presenter Mode
60
61
 
61
- - Keyboard shortcut `p` from normal presentation → opens in a new window/tab.
62
+ - Keyboard shortcut `p` from normal presentation → opens presenter mode in the current tab.
62
63
  - Navigation controls button in normal presentation.
63
64
  - Direct URL: `/#/presenter/1/0`
64
65
 
65
- Pressing `p` opens presenter mode in a **new window** so the audience view stays on the projector.
66
+ Pressing `p` opens presenter mode in the **current tab**.
66
67
 
67
68
  ## Navigation
68
69
 
@@ -85,10 +86,12 @@ When no next timeline state exists, the `Next` preview shows an end-of-deck plac
85
86
 
86
87
  ## Presenter/Audience Sync
87
88
 
88
- Presenter mode and audience view synchronize navigation via `BroadcastChannel` in the same browser/profile.
89
+ Presenter mode and audience view synchronize navigation via `BroadcastChannel` and, when supported, the Presentation API.
89
90
 
90
91
  - Presenter mode acts as the controller.
91
92
  - Audience view (opened from presenter mode) listens for navigation updates.
93
+ - The cast audience sends a `sync-request` as soon as the receiver connection appears; the presenter replies with the current slide/step in a `sync-response` so late connections resync immediately.
94
+ - The cast audience follows presenter navigation through Presentation API receiver messages.
92
95
  - No server, internet, WebSocket, or device pairing required.
93
96
  - If `BroadcastChannel` is unavailable, both views function independently.
94
97