Skip to content

add speaker notes for slides#9533

Draft
Light2Dark wants to merge 2 commits into
mainfrom
sham/speaker-notes
Draft

add speaker notes for slides#9533
Light2Dark wants to merge 2 commits into
mainfrom
sham/speaker-notes

Conversation

@Light2Dark
Copy link
Copy Markdown
Collaborator

📝 Summary

Screen.Recording.2026-05-12.at.5.32.23.PM.mov

📋 Pre-Review Checklist

  • For large changes, or changes that affect the public API: this change was discussed or approved through an issue, on Discord, or the community discussions (Please provide a link if applicable).
  • Any AI generated code has been reviewed line-by-line by the human PR author, who stands by it.
  • Video or media evidence is provided for any visual changes (optional).

✅ Merge Checklist

  • I have read the contributor guidelines.
  • Documentation has been updated where applicable, including docstrings for API changes.
  • Tests have been added for the changes made.

@vercel
Copy link
Copy Markdown

vercel Bot commented May 13, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
marimo-docs Ready Ready Preview, Comment May 13, 2026 3:49pm

Request Review

@codecov
Copy link
Copy Markdown

codecov Bot commented May 13, 2026

Bundle Report

Changes will increase total bundle size by 75.3kB (0.3%) ⬆️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
marimo-esm 25.22MB 75.3kB (0.3%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: marimo-esm

Assets Changed:

Asset Name Size Change Total Size Change (%)
assets/index-*.js 1.06kB 607.79kB 0.17%
assets/index-*.css 372 bytes 366.39kB 0.1%
assets/dist-*.js -46 bytes 137 bytes -25.14%
assets/dist-*.js 79 bytes 183 bytes 75.96% ⚠️
assets/dist-*.js -65 bytes 104 bytes -38.46%
assets/dist-*.js 62 bytes 164 bytes 60.78% ⚠️
assets/dist-*.js -158 bytes 177 bytes -47.16%
assets/dist-*.js -35 bytes 102 bytes -25.55%
assets/dist-*.js -3 bytes 256 bytes -1.16%
assets/dist-*.js 82 bytes 259 bytes 46.33% ⚠️
assets/dist-*.js 79 bytes 335 bytes 30.86% ⚠️
assets/dist-*.js 127 bytes 403 bytes 46.01% ⚠️
assets/dist-*.js -227 bytes 176 bytes -56.33%
assets/dist-*.js 227 bytes 387 bytes 141.88% ⚠️
assets/dist-*.js 100 bytes 276 bytes 56.82% ⚠️
assets/dist-*.js -204 bytes 183 bytes -52.71%
assets/dist-*.js 5 bytes 169 bytes 3.05%
assets/dist-*.js 23 bytes 160 bytes 16.79% ⚠️
assets/dist-*.js -32 bytes 137 bytes -18.93%
assets/dist-*.js -14 bytes 169 bytes -7.65%
assets/edit-*.js -122 bytes 324.65kB -0.04%
assets/reveal-*.js 72.31kB 249.35kB 40.84% ⚠️
assets/layout-*.js 155 bytes 198.39kB 0.08%
assets/file-*.js 60 bytes 46.83kB 0.13%
assets/file-*.js 32 bytes 102.67kB 0.03%
assets/worker-*.js 140 bytes 85.23kB 0.16%
assets/save-*.js 155 bytes 81.24kB 0.19%
assets/vega-*.js 82 bytes 12.79kB 0.65%
assets/ttcn-*.js 7 bytes 64 bytes 12.28% ⚠️
assets/ttcn-*.js -7 bytes 57 bytes -10.94%
assets/mermaid-*.core-CzmbMcI0.js (New) 2.38kB 2.38kB 100.0% 🚀
assets/semaphore-*.js (New) 788 bytes 788 bytes 100.0% 🚀
assets/fileToBase64-*.js 52 bytes 531 bytes 10.86% ⚠️
assets/slides-*.css 224 bytes 529 bytes 73.44% ⚠️
assets/__vite-*.js 5 bytes 98 bytes 5.38% ⚠️
assets/__vite-*.js -5 bytes 93 bytes -5.1%
assets/mermaid-*.core-BQULBKwL.js (Deleted) -2.38kB 0 bytes -100.0% 🗑️

Files in assets/edit-*.js:

  • ./src/core/edit-app.tsx → Total Size: 8.04kB

Files in assets/reveal-*.js:

  • ./src/components/slides/slide-notes.ts → Total Size: 1.29kB

  • ./src/components/slides/reveal-component.tsx → Total Size: 15.4kB

  • ./src/components/slides/slide-notes-editor.tsx → Total Size: 4.32kB

Files in assets/layout-*.js:

  • ./src/components/editor/renderers/slides-layout/slides-layout.tsx → Total Size: 2.23kB

  • ./src/components/editor/renderers/slides-layout/plugin.tsx → Total Size: 1.32kB

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Loading

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread frontend/src/components/slides/slide-notes-editor.tsx Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds speaker notes support for slides, including editable notes in the slides authoring UI and Reveal speaker-view integration.

Changes:

  • Adds speakerNotes to 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.

Comment thread frontend/src/components/slides/slide-notes-editor.tsx Outdated
Comment thread frontend/src/components/editor/renderers/slides-layout/types.ts
Comment thread frontend/src/components/slides/reveal-component.tsx
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +55 to +59
if (prevCellIdRef.current !== cellId) {
persistDebounced.flush();
setDraft(initialValue);
prevCellIdRef.current = cellId;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Suggested change
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" }]],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants