# ROADMAP β€” full feature checklist Living source of truth for what's **done βœ…**, **in progress 🚧**, and **planned ⬜**. Every feature is designed to be **optional via flags** (`features={{ … }}`) β€” a consuming project enables only what it wants. > Update this file as work lands. It is the authoritative cross-developer / cross-AI record. ## Legend βœ… done & verified Β· 🚧 in progress Β· ⬜ planned Β· πŸ”‘ needs an API key/paid plan --- ## 1. UI & theming - βœ… macOS Photos shell: sidebar, top toolbar, content area, window chrome (optional) - βœ… Sidebar: Library, Collections, Pinned (Favourites/Recently Saved/Map/Videos/Screenshots/People & Pets/ Recently Deleted w/ lock icon), Albums, Sharing (Shared Albums/Activity), Utilities, Projects - βœ… Light mode Β· βœ… Dark mode Β· βœ… **Semi-dark** (glass dark sidebar + light content) - βœ… **macOS vibrancy/"glass"**: translucent backdrop-blur menus, sidebar, toolbar, Info panel & search dropdown (theme-aware fills + hairline borders + `--apg-radius-menu`); `@supports` fallback to a solid fill where `backdrop-filter` is unavailable - βœ… Responsive desktop/laptop/tablet/mobile + ultra-narrow (Galaxy Fold ~280px); mobile drawer sidebar - βœ… Theme switch control in UI (Light/Dark/Semi-Dark/System menu) Β· ⬜ optional **weather-aware** auto theme - βœ… Theming via props: **accentColor** + **borderRadius** (CSS vars); ⬜ density/font presets - βœ… Accessibility: focus traps in overlays, ARIA dialog roles, keyboard nav, reduced-motion, contrast (AA) ## 2. Library, viewing & navigation - βœ… Library views: Years / Months / All Photos (Days grouping supported) β€” **date/time grouping** - βœ… Collections (Albums, Objects, Shared Albums, Recent Days) β€” trimmed of the placeholder-only sections (Memories / Pinned / Featured Photos / People & Pets / Trips / Utilities) for host-app embedding - βœ… Adaptive responsive grid + zoom in/out, lazy images - βœ… **Lightbox** photo viewer (prev/next, keyboard, actions) β€” 🚧 polish to 100% macOS parity - βœ… **Video player** (native controls in lightbox) β€” 🚧 macOS-style custom controls/scrubber - βœ… Multi-select (click **toggles** select/deselect; **Select All ↔ Unselect All**), **Copy to Album** + **Move to Album** (album views), keyboard shortcuts (⌘A, Delete, F, Esc, Space) ## 3. Albums - βœ… Create / rename / delete / duplicate; nested folders; covers - βœ… Add / remove / move items; "Remove from Album" - βœ… Smart albums (rule engine): Favourites, Videos, Screenshots, RAW, Live, Panoramas, Recently Saved - βœ… **Object albums** (auto, from detection) via the Objects browser β†’ object focus - βœ… **People** (auto, from face clustering) β€” populates the People & Pets view; click β†’ person-focused grid - βœ… **Documents** smart album (auto, from OCR `hasText` rule) β€” in sidebar + Collections - ⬜ "Copy into tag folder" materialized albums (e.g. a real "Table" album) β€” currently virtual via object focus ## 4. Import & capture - βœ… Import via **file browse** + **drag-and-drop** (images & videos); accepted-type allow-list - βœ… Reads dimensions / video duration; source auto-classification (camera/screenshot/download/social/scan/ai) - βœ… **Real EXIF extraction** (GPSβ†’location, DateTimeOriginalβ†’capture date, Make/Model, lens, ISO) via `exifr` - βœ… **Custom camera**: capture photo, record video (getUserMedia), front/back switch, rule-of-thirds grid - βœ… Live annotation while capturing (shapes + measurement arrows; saved with the capture) - βœ… Detailed metadata: format, **extension**, byte size, dimensions, lat/lon, date/time, source (Info panel) - βœ… Geolocation detect on capture (Geolocation API, permission-gated, in the custom camera) - βœ… Object detect on **import AND capture** β†’ auto-tag + object albums (AIAnalyzer runs on new media) ## 5. Map & places - βœ… Leaflet map, free tiles (OSM + Esri satellite), no API key - βœ… Map / Satellite / **Grid** modes; markers for located media; markers re-sync on library change - βœ… **macOS thumbnail pins** (photo cover + count badge + tail), **zoom-aware clustering**; tap a pin β†’ that location's photos in a **date-grouped sheet**; any GPS item (incl. screenshots) pins automatically - βœ… **Grid tab = Memories mosaic**: date sections, full-width **auto-sliding hero** + irregular varied tiles - βœ… **Mini-map** in the photo info panel - βœ… **Fly-to on pin click** (`flyTo`, never zooms out) + per-location **count badge** + **hover mini-slider** strip; the single-photo hover tooltip is edge-clamped (`--tip-dx` / `.apg-pin__tip--below`) and `user-select:none` - βœ… **Location-sheet filter**: search (shared `searchMedia`) + object-label chips + a single **date-range** control (`.apg-daterange` β€” presets *All dates / Last 7 days / Last 30 days / This year* + custom From/To), all AND-combined, with a live "N of M" count and one Clear-all - βœ… **Full-address reverse geocoding** β€” on opening a located item the Info panel reverse-geocodes once via OpenStreetMap Nominatim (`addressdetails=1`), parsing road/neighbourhood/suburb/city/county/state/postcode/country/countryCode/formatted into `GeoLocation` and persisting it via `updateMedia` (survives reload, never re-fetched). Host CSP must allow `nominatim.openstreetmap.org` in `connect-src` - Note: demo seed intentionally locates ~half the photos; real photos populate via EXIF GPS (Β§4) ## 6. Editor (photo & video) - βœ… Photo: Adjust (13 sliders), Filters (10 presets), Crop/Rotate/Flip β€” non-destructive - βœ… **Annotation layer**: rectangle, ellipse/oval, line, **arrow**, **double-arrow with center text** (measurement, e.g. "12 cm"), text, freehand β€” with **color**; in gallery edit + read-only in lightbox - βœ… Annotation in **custom camera** (live) and on **video** (markup layer in the video editor) - βœ… **Full video editor** β€” Adjust, Filters, **Trim**, **Markup** (annotations), **Overlay** (composite an image), **Audio** (mute original + add a music track w/ volume); exports a new clip via canvas + MediaRecorder + WebAudio (free, no ffmpeg); **Save** (overwrite) or **Save as Copy** (pick album), Cancel-confirm β€” mirrors the photo editor - βœ… Edited result persists (CSS-filter model + Gemini/canvas bakes; video bakes to a new webm) - βœ… **Save vs Save as Copy** (overwrite the photo, or create a new copy and pick its album) + **Cancel confirmation** when there are unsaved edits (Escape too) ## 7. AI (all optional; free unless marked πŸ”‘) - βœ… **Object detection** β€” TensorFlow.js COCO-SSD, in-browser, no key. Powers tags/search/find-similar/Objects - βœ… **Generative editor** β€” Gemini (Remove BG / Restore / Colorize / Replace Sky / prompt). πŸ”‘ needs image-gen quota (billing); free-tier key returns 429. Key is server-side only via `/api/ai/edit` - βœ… **Face detection + clustering** β†’ People β€” `@vladmandic/face-api` (TF.js), in-browser, **no key**. Detects faces + 128-D descriptors during analysis; the SDK clusters them (`lib/cluster.ts`) into People. Click a person β†’ library filters to their photos. Models lazy-loaded from jsDelivr (CSP-allow-listed). - βœ… **OCR** (tesseract.js, in-browser, **no key**) β†’ text extracted per image, **searchable** (search a word printed inside a photo and it's found), feeds the **Documents** smart album. A per-word confidence filter rejects the gibberish tesseract emits for photos without text, so only real documents qualify. - βœ… **Semantic search** "show me snowy mountains" β€” CLIP (transformers.js, `Xenova/clip-vit-base-patch16`, in-browser, **no key**); image embeddings computed during analysis, query embedded on search, ranked by cosine and blended after keyword hits. Models from the HF CDN (allow-listed); ~512-D vectors persist with each item - ⬜ **Captions** (transformers.js BLIP or HF, free) - ⬜ Pluggable **Hugging Face** provider option (Inference API / transformers.js) ## 7b. Advanced-features backlog (audited; prioritized β€” next candidates) > From a full feature audit vs. macOS Photos. HIGH = most-requested / highest value. - βœ… **Custom video player** (glass scrubber, buffered/played, volume, PiP, fullscreen, keyboard) - ⬜ **HIGH β€” Lightbox zoom/pan** (scroll / double-click / pinch) for detail viewing - βœ… **Editable metadata** in the Info panel β€” click‑to‑edit **caption** + multi‑line **`note`** (save on blur / Enter via `updateMedia`; `note` is folded into the search haystack). ⬜ still: keywords/tags editing, title, bulk edit - ⬜ **HIGH β€” Slideshow / Memories playback** (auto-advance + Ken Burns transitions) - ⬜ MED β€” Lightbox **filmstrip** of adjacent media; **timeline scrubber** to jump by date - ⬜ MED β€” **Keyboard-shortcut help** modal (`?`); album **drag-to-reorder** - ⬜ MED β€” **Skeleton loaders** on library load; selection-count bar inside the lightbox - ⬜ LOW β€” Smart-album **rule builder** UI; materialized tag albums; **print** dialog; import-from-URL; undo/redo beyond the editor; true windowed virtualization ## 8. Backend & storage (all optional adapters) - βœ… Default zero-config localStorage + IndexedDB adapter (`StorageAdapter` interface) - βœ… **Supabase**: Postgres (data) + Supabase Storage (blobs) adapter (`apps/web/src/lib/adapters/supabaseAdapter.ts`); imports/captures upload blobs via `putBlob`; metadata in JSONB tables. Wired in the demo when env vars are set; falls back to localStorage otherwise. **Run `docs/supabase-setup.sql` once** (creates tables + RLS + storage policy), then reload. πŸ”‘ creds in `.env.local`. - ⬜ Alternate adapters documented as options: S3 / R2 / GCS / Azure / MinIO; Postgres/MySQL/SQLite/Mongo; Prisma/Drizzle; REST/GraphQL/WebSocket; NestJS/Fastify service; BullMQ/Redis workers; vector DB (Qdrant/Pinecone/Weaviate/Chroma) for semantic search ## 9. Search - βœ… Text search (name, place, tag, detected object, source) - βœ… Click-object β†’ find every photo with it (object focus) - βœ… **OCR text search** β€” words printed inside an image are matched by the normal search - βœ… **Natural-language semantic search** (CLIP) β€” "looks like" matches blended after keyword hits (Β§7) ## 10. Cross-cutting - βœ… Security: nonce CSP, headers, input validation, URL allow-list, server-only keys, sanitization - βœ… Recycle bin (30-day), duplicate detection + merge, export/download + metadata - βœ… **Sharing**: Share a photo / multiple / one-or-more albums β†’ generates a copyable link (+ Download); **Shared Albums** (copy-link / revoke) + **Activity** feed of shares. Client-side share records (localStorage). - βœ… **Recently Deleted password lock**: set/change/remove a password (Web Crypto SHA-256, device-local), sidebar lock↔unlock icon, lock screen prompts for the password; settable from the β‹― menu or the trash header - βœ… Lazy-load `@supabase/supabase-js` (dynamic import) β€” /gallery first load trimmed 234 KB β†’ 176 KB - ⬜ Performance: true windowing/virtualization for very large libraries (currently lazy + auto-fill) - βœ… Docs: README + `docs/SETUP.md` + `docs/ARCHITECTURE.md` + this roadmap + project-local `CLAUDE.md` - βœ… Testing: Playwright e2e (manual runs); ⬜ automated CI suite ## 11. Embedding into a host app (CRM / host integration) > The SDK is no longer just the macOS-Photos demo β€” it embeds into a host product's shell. All of it is opt-in. - βœ… **Embedded layout** (`embedded`) β€” fills the host container (`height:100%`, `.apg--embedded`, `cursor:pointer`) instead of assuming a full viewport; overlays stay `position:fixed` and honour `--apg-overlay-top` - βœ… **Chrome suppression** (`chrome { titlebar, sidebar, toolbar, themeSwitcher }`, `DEFAULT_CHROME` exported) β€” hide the pieces the host already provides; `showWindowChrome` kept as a legacy alias of `chrome.titlebar` - βœ… **`hiddenViews: ViewId[]`** β€” drop sidebar rows + Collections cards (labels drop when empty; active hidden view falls back to `library`) - βœ… **`keyboardShortcuts`** flag β€” bind (or not) global shortcuts to `window` - βœ… **Host identity** (`currentUser: GalleryUser`) β€” identity-stamped **comments** (`authorId/author/authorAvatar`; only the author sees delete), **uploads** (`MediaItem.uploadedBy`, never overwritten on re-import), and **versions** (`addVersion`/`restoreVersion` stamp the author). Info panel shows an "Uploaded by" block + per-version author. `be-crm` still owns `owner_principal_id`; `uploadedBy` is display identity only - βœ… **`shareBaseUrl`** β€” host owns where share links point - βœ… **Full ThemeTokens map (50+ keys)** β†’ CSS variables (backgrounds, cards, toolbar/menu glass, separators, hover/active, text tiers, glass border, font, shadows, tile-fav, overlay/editor bg, segmented pill, sidebar/toolbar sizing); `xLight/xDark` theme-paired or bare; sanitized against `url()/expression()/javascript:/<>{}`. **Live config** β€” theme / tokens / identity / chrome re-apply via `setConfig` without remounting - βœ… **Full-screen / maximise** (`defaultFullscreen`, store `fullscreen`/`setFullscreen`/`toggleFullscreen`, toolbar button) β€” adds `.apg--fullscreen` (`position:fixed; inset:0; z-index:1400; height:100dvh`); Escape un-maximises after the lightbox/editor/camera/modal/menu checks - βœ… **Server-backed Recently-Deleted lock** (`lockProvider: { status, set, verify }`) β€” replaces the device-local `apg:lock-hash` entirely; `lockConfigured` is the UI source of truth, `lockError` separates `'wrong-password'` from `'unavailable'` - βœ… **Incremental persistence** β€” `StorageAdapter.applyChanges(StateChanges)` (diff-based, called instead of `save()`; serialized writes, rollback-on-reject) + `putMedia(id, blob, meta) β†’ { ref, url }` (durable bytes, sets `MediaItem.src`/`storageRef`); types `StateChanges` / `StoredBlob` exported - βœ… **Floating glass toolbar** + library-scale **dropdown** (`.apg-scalemenu`, replaces the Years/Months/All segmented) - ⬜ Real multi-user auth / permissions in the host (identity is display-only in the SDK; the backend is the authority) ## Web-meaningful UI (done 2026-06-29) - βœ… "All Projects / App Store" (iOS-only) β†’ **"All Albums"** overview (My Albums + Create + Recent Days). - βœ… Sidebar Albums section: All Albums + New Album + user albums (indented). ## New requests - βœ… **Advanced video editor** (2026-07-07): **multi-segment trim** (keep several ranges, cut middles, per-segment **speed**), **image/watermark overlays that actually composite** (bug fixed), **text overlays**, **keyframe animation** (move/fade/scale/rotate over time), **crop + 90Β° rotate + flips for video**, **audio** (mute/volume + music + master fade in/out), **poster/thumbnail picker**, and **export quality** (480p/720p/1080p, fps). Built on a rewritten canvas+MediaRecorder **timeline engine** (`lib/videoBake.ts` + shared `lib/videoTimeline.ts`); no ffmpeg. Bake failures now surface a clear error instead of silently dropping edits. - βœ… **Auto object smart albums** (2026-07-07): one live smart album per detected object (Person, Car, Chair, Table…) in a new sidebar **Objects** section; Collections "Objects" cards open the album. Membership is resolved live; the album set refreshes on analysis completion. - βœ… **Upload / analysis / persistence fixes** (2026-07-07): reliable file-picker ("Choose files" button); uploaded photos now get the **same AI analysis as captures** (newest-first + drain-loop, no starvation); versioning **increments correctly and survives reload** (load-path no longer strips `versions`/`comments`); **Save-as-Copy carries its own history**; imports/captures persist **durable** URLs (no dead `blob:` after reload); Supabase setup now **creates the public `media` bucket**. - βœ… **Free deployment guide** β€” [`docs/DEPLOY.md`](./DEPLOY.md) (Vercel + Supabase free tier) + [`docs/DEPLOY-MANUAL.md`](./DEPLOY-MANUAL.md) (no-Git manual upload: Vercel CLI / self-host Node / static export). - βœ… **Swappable AI backend (no paid Gemini)** β€” [`docs/AI-SETUP.md`](./AI-SETUP.md): analysis (objects/faces/OCR/embeddings) + Remove Background already run FREE in-browser (no key); generative edits (`/api/ai/edit`) now pick a backend via `AI_EDIT_PROVIDER` = **local** (own Stable Diffusion β€” free+private), **huggingface** (free token), or **gemini**, with an `auto` fallback. - βœ… **Versioning + Audit Log** (photos **and** videos, 2026-07-02): every save appends a new version (v1 = original, **never overwritten**); each version carries a human-readable audit log of what changed. Info panel β†’ **Version history** (per-version thumbnail preview, timestamp, expandable "What changed", **Restore**); sidebar **Versions & Audit** view browses all edited/commented items. Persisted inline on `MediaItem` β†’ Supabase JSONB. - βœ… **Comments** (photos **and** videos, 2026-07-02): threaded comments with author + timestamp, add/delete, shown in the Info panel; persisted with the item. Author remembered locally (`apg:comment-author`). - βœ… Editor **straighten/tilt** slider + βœ… **interactive crop** (free + fixed-ratio: Square/4:3/3:4/16:9/9:16/Original; square stays square while dragging) β€” **bakes on Done** (canvas) and uploads the result to Supabase Storage - βœ… Search dropdown defaults: **Recently Viewed / Recently Edited / Recently Added** (focus the search box) - βœ… Import existing **IPTC/XMP keywords** + location on import (exifr iptc+xmp) - βœ… **Local Remove Background** (`@imgly/background-removal`) β€” runs fully in-browser (WASM), **no key**; the editor's Remove BG uses it directly (Gemini not required). Other generative ops still use Gemini. - βœ… Info mini-map click β†’ opens full **Map centered** on the photo; βœ… **tag click β†’ date-grouped images** - βœ… Camera annotations now applied to the captured still (saved); βœ… Undo/Clear in camera + editor - βœ… Geolocation tagged on capture (prefetched, permission-gated); βœ… device info in capture EXIF - βœ… Auto **Camera** + **Screenshots** albums (created on first capture/import of that source) - βœ… Recycle bin: 30-day retention enforced (purge on load); restore/permanent-delete sync to Supabase ## Suggested build order (remaining) 1. βœ… Map/Annotation/EXIF/Info/Semi-dark/theming + βœ… Custom camera + βœ… web-meaningful UI (done 2026-06-29) 2. ⬜ **Supabase adapter (Postgres + Storage)** ← next (needs creds; no localStorage reliance after) 3. ⬜ Editor straighten + ratio crop; search defaults; import tags; local remove-bg; map/tag nav 4. ⬜ Face clustering β†’ People; OCR β†’ Documents; semantic search (free, HF/transformers.js) 5. ⬜ Video editor/annotations; macOS-parity viewer/player polish; perf virtualization; CI