add speaker notes for slides#9533
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Bundle ReportChanges will increase total bundle size by 75.3kB (0.3%) ⬆️. This is within the configured threshold ✅ Detailed changes
Affected Assets, Files, and Routes:view changes for bundle: marimo-esmAssets Changed:
Files in
Files in
Files in
|
There was a problem hiding this comment.
1 issue found across 9 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="frontend/src/components/slides/slide-notes-editor.tsx">
<violation number="1" location="frontend/src/components/slides/slide-notes-editor.tsx:45">
P2: Switching slides before the debounce fires can drop recent speaker-note edits. Flush or persist pending text when `cellId` changes/unmounts so fast navigation doesn't lose input.</violation>
</file>
Architecture diagram
sequenceDiagram
participant User as User (Browser)
participant SlidesUI as SlidesLayoutRenderer
participant Deck as Reveal Deck Component
participant NotesPlugin as Reveal Notes Plugin
participant KioskIframe as Kiosk Iframe (Speaker View)
participant NotesEditor as SlideNotesEditor
participant Store as Layout Store (Jotai)
Note over User,Store: Slide Presentation Flow with Speaker Notes
User->>SlidesUI: Interact with slides (navigate, edit)
SlidesUI->>SlidesUI: Determine isReading mode (read OR kiosk flag)
alt Kiosk Mode Active (speaker view iframe)
SlidesUI->>SlidesUI: Collapse to read-only layout (hide chrome)
end
User->>NotesEditor: Type/Edit speaker notes for current slide
NotesEditor->>NotesEditor: Debounce input (300ms)
NotesEditor->>Store: Persist updated speakerNotes in SlideConfig map
Store-->>NotesEditor: Confirm update
User->>Deck: Press 'S' to open speaker view
Deck->>NotesPlugin: Initialize Notes plugin
NotesPlugin->>KioskIframe: Create kiosk iframe with ?kiosk=true&show-chrome=false
Note over NotesPlugin,KioskIframe: Kiosk URL includes current slide context
alt Kiosk iframe loads (inside speaker view)
KioskIframe->>SlidesUI: Load read-only slide deck (kioskMode=true)
SlidesUI->>Deck: Render slides with isReading=true
Deck->>Deck: Skip RevealNotes plugin (no nested speaker view)
Note over KioskIframe,Deck: Shows slide content + inline notes aside
end
Note over Deck,Store: Slide Rendering with Notes Injection
SlidesUI->>Deck: Pass slideConfigs (with speakerNotes) to SubslideView
Deck->>Deck: buildSubslideNotes() for each subslide
Deck->>Deck: Compute slideLevel notes + cumulativeByBlock per fragment
alt Fragment block has notes
Deck->>Deck: Inject NotesAside (aside.notes) inside Fragment element
else Slide-level notes exist (non-fragment)
Deck->>Deck: Inject NotesAside outside fragment containers
end
User->>Deck: Navigate slides / reveal fragments
Deck->>Deck: Update active slide index and fragment index
Deck->>NotesPlugin: Report slide change
NotesPlugin->>KioskIframe: Update preview in speaker view
alt User edits notes while presenting (only in main deck, not kiosk)
User->>NotesEditor: Edit text
NotesEditor->>Store: Save new notes
Store-->>NotesEditor: Updated config
NotesEditor->>Deck: Re-render with updated notes (via layout state)
end
Note over Deck,Store: Kiosk Mode Bypass
alt Deck is inside kiosk iframe
Deck->>Deck: Skip keyboard event propagation (stopPropagation on textarea)
Deck->>Deck: Disable Notes plugin to prevent nested popups
Deck->>NotesPlugin: Not initialized (plugin list empty)
end
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
There was a problem hiding this comment.
Pull request overview
Adds speaker notes support for slides, including editable notes in the slides authoring UI and Reveal speaker-view integration.
Changes:
- Adds
speakerNotesto slide layout config and smoke-test layout data. - Adds helper logic and tests for aggregating slide/fragment notes.
- Adds a notes editor panel, resize handle styling, kiosk handling, and Reveal notes plugin wiring.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
marimo/_smoke_tests/slides_examples/nested_slides.py |
Updates generated version metadata. |
marimo/_smoke_tests/slides_examples/layouts/nested_slides.slides.json |
Adds sample speaker notes to slide config entries. |
frontend/src/components/slides/slides.css |
Adds resize-handle styling for the notes panel. |
frontend/src/components/slides/slide-notes.ts |
Adds helpers for collecting and accumulating notes. |
frontend/src/components/slides/slide-notes-editor.tsx |
Adds editable speaker notes textarea. |
frontend/src/components/slides/reveal-component.tsx |
Integrates notes rendering, Reveal notes plugin, kiosk URL, and notes panel layout. |
frontend/src/components/slides/__tests__/slide-notes.test.ts |
Adds tests for notes aggregation helpers. |
frontend/src/components/editor/renderers/slides-layout/types.ts |
Adds speakerNotes to slide config type. |
frontend/src/components/editor/renderers/slides-layout/slides-layout.tsx |
Treats kiosk clients as read-only slide renderers. |
There was a problem hiding this comment.
2 issues found across 6 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="frontend/src/components/slides/slide-notes-editor.tsx">
<violation number="1" location="frontend/src/components/slides/slide-notes-editor.tsx:55">
P2: `draft` is only synchronized when `cellId` changes, so external note updates for the currently selected slide are not reflected in the textarea.</violation>
</file>
<file name="frontend/src/components/editor/renderers/slides-layout/__tests__/plugin.test.ts">
<violation number="1" location="frontend/src/components/editor/renderers/slides-layout/__tests__/plugin.test.ts:216">
P2: This case doesn’t actually verify that `speakerNotes` survives validation, so it won’t catch the schema dropping the field. Assert the parsed payload (or pass `parsed.data` into `deserializeLayout`) to make the regression test meaningful.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| if (prevCellIdRef.current !== cellId) { | ||
| persistDebounced.flush(); | ||
| setDraft(initialValue); | ||
| prevCellIdRef.current = cellId; | ||
| } |
There was a problem hiding this comment.
P2: draft is only synchronized when cellId changes, so external note updates for the currently selected slide are not reflected in the textarea.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At frontend/src/components/slides/slide-notes-editor.tsx, line 55:
<comment>`draft` is only synchronized when `cellId` changes, so external note updates for the currently selected slide are not reflected in the textarea.</comment>
<file context>
@@ -25,30 +28,51 @@ export const SlideNotesEditor = ({
+ // adopting the new slide's notes.
+ const prevCellIdRef = useRef(cellId);
+ useEffect(() => {
+ if (prevCellIdRef.current !== cellId) {
+ persistDebounced.flush();
+ setDraft(initialValue);
</file context>
| if (prevCellIdRef.current !== cellId) { | |
| persistDebounced.flush(); | |
| setDraft(initialValue); | |
| prevCellIdRef.current = cellId; | |
| } | |
| if (prevCellIdRef.current !== cellId) { | |
| persistDebounced.flush(); | |
| prevCellIdRef.current = cellId; | |
| } | |
| setDraft(initialValue); |
| @@ -209,6 +209,28 @@ const BACKWARDS_COMPAT_SNAPSHOTS: BackwardsCompatCase[] = [ | |||
| cellEntries: [["a", { type: "slide" }]], | |||
There was a problem hiding this comment.
P2: This case doesn’t actually verify that speakerNotes survives validation, so it won’t catch the schema dropping the field. Assert the parsed payload (or pass parsed.data into deserializeLayout) to make the regression test meaningful.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At frontend/src/components/editor/renderers/slides-layout/__tests__/plugin.test.ts, line 216:
<comment>This case doesn’t actually verify that `speakerNotes` survives validation, so it won’t catch the schema dropping the field. Assert the parsed payload (or pass `parsed.data` into `deserializeLayout`) to make the regression test meaningful.</comment>
<file context>
@@ -209,6 +209,28 @@ const BACKWARDS_COMPAT_SNAPSHOTS: BackwardsCompatCase[] = [
+ // `speakerNotes` was added to SlideConfig. The validator must
+ // know about it (so it isn't silently stripped), the deserializer must
+ // carry it through, and serialize → deserialize must round-trip it.
+ label: "speakerNotes round-trips through validate + (de)serialize",
+ input: {
+ cells: [
</file context>
📝 Summary
Screen.Recording.2026-05-12.at.5.32.23.PM.mov
📋 Pre-Review Checklist
✅ Merge Checklist