Files
32b8c8748c feat(prototype): slide embed picker PRD and variant explorations (#832)
Add a PRD and three prototype directions (Gallery, Command Bar, Guided) behind the prototype picker harness for the lesson Slide embed flow. Covers the top 10 embeddable slide platforms with per-platform detection, link/embed-code normalization, live preview, and How-to-embed docs links.

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Rotimi Best <rotimi-best@users.noreply.github.com>
2026-08-14 11:00:06 +01:00

10 KiB

PRD — Slide Embed Picker

Feature area: Course → Lesson → Materials → Slide tab Status: Draft for review Author: Design exploration (cloud agent) Related prototype: index.html — three interaction directions behind the prototype picker


1. Problem

The Slide tab is a single unlabeled URL input with one line of helper text: "You can embed Google Slides or Canva Presentation." (apps/dashboard/src/lib/features/course/components/lesson/slide/slide.svelte).

This creates three problems for the teacher building a lesson:

  1. It isn't clear what to paste. A raw edit URL (.../edit#slide=id.p) does not embed. Google Slides needs a published /embed link; Canva needs ?embed; PowerPoint, Pitch, Gamma and SlideShare hand you a full <iframe> embed code, not a link. The field looks identical for all of them and silently fails when the wrong string is pasted.
  2. It isn't clear which platforms are supported. The copy names two (Google Slides, Canva). In reality the same <iframe> mechanism works for at least ten major tools, but a teacher has no way to know that.
  3. There's no help path. When the embed shows a blank frame or a "sign in" screen, the teacher is stuck — there is nowhere to click for guidance.

The only transform the current code does is append ?embed for www.canva.com URLs. Everything else is passed through verbatim.

2. Goals

  • Make embedding a deck obvious and low-error: the teacher always knows what to paste and can see it working before saving.
  • Surface the breadth of support with a visual, icon-forward platform picker.
  • Give every platform a one-click path to step-by-step docs.
  • Normalize input into a valid embed src (accept a share link or a pasted <iframe> embed code) so a correct render is the default, not the exception.
  • Preserve the existing data contract: the lesson still persists a single slideUrl. (Per repo guidance, the persisted column stores the resolved embed URL/data, not presentational markup.)

3. Non-goals

  • Uploading raw .pptx / .key files for hosting (these platforms host the deck; we embed it).
  • Building a slide editor. We embed decks authored elsewhere.
  • Server-side scraping of private decks or bypassing a platform's own auth wall.
  • Analytics on embedded decks (several platforms explicitly don't expose this).

4. Top 10 supported platforms

Ranked by prevalence in education/SaaS plus reliability of the public embed path. Each row lists what the teacher pastes and how we turn it into an embed src. All mechanics were verified against each vendor's current help docs (Aug 2026).

# Platform Teacher pastes We produce Notes
1 Google Slides Publish-to-web link https://docs.google.com/presentation/d/e/<ID>/embed?start=false&loop=false&delayms=3000 File → Share → Publish to web → Embed. We rewrite /pub · /edit · /present → /embed.
2 Canva Design view link or embed code https://www.canva.com/design/<ID>/view?embed Share → More → Embed. We append ?embed (current behavior, kept).
3 Microsoft PowerPoint (OneDrive / Office for the web) <iframe> embed code src extracted from the pasted iframe (onedrive.live.com/embed?...) File → Share → Embed in PowerPoint for the web. Personal OneDrive avoids the sign-in wall.
4 Apple Keynote (iCloud) iCloud share link https://www.icloud.com/keynote/<id>?embed=true Collaborate → Copy Link (Anyone / View only). We strip #name and append ?embed=true. Collaboration must stay on.
5 Figma Slides figma.com/slides/… or /deck/… link https://embed.figma.com/slides/<KEY>?embed-host=classroomio Embed Kit 2.0: swap www → embed, keep slides/deck, add embed-host.
6 Prezi View link or embed code https://prezi.com/view/<ID>/embed Share → Embed. We append /embed to the view link.
7 Pitch <iframe> embed code (public link) src extracted (pitch.com/embed/<id>) Share externally → link → Copy embed code. Disabling the link breaks the embed.
8 Gamma Embed code or public deck link src extracted / gamma.app/embed/<id> Share → enable public access → copy iframe.
9 SlideShare <iframe> embed code src extracted (slideshare.net/slideshow/embed_code/key/<KEY>) Public decks only; LinkedIn-owned.
10 Beautiful.ai Public link or embed code src extracted / player link Sharing Settings → Public → Get Embed Code (iframe) or oEmbed link.

Two input shapes. Six platforms give the teacher a link we transform (Google Slides, Canva, Keynote, Figma, Prezi, Beautiful.ai); four hand over a full <iframe> embed code (PowerPoint, Pitch, Gamma, SlideShare). The picker therefore accepts either — if the pasted value contains an <iframe>, we lift its src; otherwise we apply the platform's link transform.

5. Proposed feature — the Slide Embed Picker

Replace the bare input with a small, guided flow:

5.1 Feature list

  1. Visual platform picker. A gallery of the 10 platforms, each as a branded icon tile, so the teacher sees at a glance what's supported.
  2. Per-platform tailored input. Selecting a platform reveals the right field for it — a single link input or an embed-code area — with placeholder + one-line "where to find it" microcopy specific to that platform.
  3. Paste normalization. Accepts a share link or a full <iframe> embed code and resolves it to a valid embed src (extract-src or link-transform per §4).
  4. Live preview. A 16:9 preview renders the resolved embed before saving, with an explicit "Embed ready" confirmation, so failures are caught at author time, not by students.
  5. Inline validation. If the pasted value doesn't match the chosen platform (e.g. an /edit link that was never published), show a specific, fixable message ("This looks like an edit link — publish to the web first").
  6. "How to embed" docs button. Every platform has a deep link to classroomio.com/docs/guides/embed-slides#<platform> for step-by-step help.
  7. Auto-detect (accelerator). When a teacher pastes first, detect the platform from the URL/host and pre-select it, so an expert can skip the gallery.
  8. Change / clear. Easy path back to the gallery to switch platforms or remove the deck.
  9. Accessibility & i18n. Keyboard-navigable tiles, labelled controls, all copy in en.json (no hardcoded strings), reduced-motion respected.
  10. Backward compatible. An already-saved slideUrl re-opens in the matching platform's editor state; the stored value stays a single embed URL.

5.2 Interaction directions (see prototype)

The prototype explores three genuinely different ways to structure the same flow. They are meant to be compared, not combined:

Direction Interaction model Best when Cost
Gallery Browse a grid of platform tiles → focus into a per-platform input + preview Discovery matters; teacher may not know what's supported One extra click before typing
Command Bar Paste first into one smart field → platform auto-detects → preview + contextual docs Fast, repeat authors who already have the link Less discoverable; leans on detection
Guided Searchable platform rail + step-by-step instructions beside the input First-timers who need hand-holding to get a valid link Densest; most vertical space

6. UX flow (happy path)

  1. Teacher opens the Slide tab (empty).
  2. Picks Google Slides from the gallery (or pastes a link and it auto-selects).
  3. Field shows the Google-specific placeholder + "File → Share → Publish to web → Embed."
  4. Teacher pastes the published link. We rewrite it to the /embed form.
  5. Live preview renders; a green Embed ready badge appears.
  6. Autosave persists the resolved slideUrl (existing save behavior).
  7. In view mode, students see the embedded deck (existing <iframe> render).

Unhappy path: pasted an unpublished /edit link → inline message + How to embed button → docs.

7. Data & implementation notes

  • No schema change. Continue to persist slideUrl (resolved embed src). Do not store the raw <iframe> markup in the content column — extract and store only the src (repo rule: persisted columns store data, not presentation).
  • Where the logic lives. Platform configs (id, brand, input kind, placeholder, docs link, test, resolve) belong in a pure util, e.g. apps/dashboard/src/lib/features/course/utils/slide-embed.ts, so both detection and transform are unit-testable and reused by the view-mode getUrl() normalizer that today only special-cases Canva.
  • Docs. Add apps/docs/content/docs/guides/embed-slides.mdx with a section per platform and stable #<platform> anchors matching the docs links.
  • Copy. New keys under course.navItem.lessons.materials.tabs.slide.* in en.json; translate to the other locales before commit.
  • Component. Keep the component thin; put resolve/validate logic in the util and (if any request is added) an API class — no business logic in the .svelte file.

8. Success metrics

  • ↓ rate of saved slideUrl values that render a blank/invalid frame (measured by view-mode load failures).
  • ↑ share of lessons that include a working embedded deck.
  • ↓ support questions tagged "slides won't embed".
  • Time-to-first-working-embed for a new teacher.

9. Open questions

  1. Do we allow a raw pasted <iframe> for any host (generic passthrough), or only the 10 allow-listed platforms (safer, sanitized)?
  2. Should the preview load the real remote iframe at author time, or a lightweight resolved-URL confirmation (avoids third-party auth walls during editing)?
  3. Per-platform embed options (autoplay, loop, start slide for Google Slides) — expose now or defer?
  4. Which direction from §5.2 do we ship? (This is the decision the prototype picker exists to make.)