# Personal Video Editor App — Planning Notes

## Goal
Build a personal iPhone video editing app (InShot-style) using Claude Code + existing
Apple Developer account, sideloaded/unreviewed, re-signed annually. Core motivation:
fix InShot's storage problem — no external drive support, no relinking after a source
clip is moved/deleted, and every draft duplicates the original clip.

---

## Core Architectural Fix: Non-Destructive, Reference-Based Storage

**The problem with InShot:** it copies source video into its own sandbox per project,
so multiple edits of the same clip = multiple copies on disk, and there's no way to
relink a project if the original clip moves or is deleted.

**The fix — two-layer data model:**

1. **Source library** — actual video files, referenced (never copied) via
   security-scoped bookmarks. Each source gets a stable unique ID.
2. **Drafts** — lightweight JSON "recipes": an ordered list of source clip IDs +
   trim points + text overlay data + audio config + volume/mute settings. A draft is
   instructions, not a copy of video data.

**Result:** 5 different reels cut from the same original clip = 1 video file on disk +
5 tiny JSON recipes. Storage cost of a new draft ≈ 0.

### "Save As New Draft"
Explicit, deliberate user action — duplicates the *recipe* (not the video) into a new
draft record. Matches how the user wants to branch variations without accidentally
mutating a "finished" draft. Undo is handled as a linear undo stack **within** a single
draft's edit history — no branching/version-tree logic needed.

### Build order (validate storage architecture before editing UI)
1. Source library + bookmark system (import, stable refs, staleness/relink handling)
2. Draft = array of edit instructions referencing source IDs (prove save/load/duplicate
   works with zero video processing)
3. Wire recipes into `AVMutableComposition` for preview/export

---

## Source Types: Photos Album vs. External Drive (important distinction)

- **External drive files** — accessed via `UIDocumentPickerViewController` +
  security-scoped bookmarks. These bookmarks are **inode-based**, so they survive the
  file being moved or renamed within the filesystem, across app relaunches and device
  restarts.
- **Photos album clips** — accessed via the Photos framework using a `PHAsset`
  identifier, NOT a plain file bookmark. The video data lives inside Photos' own
  managed storage. If a clip is exported out of Photos onto a hard drive, that's a
  **new, disconnected file** — the PHAsset reference does not "follow" it automatically.

**Practical implication:** editing straight from an external drive "just works" with
bookmarks. Editing from Photos and later moving the clip to a drive requires an
explicit relink step (see below) — it will not resolve on its own.

---

## Relink Feature (for Photos → external drive moves)

**Why needed:** Photos-based references break when a clip is exported/moved out of
Photos, since there's no direct filesystem link to update.

**How it works — fingerprint matching:**
- At import time, store a lightweight fingerprint with every clip reference: duration,
  frame dimensions, file size, creation date, maybe a hash of the first few frames.
- When a reference breaks (Photos asset gone, bookmark stale), scan a
  user-granted folder for a file matching that fingerprint, and offer to relink.

**iOS sandboxing limits "auto":**
- The app can't silently browse arbitrary external storage — it needs the user to grant
  access to a folder once via the document picker (stores a security-scoped bookmark to
  that folder).
- After that one grant, the app **can** silently rescan that folder and auto-relink
  anything it fingerprint-matches — no reprompt needed.
- New/unseen locations still need one manual "point me here" interaction — but only
  once per new location, not per clip.

**Confirmation step (decided: quick confirmation required, not fully silent):**
- Show a **thumbnail frame** from the matched file next to the clip being replaced —
  not just a filename. Fingerprints can produce close-but-wrong matches (similar
  duration/resolution); a visual thumbnail catches this at a glance.
- After confirming, run a **duration/range sanity check**: if the draft trims to, say,
  0:08–0:15, and the matched file is shorter than that, flag it explicitly ("file too
  short for this clip's trim points") rather than silently failing or exporting a
  frozen/black frame.
- Treat a relink as **reversible** — an easy "this isn't right, unlink and try again"
  action, so a bad match doesn't permanently corrupt the draft.

---

## Export With Media → External Drive (Option A: chosen approach)

**Decision: exporting a draft + its original clips to a hard drive should be a
self-contained, re-pointing export — not just a backup copy.**

- Export step copies the actual video bytes to the drive **and** updates the draft's
  internal source pointer to treat the drive copy as the new primary source
  ("re-adopting" the file).
- Once re-pointed, the draft no longer depends on the Photos asset at all — **deleting
  the Photos original afterward is safe.**
- Rejected alternative (Option B — copy to drive as backup without re-pointing): would
  still work via the relink/fingerprint flow if the Photos original were deleted, but
  unnecessarily relies on relink succeeding for something this important. Simpler and
  safer to just re-point at export time.

---

## Graceful Degradation (missing/broken source clips)

- A missing clip should never take down the whole draft.
- All edit metadata (trims, text overlay config, audio settings) stays intact
  regardless of whether the source resolves.
- Timeline shows the specific broken clip as a placeholder ("missing — locate file");
  other clips in the same draft remain fully editable.
- Export is blocked (or the broken segment is flagged/skipped) until relinked.
- Nothing about the edit itself is lost — it's a "can't find the pixels right now"
  state, not data loss.

---

## Feature List (from original brainstorm)

- Show audio drops/breaks → align clip transitions/actions; auto assign/adjust clip
  length to those points (this is signal processing, not AVFoundation editing — pull
  raw PCM via `AVAssetReader`, compute amplitude/RMS over short windows, detect drops
  below a threshold; budget as its own mini-project)
- Auto-center text; consistent text box positioning across clips
- Auto-save text size and font
- Adjust all text at once, or individually
- Text background
- Safe zones for Instagram feed page vs. full-screen Reels page (UI-only guide overlay
  during editing; separate from actual crop/pad at export)
- Save progress
- Undo (linear stack within a draft)
- Zoom in on timeline for easier short-clip adjustment
- Select clips to move/delete/etc.
- Save different drafts of the same clips without duplicating the clip (✅ solved by
  the reference-based architecture above)
- Correct export formats for Instagram Reels/Post/Story and TikTok (each platform
  wants specific resolution/bitrate/frame rate — Reels/Story ≈ 1080×1920, Feed post
  1:1 or 4:5 — getting these exact avoids silent re-compression by the platform)
- On clip import: highlight already-imported clips, allow deselection to undo an
  import, number each clip and show its number in the import window
- Full-screen preview
- Multiple songs; mute per-clip audio; adjust each clip/track's volume separately
  (tricky part: per-clip mute + independent music volume both need to survive later
  trim/reorder without orphaning the time-based volume automation)
- Preview on different device views (e.g., simulate how it'll look on Instagram)
- Comment on preview with caption edit
- Easy-copy caption input
- Possible integration with a captioning app
- Hard drive use: app remembers which clip was used so deleting/retrieving/moving
  clips doesn't corrupt the edit (✅ this is the whole relink/bookmark system above)
- Backup download/export with cache
- Cache delete
- Save different drafts of the same edit into the same folder
- Save directly to iPhone Photo Album (not just Files)

---

## Hard AVFoundation Problems (in rough priority order to prototype)

1. **Security-scoped bookmarks / relink system** — prototype first; if this doesn't
   work reliably, nothing else matters.
2. **Non-destructive composition model** — `AVMutableComposition` is naturally
   non-destructive (an instruction list until export), which is the right foundation
   for the draft/recipe model. No built-in undo, though — build a command-history
   stack on top.
3. **Text overlay compositing + orientation** — `AVVideoCompositionCoreAnimationTool`
   or a custom `AVVideoCompositing` class. Must correctly apply each clip's
   `preferredTransform` (portrait footage is stored as landscape pixels + a rotation
   flag) or text ends up upside-down/mirrored/misplaced — the most common DIY bug.
4. **Multi-track audio mixing** — `AVMutableAudioMix` with per-track volume keyframes
   at specific `CMTime` values; must survive trims/reorders without orphaning the
   automation.
5. **Safe zones + multi-format export** — UI-only safe zone guides vs. actual
   crop/pad via `renderSize` on `AVMutableVideoComposition`; exact resolution/bitrate/
   frame rate per target platform.
6. **Frame-accurate trimming** — video is stored in GOPs (keyframes + deltas); trims
   can land near-but-not-exactly on the tapped frame unless re-encoded at the cut
   point. Usually fine for casual editing — worth knowing so it's not mistaken for a
   bug.
7. **Audio drop/silence detection** — separate signal-processing task, not core
   AVFoundation editing.

---

## Open Source Reference Repos (for the editing pipeline — NOT the storage architecture)

No open source repo matches the storage architecture above — that pattern (bookmark-
based, non-destructive, multi-draft references) isn't present in hobbyist iOS video
editor repos; it's closer to what professional non-open-source apps (LumaFusion,
Resolve) do. Build it from scratch using Apple's security-scoped bookmark APIs
directly.

For the AVFoundation editing pipeline itself (trim/text overlay/audio mixing/export),
useful references found:

- **VideoEditorKit** — SwiftUI video editing framework, ready-to-embed editor, export,
  serializable editing state, host-controlled configuration. Most promising overall
  reference; SwiftUI pairs well with Claude Code.
- **swift-simple-video-editor** (indrasat) — small Swift/AVFoundation codebase
  implementing merge, trim, speed change, effects, text overlay, sticker overlay.
  Small enough for Claude Code to fully digest; good reference for the composition/
  export code specifically. Note: uses destructive auto-save-after-each-step pattern —
  don't copy that part.
- **PryntTrimmerView** — trim/crop UI component (SPM/CocoaPods/Carthage).
- **VideoTrim** (pikachu987) — trim UI component with scrubber/frame thumbnails.
- Skip: IMG.LY starter kit (commercial SDK, requires license key, watermarked without
  one — not real open source code to own).

**Malware/supply-chain note:** risk is mainly in transitive dependencies
(Podfile/Package.swift), not the human-written Swift itself. Prefer repos with
minimal external dependencies. This is a personal unreviewed app, so the main risk
surface is the dev machine, not App Store review — read/adapt code with Claude Code
rather than blindly running unfamiliar build scripts or installing unfamiliar pods.

---

## UI Cloning Notes

- Interaction patterns/layout (bottom toolbar, draggable timeline with thumbnails,
  tap-a-clip-to-edit flow) are standard across InShot/CapCut/VN — fine to replicate,
  not copyrightable.
- Don't lift literal assets (exact icons, exact palette, logo, screenshots). Describe
  layout in words to Claude Code and generate original icon set/color scheme instead.

---

## Open Questions / Decisions Still Needed
- None currently blocking — next step is prototyping the security-scoped bookmark +
  relink system before building any editing UI.
