Skip to content

PRD: Slideshow Creator — local-first web app #1

Description

@cbaucom

Problem Statement

I want to turn folders of personal photos and videos into polished slideshow videos, the way Apple Photos "Memories" does — but Apple's tool decides too much for me. I can't properly control which media is included, the order, the pacing, the music, or the transitions. Other editors (iMovie, CapCut) offer control but demand timeline-editing labor for what should be a "arrange and play" experience. I want hand-curated content with automatic, Apple-grade presentation: I pick and order the media, the app makes it beautiful, and everything the app decides is overridable.

Solution

A local-first web app (Chromium, installable as a PWA) where a Project is a folder on disk. The user points the app at a folder; all photos/videos inside become the media bin, and the app writes a slideshow.json (timeline + settings) into that same folder. The user arranges media in a storyboard grid, picks music via in-app Jamendo search (downloaded into the folder) or any audio file already in the folder, and the app produces a beat-synced, Ken Burns–animated slideshow rendered live by a Remotion composition in a preview pane. A settings cascade (global defaults → per-slide overrides) plus Theme presets makes every automatic decision customizable, down to a fully plain mode (no transitions, fixed duration per image, videos play as-is). Export to .mp4 is deliberately deferred; the Remotion architecture pre-solves it.

User Stories

  1. As a user, I want to point the app at a local folder, so that everything in it becomes my slideshow's media bin without uploading anything anywhere.
  2. As a user, I want the app to save my timeline and settings as slideshow.json inside the project folder, so that the project is a self-contained, syncable, backup-able folder.
  3. As a user, I want the app to remember my recent project folders and re-open them with minimal permission friction, so that returning to a project tomorrow "just works".
  4. As a user, I want new files dropped into the project folder to appear in the media bin on refresh, so that adding media is as easy as using Finder/Explorer.
  5. As a user, I want to drag-and-drop additional files into the app window and have them copied into the project folder, so that I never have to think about where media lives.
  6. As a user, I want to see my media as a reorderable storyboard grid of thumbnails, so that I can arrange the sequence the way I think about it — a series of moments.
  7. As a user, I want to include or exclude any media file from the timeline without deleting it from the folder, so that curation is non-destructive.
  8. As a user, I want both photos and videos to be first-class slides in the same sequence, so that my slideshows mix media like Apple Memories does.
  9. As a user, I want to add title/text slides (e.g. a trip name to open the show), so that slideshows have narrative framing.
  10. As a user, I want global default settings (slide duration, transition type, Ken Burns on/off, fit mode), so that I configure the look once, not per slide.
  11. As a user, I want to override any global setting on an individual slide, so that one odd photo doesn't force me to change the whole show.
  12. As a user, I want Theme presets (Classic, Energetic, Plain) that bundle settings, so that I can get a coherent look in one click.
  13. As a user, I want a Plain mode — no transitions, no motion, each image shown X seconds, videos play untouched — so that I can produce a no-frills slideshow when that's the right tone.
  14. As a user, I want to search open-licensed music by mood/genre/keyword inside the app (Jamendo), so that I can find a soundtrack without leaving the editor.
  15. As a user, I want to preview streaming search results before choosing, so that I can audition tracks quickly.
  16. As a user, I want a chosen track downloaded into the project folder, so that the slideshow keeps working even if the source link rots.
  17. As a user, I want any audio file already present in the project folder to be offered as a soundtrack option, so that I can source music any way I like.
  18. As a user, I want slide transitions nudged to land on the music's beats, so that the slideshow feels edited to the soundtrack like Apple Memories.
  19. As a user, I want an Energy setting controlling how many beats each slide holds, so that I can make the same show feel calm or punchy.
  20. As a user, I want beat sync to use my target durations as the baseline (nudged, not hard-quantized), so that slides keep roughly even screen time.
  21. As a user, I want to manually correct tempo/offset (e.g. tap-along) when automatic detection gets it wrong, so that a bad analysis never blocks me.
  22. As a user, I want to turn beat sync off entirely, so that durations are exactly what I set.
  23. As a user, I want background music to duck to ~20% while a video clip's own audio plays, so that voices in clips remain the point of including them.
  24. As a user, I want per-slide audio overrides (mute video audio / mute music / mix levels), so that each clip can be handled appropriately.
  25. As a user, I want photos cropped to fill the frame by default, with Ken Burns motion making the crop feel intentional, so that portrait phone photos look cinematic in a 16:9 show.
  26. As a user, I want per-slide fit overrides (letterbox, blur-fill), so that an important photo is never cropped against my will.
  27. As a user, I want videos fitted (letterboxed), never cropped, so that the original framing of clips is preserved.
  28. As a user, I want Ken Burns direction to auto-alternate between consecutive slides, so that motion never feels repetitive.
  29. As a user, I want a 16:9 1080p canvas by default with aspect ratio selectable per project, so that I can later make 9:16 versions for phones.
  30. As a user, I want a live preview pane that plays the slideshow exactly as the final render would look, so that what I see is what I get.
  31. As a user, I want playback controls (play/pause, scrub, jump to slide), so that I can review specific moments quickly.
  32. As a user, I want clicking a slide in the grid to open its settings (duration, transition, motion, fit, audio), so that per-slide control is one click away.
  33. As a user, I want the app to detect missing/renamed media files on project open and tell me which slides are affected, so that breakage is visible and fixable rather than silent.
  34. As a user, I want my edits autosaved to slideshow.json, so that closing the tab never loses work.
  35. As a user, I want to install the app as a PWA, so that folder permissions persist and it feels like a desktop app.
  36. As a user, I want full-screen playback, so that I can present the slideshow on a TV via AirPlay/casting of the browser.

Implementation Decisions

  • Platform & stack: Vite + React + TypeScript SPA. No backend, no accounts. Chromium-only (File System Access API); installable as PWA. Rendering/preview via Remotion @remotion/player. Audio analysis via Web Audio API. Music search via Jamendo API (free tier, client_id).
  • Project = folder: the only persistence is the user's folder. Media is referenced by filename within the folder (never copied elsewhere); slideshow.json stores the timeline, settings cascade, theme, soundtrack reference, and beat-grid corrections. Directory handles are persisted in IndexedDB for re-open; permission re-grant flow handled in Project Store.
  • Module architecture (deep modules, pure cores):
    • Timeline Core — pure domain model: slides (media + title types), ordering, theme presets, and settings-cascade resolution (globalSettings, slideOverrides) → ResolvedSlideSettings. No browser APIs.
    • Beat Grid — two layers: a thin Web Audio decode adapter, and pure analysis math (onset detection, BPM estimation, beat offsets) plus nudge(targetDuration, beatGrid, energy) → snappedDuration. Stores manual tempo/offset corrections.
    • Sequence Planner — the heart: pure function (timeline, beatGrid, mediaMetadata) → RenderPlan producing absolute frame positions, per-slide durations, transition windows, alternating Ken Burns vectors, and the music ducking envelope around video-audio segments. All downstream layers execute the plan and make no decisions.
    • Project Store — File System Access wrapper: open/enumerate folder, media/audio type detection, read/write slideshow.json, autosave debounce, missing-file detection, permission lifecycle.
    • Composition — thin Remotion layer: components for media slides, title cards, crossfade/dip-to-black/cut transitions, Ken Burns transform, and audio tracks driven by the RenderPlan's ducking envelope.
    • Music Search — Jamendo client: query, stream-preview URLs, download-to-folder via Project Store.
    • Editor Shell — storyboard grid (drag reorder), settings panels, preview host. Intentionally shallow glue.
  • Settings cascade contract: every presentational behavior (duration, transition, motion, fit, audio policy) resolves global → per-slide; Themes are saved settings objects, nothing more. "Plain mode" is the Plain theme, not special-cased code.
  • Beat sync policy: target-duration-nudged-to-nearest-beat (never hard quantize); Energy maps to beats-held-per-slide bands. Beat sync is a cascade setting and can be off.
  • Audio policy: default duck-to-20% under video audio with attack/release ramps in the ducking envelope; per-slide overrides (mute video / mute music / custom mix).
  • Fit policy: photos crop-to-fill default; letterbox and blur-fill as overrides. Videos always fit. Canvas default 1920×1080; aspect is a project setting and compositions are dimension-parametric.
  • v1 motion vocabulary: crossfade, dip-to-black, hard cut; Ken Burns zoom in/out + pan with auto-alternation; title slides. Nothing else until three real slideshows have been made.

Testing Decisions

  • A good test exercises external behavior through the module's public interface — given inputs, assert outputs/effects — never internal helpers or intermediate state. Pure modules make this cheap.
  • Timeline Core: table-driven tests for cascade resolution (global only, override wins, theme application, plain mode), ordering operations, and serialization round-trip of slideshow.json.
  • Beat Grid: tests on the pure math with synthetic beat grids and synthesized click-track buffers (known BPM in → detected BPM/offset out within tolerance); nudge behavior across energy levels and edge cases (duration shorter than one beat, track shorter than show).
  • Sequence Planner: the most heavily tested module. Golden-plan tests: fixed timeline + beat grid + metadata in → exact RenderPlan out (frame positions, transition windows, alternating Ken Burns, ducking envelope around video segments). Property tests: total duration consistency, no overlapping non-transition windows, ducking segments exactly cover video-audio spans.
  • Project Store: tested against an in-memory fake of the File System Access handle interfaces — folder enumeration, json round-trip, autosave debounce, missing-file detection. No real-FS tests in CI.
  • Music Search: tested against recorded/mocked Jamendo responses — query mapping, result parsing, error/empty states, download-to-folder handoff. No live network in tests.
  • Composition & Editor Shell: no unit tests; verified by eye via preview. Their correctness is dominated by the RenderPlan, which is tested upstream.
  • Prior art: none (greenfield). Establish Vitest as the runner; tests colocated per module.

Out of Scope

  • Video export (.mp4) — architecture pre-solves it via Remotion, but no export UI/pipeline in v1.
  • Automatic curation: face/scene detection, "best shot" selection, auto-drafting from a photo dump.
  • Video trimming (in/out points) — user trims before import; candidate for v2 via per-slide scrubber.
  • Cloud provider integrations (Google Photos picker, Dropbox chooser, Drive) — v2; users export to disk for v1.
  • In-app paste-a-link audio fetching and any CORS proxy.
  • Accounts, sync, sharing, collaboration, hosting of any kind.
  • Multiple audio tracks, narration recording, audio crossfading between songs.
  • Firefox/Safari support.
  • Transition library beyond the v1 vocabulary (wipes, 3D, particles).

Further Notes

  • Known risk: onset/BPM detection quality varies by genre (pop/electronic good; sparse acoustic weak). The manual tap-to-correct fallback is therefore required for v1, not a nice-to-have.
  • Licensing: personal use keeps music licensing forgiving; Jamendo's terms suit personal/non-commercial use. Revisit before any public release.
  • Future-proofing notes: export later means the Composition must remain deterministic — no wall-clock or Math.random() in render paths; Ken Burns directions and any variation derive from slide index/seed in the RenderPlan. Aspect-ratio parametrization (9:16) should be respected in all Composition components from day one.
  • Origin story: spec produced from a grilled design session resolving platform, persistence, rendering, audio sourcing, beat sync, editor model, fit policy, and motion vocabulary one branch at a time.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ready-for-agentTriaged PRD ready for agent implementation

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions